altosui: Respect storage limits in flight log max config
[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          frequency_label;
47         JLabel          radio_calibration_label;
48         JLabel          radio_frequency_label;
49         JLabel          flight_log_max_label;
50         JLabel          ignite_mode_label;
51         JLabel          pad_orientation_label;
52         JLabel          callsign_label;
53
54         public boolean          dirty;
55
56         JFrame          owner;
57         JLabel          product_value;
58         JLabel          version_value;
59         JLabel          serial_value;
60         JComboBox       main_deploy_value;
61         JComboBox       apogee_delay_value;
62         AltosFreqList   radio_frequency_value;
63         JTextField      radio_calibration_value;
64         JComboBox       flight_log_max_value;
65         JComboBox       ignite_mode_value;
66         JComboBox       pad_orientation_value;
67         JTextField      callsign_value;
68
69         JButton         save;
70         JButton         reset;
71         JButton         reboot;
72         JButton         close;
73
74         ActionListener  listener;
75
76         static String[] main_deploy_values = {
77                 "100", "150", "200", "250", "300", "350",
78                 "400", "450", "500"
79         };
80
81         static String[] apogee_delay_values = {
82                 "0", "1", "2", "3", "4", "5"
83         };
84
85         static String[] flight_log_max_values = {
86                 "64", "128", "192", "256", "320",
87                 "384", "448", "512", "576", "640",
88                 "704", "768", "832", "896", "960",
89         };
90
91         static String[] ignite_mode_values = {
92                 "Dual Deploy",
93                 "Redundant Apogee",
94                 "Redundant Main",
95         };
96
97         static String[] pad_orientation_values = {
98                 "Antenna Up",
99                 "Antenna Down",
100         };
101
102         /* A window listener to catch closing events and tell the config code */
103         class ConfigListener extends WindowAdapter {
104                 AltosConfigUI   ui;
105
106                 public ConfigListener(AltosConfigUI this_ui) {
107                         ui = this_ui;
108                 }
109
110                 public void windowClosing(WindowEvent e) {
111                         ui.actionPerformed(new ActionEvent(e.getSource(),
112                                                            ActionEvent.ACTION_PERFORMED,
113                                                            "Close"));
114                 }
115         }
116
117         /* Build the UI using a grid bag */
118         public AltosConfigUI(JFrame in_owner, boolean remote) {
119                 super (in_owner, "Configure TeleMetrum", false);
120
121                 owner = in_owner;
122                 GridBagConstraints c;
123
124                 Insets il = new Insets(4,4,4,4);
125                 Insets ir = new Insets(4,4,4,4);
126
127                 pane = getContentPane();
128                 pane.setLayout(new GridBagLayout());
129
130                 /* Product */
131                 c = new GridBagConstraints();
132                 c.gridx = 0; c.gridy = 0;
133                 c.gridwidth = 4;
134                 c.fill = GridBagConstraints.NONE;
135                 c.anchor = GridBagConstraints.LINE_START;
136                 c.insets = il;
137                 product_label = new JLabel("Product:");
138                 pane.add(product_label, c);
139
140                 c = new GridBagConstraints();
141                 c.gridx = 4; c.gridy = 0;
142                 c.gridwidth = 4;
143                 c.fill = GridBagConstraints.HORIZONTAL;
144                 c.weightx = 1;
145                 c.anchor = GridBagConstraints.LINE_START;
146                 c.insets = ir;
147                 product_value = new JLabel("");
148                 pane.add(product_value, c);
149
150                 /* Version */
151                 c = new GridBagConstraints();
152                 c.gridx = 0; c.gridy = 1;
153                 c.gridwidth = 4;
154                 c.fill = GridBagConstraints.NONE;
155                 c.anchor = GridBagConstraints.LINE_START;
156                 c.insets = il;
157                 c.ipady = 5;
158                 version_label = new JLabel("Software version:");
159                 pane.add(version_label, c);
160
161                 c = new GridBagConstraints();
162                 c.gridx = 4; c.gridy = 1;
163                 c.gridwidth = 4;
164                 c.fill = GridBagConstraints.HORIZONTAL;
165                 c.weightx = 1;
166                 c.anchor = GridBagConstraints.LINE_START;
167                 c.insets = ir;
168                 c.ipady = 5;
169                 version_value = new JLabel("");
170                 pane.add(version_value, c);
171
172                 /* Serial */
173                 c = new GridBagConstraints();
174                 c.gridx = 0; c.gridy = 2;
175                 c.gridwidth = 4;
176                 c.fill = GridBagConstraints.NONE;
177                 c.anchor = GridBagConstraints.LINE_START;
178                 c.insets = il;
179                 c.ipady = 5;
180                 serial_label = new JLabel("Serial:");
181                 pane.add(serial_label, c);
182
183                 c = new GridBagConstraints();
184                 c.gridx = 4; c.gridy = 2;
185                 c.gridwidth = 4;
186                 c.fill = GridBagConstraints.HORIZONTAL;
187                 c.weightx = 1;
188                 c.anchor = GridBagConstraints.LINE_START;
189                 c.insets = ir;
190                 c.ipady = 5;
191                 serial_value = new JLabel("");
192                 pane.add(serial_value, c);
193
194                 /* Main deploy */
195                 c = new GridBagConstraints();
196                 c.gridx = 0; c.gridy = 3;
197                 c.gridwidth = 4;
198                 c.fill = GridBagConstraints.NONE;
199                 c.anchor = GridBagConstraints.LINE_START;
200                 c.insets = il;
201                 c.ipady = 5;
202                 main_deploy_label = new JLabel("Main Deploy Altitude(m):");
203                 pane.add(main_deploy_label, c);
204
205                 c = new GridBagConstraints();
206                 c.gridx = 4; c.gridy = 3;
207                 c.gridwidth = 4;
208                 c.fill = GridBagConstraints.HORIZONTAL;
209                 c.weightx = 1;
210                 c.anchor = GridBagConstraints.LINE_START;
211                 c.insets = ir;
212                 c.ipady = 5;
213                 main_deploy_value = new JComboBox(main_deploy_values);
214                 main_deploy_value.setEditable(true);
215                 main_deploy_value.addItemListener(this);
216                 pane.add(main_deploy_value, c);
217
218                 /* Apogee delay */
219                 c = new GridBagConstraints();
220                 c.gridx = 0; c.gridy = 4;
221                 c.gridwidth = 4;
222                 c.fill = GridBagConstraints.NONE;
223                 c.anchor = GridBagConstraints.LINE_START;
224                 c.insets = il;
225                 c.ipady = 5;
226                 apogee_delay_label = new JLabel("Apogee Delay(s):");
227                 pane.add(apogee_delay_label, c);
228
229                 c = new GridBagConstraints();
230                 c.gridx = 4; c.gridy = 4;
231                 c.gridwidth = 4;
232                 c.fill = GridBagConstraints.HORIZONTAL;
233                 c.weightx = 1;
234                 c.anchor = GridBagConstraints.LINE_START;
235                 c.insets = ir;
236                 c.ipady = 5;
237                 apogee_delay_value = new JComboBox(apogee_delay_values);
238                 apogee_delay_value.setEditable(true);
239                 apogee_delay_value.addItemListener(this);
240                 pane.add(apogee_delay_value, c);
241
242                 /* Frequency */
243                 c = new GridBagConstraints();
244                 c.gridx = 0; c.gridy = 5;
245                 c.gridwidth = 4;
246                 c.fill = GridBagConstraints.NONE;
247                 c.anchor = GridBagConstraints.LINE_START;
248                 c.insets = il;
249                 c.ipady = 5;
250                 radio_frequency_label = new JLabel("Frequency:");
251                 pane.add(radio_frequency_label, c);
252
253                 c = new GridBagConstraints();
254                 c.gridx = 4; c.gridy = 5;
255                 c.gridwidth = 4;
256                 c.fill = GridBagConstraints.HORIZONTAL;
257                 c.weightx = 1;
258                 c.anchor = GridBagConstraints.LINE_START;
259                 c.insets = ir;
260                 c.ipady = 5;
261                 radio_frequency_value = new AltosFreqList();
262                 radio_frequency_value.addItemListener(this);
263                 pane.add(radio_frequency_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                 /* Pad orientation */
362                 c = new GridBagConstraints();
363                 c.gridx = 0; c.gridy = 10;
364                 c.gridwidth = 4;
365                 c.fill = GridBagConstraints.NONE;
366                 c.anchor = GridBagConstraints.LINE_START;
367                 c.insets = il;
368                 c.ipady = 5;
369                 pad_orientation_label = new JLabel("Pad Orientation:");
370                 pane.add(pad_orientation_label, c);
371
372                 c = new GridBagConstraints();
373                 c.gridx = 4; c.gridy = 10;
374                 c.gridwidth = 4;
375                 c.fill = GridBagConstraints.HORIZONTAL;
376                 c.weightx = 1;
377                 c.anchor = GridBagConstraints.LINE_START;
378                 c.insets = ir;
379                 c.ipady = 5;
380                 pad_orientation_value = new JComboBox(pad_orientation_values);
381                 pad_orientation_value.setEditable(false);
382                 pad_orientation_value.addItemListener(this);
383                 pane.add(pad_orientation_value, c);
384
385                 /* Buttons */
386                 c = new GridBagConstraints();
387                 c.gridx = 0; c.gridy = 11;
388                 c.gridwidth = 2;
389                 c.fill = GridBagConstraints.NONE;
390                 c.anchor = GridBagConstraints.LINE_START;
391                 c.insets = il;
392                 save = new JButton("Save");
393                 pane.add(save, c);
394                 save.addActionListener(this);
395                 save.setActionCommand("Save");
396
397                 c = new GridBagConstraints();
398                 c.gridx = 2; c.gridy = 11;
399                 c.gridwidth = 2;
400                 c.fill = GridBagConstraints.NONE;
401                 c.anchor = GridBagConstraints.CENTER;
402                 c.insets = il;
403                 reset = new JButton("Reset");
404                 pane.add(reset, c);
405                 reset.addActionListener(this);
406                 reset.setActionCommand("Reset");
407
408                 c = new GridBagConstraints();
409                 c.gridx = 4; c.gridy = 11;
410                 c.gridwidth = 2;
411                 c.fill = GridBagConstraints.NONE;
412                 c.anchor = GridBagConstraints.CENTER;
413                 c.insets = il;
414                 reboot = new JButton("Reboot");
415                 pane.add(reboot, c);
416                 reboot.addActionListener(this);
417                 reboot.setActionCommand("Reboot");
418
419                 c = new GridBagConstraints();
420                 c.gridx = 6; c.gridy = 11;
421                 c.gridwidth = 2;
422                 c.fill = GridBagConstraints.NONE;
423                 c.anchor = GridBagConstraints.LINE_END;
424                 c.insets = il;
425                 close = new JButton("Close");
426                 pane.add(close, c);
427                 close.addActionListener(this);
428                 close.setActionCommand("Close");
429
430                 addWindowListener(new ConfigListener(this));
431         }
432
433         /* Once the initial values are set, the config code will show the dialog */
434         public void make_visible() {
435                 pack();
436                 setLocationRelativeTo(owner);
437                 setVisible(true);
438         }
439
440         /* If any values have been changed, confirm before closing */
441         public boolean check_dirty(String operation) {
442                 if (dirty) {
443                         Object[] options = { String.format("%s anyway", operation), "Keep editing" };
444                         int i;
445                         i = JOptionPane.showOptionDialog(this,
446                                                          String.format("Configuration modified. %s anyway?", operation),
447                                                          "Configuration Modified",
448                                                          JOptionPane.DEFAULT_OPTION,
449                                                          JOptionPane.WARNING_MESSAGE,
450                                                          null, options, options[1]);
451                         if (i != 0)
452                                 return false;
453                 }
454                 return true;
455         }
456
457         /* Listen for events from our buttons */
458         public void actionPerformed(ActionEvent e) {
459                 String  cmd = e.getActionCommand();
460
461                 if (cmd.equals("Close") || cmd.equals("Reboot"))
462                         if (!check_dirty(cmd))
463                                 return;
464                 listener.actionPerformed(e);
465                 if (cmd.equals("Close") || cmd.equals("Reboot")) {
466                         setVisible(false);
467                         dispose();
468                 }
469                 dirty = false;
470         }
471
472         /* ItemListener interface method */
473         public void itemStateChanged(ItemEvent e) {
474                 dirty = true;
475         }
476
477         /* DocumentListener interface methods */
478         public void changedUpdate(DocumentEvent e) {
479                 dirty = true;
480         }
481
482         public void insertUpdate(DocumentEvent e) {
483                 dirty = true;
484         }
485
486         public void removeUpdate(DocumentEvent e) {
487                 dirty = true;
488         }
489
490         /* Let the config code hook on a listener */
491         public void addActionListener(ActionListener l) {
492                 listener = l;
493         }
494
495         /* set and get all of the dialog values */
496         public void set_product(String product) {
497                 radio_frequency_value.set_product(product);
498                 product_value.setText(product);
499         }
500
501         public void set_version(String version) {
502                 version_value.setText(version);
503         }
504
505         public void set_serial(int serial) {
506                 radio_frequency_value.set_serial(serial);
507                 serial_value.setText(String.format("%d", serial));
508         }
509
510         public void set_main_deploy(int new_main_deploy) {
511                 main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
512         }
513
514         public int main_deploy() {
515                 return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
516         }
517
518         public void set_apogee_delay(int new_apogee_delay) {
519                 apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
520         }
521
522         public int apogee_delay() {
523                 return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
524         }
525
526         public void set_radio_frequency(double new_radio_frequency) {
527                 int i;
528                 for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
529                         AltosFrequency  f = (AltosFrequency) radio_frequency_value.getItemAt(i);
530                         
531                         if (f.close(new_radio_frequency)) {
532                                 radio_frequency_value.setSelectedIndex(i);
533                                 return;
534                         }
535                 }
536                 for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
537                         AltosFrequency  f = (AltosFrequency) radio_frequency_value.getItemAt(i);
538                         
539                         if (new_radio_frequency < f.frequency)
540                                 break;
541                 }
542                 String  description = String.format("%s serial %s",
543                                                     product_value.getText(),
544                                                     serial_value.getText());
545                 AltosFrequency  new_frequency = new AltosFrequency(new_radio_frequency, description);
546                 AltosPreferences.add_common_frequency(new_frequency);
547                 radio_frequency_value.insertItemAt(new_frequency, i);
548         }
549
550         public double radio_frequency() {
551                 return radio_frequency_value.frequency();
552         }
553
554         public void set_radio_calibration(int new_radio_calibration) {
555                 radio_calibration_value.setText(String.format("%d", new_radio_calibration));
556         }
557
558         public int radio_calibration() {
559                 return Integer.parseInt(radio_calibration_value.getText());
560         }
561
562         public void set_callsign(String new_callsign) {
563                 callsign_value.setText(new_callsign);
564         }
565
566         public String callsign() {
567                 return callsign_value.getText();
568         }
569
570         public void set_flight_log_max(int new_flight_log_max) {
571                 if (new_flight_log_max == 0)
572                         flight_log_max_value.setEnabled(false);
573                 flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max));
574         }
575
576         public int flight_log_max() {
577                 return Integer.parseInt(flight_log_max_value.getSelectedItem().toString());
578         }
579
580         public void set_flight_log_max_limit(int flight_log_max_limit) {
581                 boolean any_added = false;
582                 flight_log_max_value.removeAllItems();
583                 for (int i = 0; i < flight_log_max_values.length; i++) {
584                         if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){
585                                 flight_log_max_value.addItem(flight_log_max_values[i]);
586                                 any_added = true;
587                         }
588                 }
589                 flight_log_max_value.addItem(String.format("%d", flight_log_max_limit));
590         }
591
592         public void set_ignite_mode(int new_ignite_mode) {
593                 if (new_ignite_mode < 0) {
594                         ignite_mode_value.setEnabled(false);
595                         new_ignite_mode = 0;
596                 } else {
597                         ignite_mode_value.setEnabled(true);
598                 }
599                 ignite_mode_value.setSelectedIndex(new_ignite_mode);
600         }
601
602         public int ignite_mode() {
603                 if (ignite_mode_value.isEnabled())
604                         return ignite_mode_value.getSelectedIndex();
605                 else
606                         return -1;
607         }
608
609
610         public void set_pad_orientation(int new_pad_orientation) {
611                 if (new_pad_orientation < 0) {
612                         pad_orientation_value.setEnabled(false);
613                         new_pad_orientation = 0;
614                 } else {
615                         pad_orientation_value.setEnabled(true);
616                 }
617                 pad_orientation_value.setSelectedIndex(new_pad_orientation);
618         }
619
620         public int pad_orientation() {
621                 if (pad_orientation_value.isEnabled())
622                         return pad_orientation_value.getSelectedIndex();
623                 else
624                         return -1;
625         }
626
627         public void set_clean() {
628                 dirty = false;
629         }
630 }