Merge branch 'preload-maps'
[fw/altos] / altosui / AltosConfigUI.java
1 /*
2  * Copyright © 2010 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.event.*;
22 import javax.swing.*;
23 import javax.swing.filechooser.FileNameExtensionFilter;
24 import javax.swing.table.*;
25 import javax.swing.event.*;
26 import java.io.*;
27 import java.util.*;
28 import java.text.*;
29 import java.util.prefs.*;
30 import java.util.concurrent.LinkedBlockingQueue;
31
32 import libaltosJNI.*;
33
34 public class AltosConfigUI
35         extends JDialog
36         implements ActionListener, ItemListener, DocumentListener
37 {
38
39         Container       pane;
40         Box             box;
41         JLabel          product_label;
42         JLabel          version_label;
43         JLabel          serial_label;
44         JLabel          main_deploy_label;
45         JLabel          apogee_delay_label;
46         JLabel          radio_channel_label;
47         JLabel          radio_calibration_label;
48         JLabel          flight_log_max_label;
49         JLabel          ignite_mode_label;
50         JLabel          callsign_label;
51
52         public boolean          dirty;
53
54         JFrame          owner;
55         JLabel          product_value;
56         JLabel          version_value;
57         JLabel          serial_value;
58         JComboBox       main_deploy_value;
59         JComboBox       apogee_delay_value;
60         JComboBox       radio_channel_value;
61         JTextField      radio_calibration_value;
62         JComboBox       flight_log_max_value;
63         JComboBox       ignite_mode_value;
64         JTextField      callsign_value;
65
66         JButton         save;
67         JButton         reset;
68         JButton         reboot;
69         JButton         close;
70
71         ActionListener  listener;
72
73         static String[] main_deploy_values = {
74                 "100", "150", "200", "250", "300", "350",
75                 "400", "450", "500"
76         };
77
78         static String[] apogee_delay_values = {
79                 "0", "1", "2", "3", "4", "5"
80         };
81
82         static String[] flight_log_max_values = {
83                 "64", "128", "192", "256", "320",
84                 "384", "448", "512", "576", "640",
85                 "704", "768", "832", "896", "960",
86         };
87
88         static String[] ignite_mode_values = {
89                 "Dual Deploy",
90                 "Redundant Apogee",
91                 "Redundant Main",
92         };
93
94         static String[] radio_channel_values = new String[10];
95                 {
96                         for (int i = 0; i <= 9; i++)
97                                 radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)",
98                                                                         i, 434.550 + i * 0.1);
99                 }
100
101         /* A window listener to catch closing events and tell the config code */
102         class ConfigListener extends WindowAdapter {
103                 AltosConfigUI   ui;
104
105                 public ConfigListener(AltosConfigUI this_ui) {
106                         ui = this_ui;
107                 }
108
109                 public void windowClosing(WindowEvent e) {
110                         ui.actionPerformed(new ActionEvent(e.getSource(),
111                                                            ActionEvent.ACTION_PERFORMED,
112                                                            "Close"));
113                 }
114         }
115
116         /* Build the UI using a grid bag */
117         public AltosConfigUI(JFrame in_owner, boolean remote) {
118                 super (in_owner, "Configure TeleMetrum", false);
119
120                 owner = in_owner;
121                 GridBagConstraints c;
122
123                 Insets il = new Insets(4,4,4,4);
124                 Insets ir = new Insets(4,4,4,4);
125
126                 pane = getContentPane();
127                 pane.setLayout(new GridBagLayout());
128
129                 /* Product */
130                 c = new GridBagConstraints();
131                 c.gridx = 0; c.gridy = 0;
132                 c.gridwidth = 4;
133                 c.fill = GridBagConstraints.NONE;
134                 c.anchor = GridBagConstraints.LINE_START;
135                 c.insets = il;
136                 product_label = new JLabel("Product:");
137                 pane.add(product_label, c);
138
139                 c = new GridBagConstraints();
140                 c.gridx = 4; c.gridy = 0;
141                 c.gridwidth = 4;
142                 c.fill = GridBagConstraints.HORIZONTAL;
143                 c.weightx = 1;
144                 c.anchor = GridBagConstraints.LINE_START;
145                 c.insets = ir;
146                 product_value = new JLabel("");
147                 pane.add(product_value, c);
148
149                 /* Version */
150                 c = new GridBagConstraints();
151                 c.gridx = 0; c.gridy = 1;
152                 c.gridwidth = 4;
153                 c.fill = GridBagConstraints.NONE;
154                 c.anchor = GridBagConstraints.LINE_START;
155                 c.insets = il;
156                 c.ipady = 5;
157                 version_label = new JLabel("Software version:");
158                 pane.add(version_label, c);
159
160                 c = new GridBagConstraints();
161                 c.gridx = 4; c.gridy = 1;
162                 c.gridwidth = 4;
163                 c.fill = GridBagConstraints.HORIZONTAL;
164                 c.weightx = 1;
165                 c.anchor = GridBagConstraints.LINE_START;
166                 c.insets = ir;
167                 c.ipady = 5;
168                 version_value = new JLabel("");
169                 pane.add(version_value, c);
170
171                 /* Serial */
172                 c = new GridBagConstraints();
173                 c.gridx = 0; c.gridy = 2;
174                 c.gridwidth = 4;
175                 c.fill = GridBagConstraints.NONE;
176                 c.anchor = GridBagConstraints.LINE_START;
177                 c.insets = il;
178                 c.ipady = 5;
179                 serial_label = new JLabel("Serial:");
180                 pane.add(serial_label, c);
181
182                 c = new GridBagConstraints();
183                 c.gridx = 4; c.gridy = 2;
184                 c.gridwidth = 4;
185                 c.fill = GridBagConstraints.HORIZONTAL;
186                 c.weightx = 1;
187                 c.anchor = GridBagConstraints.LINE_START;
188                 c.insets = ir;
189                 c.ipady = 5;
190                 serial_value = new JLabel("");
191                 pane.add(serial_value, c);
192
193                 /* Main deploy */
194                 c = new GridBagConstraints();
195                 c.gridx = 0; c.gridy = 3;
196                 c.gridwidth = 4;
197                 c.fill = GridBagConstraints.NONE;
198                 c.anchor = GridBagConstraints.LINE_START;
199                 c.insets = il;
200                 c.ipady = 5;
201                 main_deploy_label = new JLabel("Main Deploy Altitude(m):");
202                 pane.add(main_deploy_label, c);
203
204                 c = new GridBagConstraints();
205                 c.gridx = 4; c.gridy = 3;
206                 c.gridwidth = 4;
207                 c.fill = GridBagConstraints.HORIZONTAL;
208                 c.weightx = 1;
209                 c.anchor = GridBagConstraints.LINE_START;
210                 c.insets = ir;
211                 c.ipady = 5;
212                 main_deploy_value = new JComboBox(main_deploy_values);
213                 main_deploy_value.setEditable(true);
214                 main_deploy_value.addItemListener(this);
215                 pane.add(main_deploy_value, c);
216
217                 /* Apogee delay */
218                 c = new GridBagConstraints();
219                 c.gridx = 0; c.gridy = 4;
220                 c.gridwidth = 4;
221                 c.fill = GridBagConstraints.NONE;
222                 c.anchor = GridBagConstraints.LINE_START;
223                 c.insets = il;
224                 c.ipady = 5;
225                 apogee_delay_label = new JLabel("Apogee Delay(s):");
226                 pane.add(apogee_delay_label, c);
227
228                 c = new GridBagConstraints();
229                 c.gridx = 4; c.gridy = 4;
230                 c.gridwidth = 4;
231                 c.fill = GridBagConstraints.HORIZONTAL;
232                 c.weightx = 1;
233                 c.anchor = GridBagConstraints.LINE_START;
234                 c.insets = ir;
235                 c.ipady = 5;
236                 apogee_delay_value = new JComboBox(apogee_delay_values);
237                 apogee_delay_value.setEditable(true);
238                 apogee_delay_value.addItemListener(this);
239                 pane.add(apogee_delay_value, c);
240
241                 /* Radio channel */
242                 c = new GridBagConstraints();
243                 c.gridx = 0; c.gridy = 5;
244                 c.gridwidth = 4;
245                 c.fill = GridBagConstraints.NONE;
246                 c.anchor = GridBagConstraints.LINE_START;
247                 c.insets = il;
248                 c.ipady = 5;
249                 radio_channel_label = new JLabel("Radio Channel:");
250                 pane.add(radio_channel_label, c);
251
252                 c = new GridBagConstraints();
253                 c.gridx = 4; c.gridy = 5;
254                 c.gridwidth = 4;
255                 c.fill = GridBagConstraints.HORIZONTAL;
256                 c.weightx = 1;
257                 c.anchor = GridBagConstraints.LINE_START;
258                 c.insets = ir;
259                 c.ipady = 5;
260                 radio_channel_value = new JComboBox(radio_channel_values);
261                 radio_channel_value.setEditable(false);
262                 radio_channel_value.addItemListener(this);
263                 pane.add(radio_channel_value, c);
264
265                 /* Radio Calibration */
266                 c = new GridBagConstraints();
267                 c.gridx = 0; c.gridy = 6;
268                 c.gridwidth = 4;
269                 c.fill = GridBagConstraints.NONE;
270                 c.anchor = GridBagConstraints.LINE_START;
271                 c.insets = il;
272                 c.ipady = 5;
273                 radio_calibration_label = new JLabel("RF Calibration:");
274                 pane.add(radio_calibration_label, c);
275
276                 c = new GridBagConstraints();
277                 c.gridx = 4; c.gridy = 6;
278                 c.gridwidth = 4;
279                 c.fill = GridBagConstraints.HORIZONTAL;
280                 c.weightx = 1;
281                 c.anchor = GridBagConstraints.LINE_START;
282                 c.insets = ir;
283                 c.ipady = 5;
284                 radio_calibration_value = new JTextField(String.format("%d", 1186611));
285                 radio_calibration_value.getDocument().addDocumentListener(this);
286                 if (remote)
287                         radio_calibration_value.setEnabled(false);
288                 pane.add(radio_calibration_value, c);
289
290                 /* Callsign */
291                 c = new GridBagConstraints();
292                 c.gridx = 0; c.gridy = 7;
293                 c.gridwidth = 4;
294                 c.fill = GridBagConstraints.NONE;
295                 c.anchor = GridBagConstraints.LINE_START;
296                 c.insets = il;
297                 c.ipady = 5;
298                 callsign_label = new JLabel("Callsign:");
299                 pane.add(callsign_label, c);
300
301                 c = new GridBagConstraints();
302                 c.gridx = 4; c.gridy = 7;
303                 c.gridwidth = 4;
304                 c.fill = GridBagConstraints.HORIZONTAL;
305                 c.weightx = 1;
306                 c.anchor = GridBagConstraints.LINE_START;
307                 c.insets = ir;
308                 c.ipady = 5;
309                 callsign_value = new JTextField(AltosPreferences.callsign());
310                 callsign_value.getDocument().addDocumentListener(this);
311                 pane.add(callsign_value, c);
312
313                 /* Flight log max */
314                 c = new GridBagConstraints();
315                 c.gridx = 0; c.gridy = 8;
316                 c.gridwidth = 4;
317                 c.fill = GridBagConstraints.NONE;
318                 c.anchor = GridBagConstraints.LINE_START;
319                 c.insets = il;
320                 c.ipady = 5;
321                 flight_log_max_label = new JLabel("Maximum Flight Log Size:");
322                 pane.add(flight_log_max_label, c);
323
324                 c = new GridBagConstraints();
325                 c.gridx = 4; c.gridy = 8;
326                 c.gridwidth = 4;
327                 c.fill = GridBagConstraints.HORIZONTAL;
328                 c.weightx = 1;
329                 c.anchor = GridBagConstraints.LINE_START;
330                 c.insets = ir;
331                 c.ipady = 5;
332                 flight_log_max_value = new JComboBox(flight_log_max_values);
333                 flight_log_max_value.setEditable(true);
334                 flight_log_max_value.addItemListener(this);
335                 pane.add(flight_log_max_value, c);
336
337                 /* Ignite mode */
338                 c = new GridBagConstraints();
339                 c.gridx = 0; c.gridy = 9;
340                 c.gridwidth = 4;
341                 c.fill = GridBagConstraints.NONE;
342                 c.anchor = GridBagConstraints.LINE_START;
343                 c.insets = il;
344                 c.ipady = 5;
345                 ignite_mode_label = new JLabel("Igniter Firing Mode:");
346                 pane.add(ignite_mode_label, c);
347
348                 c = new GridBagConstraints();
349                 c.gridx = 4; c.gridy = 9;
350                 c.gridwidth = 4;
351                 c.fill = GridBagConstraints.HORIZONTAL;
352                 c.weightx = 1;
353                 c.anchor = GridBagConstraints.LINE_START;
354                 c.insets = ir;
355                 c.ipady = 5;
356                 ignite_mode_value = new JComboBox(ignite_mode_values);
357                 ignite_mode_value.setEditable(false);
358                 ignite_mode_value.addItemListener(this);
359                 pane.add(ignite_mode_value, c);
360
361                 /* Buttons */
362                 c = new GridBagConstraints();
363                 c.gridx = 0; c.gridy = 10;
364                 c.gridwidth = 2;
365                 c.fill = GridBagConstraints.NONE;
366                 c.anchor = GridBagConstraints.LINE_START;
367                 c.insets = il;
368                 save = new JButton("Save");
369                 pane.add(save, c);
370                 save.addActionListener(this);
371                 save.setActionCommand("Save");
372
373                 c = new GridBagConstraints();
374                 c.gridx = 2; c.gridy = 10;
375                 c.gridwidth = 2;
376                 c.fill = GridBagConstraints.NONE;
377                 c.anchor = GridBagConstraints.CENTER;
378                 c.insets = il;
379                 reset = new JButton("Reset");
380                 pane.add(reset, c);
381                 reset.addActionListener(this);
382                 reset.setActionCommand("Reset");
383
384                 c = new GridBagConstraints();
385                 c.gridx = 4; c.gridy = 10;
386                 c.gridwidth = 2;
387                 c.fill = GridBagConstraints.NONE;
388                 c.anchor = GridBagConstraints.CENTER;
389                 c.insets = il;
390                 reboot = new JButton("Reboot");
391                 pane.add(reboot, c);
392                 reboot.addActionListener(this);
393                 reboot.setActionCommand("Reboot");
394
395                 c = new GridBagConstraints();
396                 c.gridx = 6; c.gridy = 10;
397                 c.gridwidth = 2;
398                 c.fill = GridBagConstraints.NONE;
399                 c.anchor = GridBagConstraints.LINE_END;
400                 c.insets = il;
401                 close = new JButton("Close");
402                 pane.add(close, c);
403                 close.addActionListener(this);
404                 close.setActionCommand("Close");
405
406                 addWindowListener(new ConfigListener(this));
407         }
408
409         /* Once the initial values are set, the config code will show the dialog */
410         public void make_visible() {
411                 pack();
412                 setLocationRelativeTo(owner);
413                 setVisible(true);
414         }
415
416         /* If any values have been changed, confirm before closing */
417         public boolean check_dirty(String operation) {
418                 if (dirty) {
419                         Object[] options = { String.format("%s anyway", operation), "Keep editing" };
420                         int i;
421                         i = JOptionPane.showOptionDialog(this,
422                                                          String.format("Configuration modified. %s anyway?", operation),
423                                                          "Configuration Modified",
424                                                          JOptionPane.DEFAULT_OPTION,
425                                                          JOptionPane.WARNING_MESSAGE,
426                                                          null, options, options[1]);
427                         if (i != 0)
428                                 return false;
429                 }
430                 return true;
431         }
432
433         /* Listen for events from our buttons */
434         public void actionPerformed(ActionEvent e) {
435                 String  cmd = e.getActionCommand();
436
437                 if (cmd.equals("Close") || cmd.equals("Reboot"))
438                         if (!check_dirty(cmd))
439                                 return;
440                 listener.actionPerformed(e);
441                 if (cmd.equals("Close") || cmd.equals("Reboot")) {
442                         setVisible(false);
443                         dispose();
444                 }
445                 dirty = false;
446         }
447
448         /* ItemListener interface method */
449         public void itemStateChanged(ItemEvent e) {
450                 dirty = true;
451         }
452
453         /* DocumentListener interface methods */
454         public void changedUpdate(DocumentEvent e) {
455                 dirty = true;
456         }
457
458         public void insertUpdate(DocumentEvent e) {
459                 dirty = true;
460         }
461
462         public void removeUpdate(DocumentEvent e) {
463                 dirty = true;
464         }
465
466         /* Let the config code hook on a listener */
467         public void addActionListener(ActionListener l) {
468                 listener = l;
469         }
470
471         /* set and get all of the dialog values */
472         public void set_product(String product) {
473                 product_value.setText(product);
474         }
475
476         public void set_version(String version) {
477                 version_value.setText(version);
478         }
479
480         public void set_serial(int serial) {
481                 serial_value.setText(String.format("%d", serial));
482         }
483
484         public void set_main_deploy(int new_main_deploy) {
485                 main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
486         }
487
488         public int main_deploy() {
489                 return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
490         }
491
492         public void set_apogee_delay(int new_apogee_delay) {
493                 apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
494         }
495
496         public int apogee_delay() {
497                 return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
498         }
499
500         public void set_radio_channel(int new_radio_channel) {
501                 radio_channel_value.setSelectedIndex(new_radio_channel);
502         }
503
504         public int radio_channel() {
505                 return radio_channel_value.getSelectedIndex();
506         }
507
508         public void set_radio_calibration(int new_radio_calibration) {
509                 radio_calibration_value.setText(String.format("%d", new_radio_calibration));
510         }
511
512         public int radio_calibration() {
513                 return Integer.parseInt(radio_calibration_value.getText());
514         }
515
516         public void set_callsign(String new_callsign) {
517                 callsign_value.setText(new_callsign);
518         }
519
520         public String callsign() {
521                 return callsign_value.getText();
522         }
523
524         public void set_flight_log_max(int new_flight_log_max) {
525                 if (new_flight_log_max == 0)
526                         flight_log_max_value.setEnabled(false);
527                 flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max));
528         }
529
530         public int flight_log_max() {
531                 return Integer.parseInt(flight_log_max_value.getSelectedItem().toString());
532         }
533
534         public void set_ignite_mode(int new_ignite_mode) {
535                 if (new_ignite_mode < 0) {
536                         ignite_mode_value.setEnabled(false);
537                         new_ignite_mode = 0;
538                 } else {
539                         ignite_mode_value.setEnabled(true);
540                 }
541                 ignite_mode_value.setSelectedItem(Integer.toString(new_ignite_mode));
542         }
543
544         public int ignite_mode() {
545                 return ignite_mode_value.getSelectedIndex();
546         }
547
548         public void set_clean() {
549                 dirty = false;
550         }
551 }