2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
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.
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.
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.
21 import java.awt.event.*;
23 import javax.swing.filechooser.FileNameExtensionFilter;
24 import javax.swing.table.*;
25 import javax.swing.event.*;
29 import java.util.prefs.*;
30 import java.util.concurrent.LinkedBlockingQueue;
34 public class AltosConfigUI
36 implements ActionListener, ItemListener, DocumentListener
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 radio_enable_label;
50 JLabel flight_log_max_label;
51 JLabel ignite_mode_label;
52 JLabel pad_orientation_label;
53 JLabel callsign_label;
61 JComboBox main_deploy_value;
62 JComboBox apogee_delay_value;
63 AltosFreqList radio_frequency_value;
64 JTextField radio_calibration_value;
65 JRadioButton radio_enable_value;
66 JComboBox flight_log_max_value;
67 JComboBox ignite_mode_value;
68 JComboBox pad_orientation_value;
69 JTextField callsign_value;
76 ActionListener listener;
78 static String[] main_deploy_values = {
79 "100", "150", "200", "250", "300", "350",
83 static String[] apogee_delay_values = {
84 "0", "1", "2", "3", "4", "5"
87 static String[] flight_log_max_values = {
88 "64", "128", "192", "256", "320",
89 "384", "448", "512", "576", "640",
90 "704", "768", "832", "896", "960",
93 static String[] ignite_mode_values = {
99 static String[] pad_orientation_values = {
104 /* A window listener to catch closing events and tell the config code */
105 class ConfigListener extends WindowAdapter {
108 public ConfigListener(AltosConfigUI this_ui) {
112 public void windowClosing(WindowEvent e) {
113 ui.actionPerformed(new ActionEvent(e.getSource(),
114 ActionEvent.ACTION_PERFORMED,
119 /* Build the UI using a grid bag */
120 public AltosConfigUI(JFrame in_owner, boolean remote) {
121 super (in_owner, "Configure TeleMetrum", false);
124 GridBagConstraints c;
126 Insets il = new Insets(4,4,4,4);
127 Insets ir = new Insets(4,4,4,4);
129 pane = getContentPane();
130 pane.setLayout(new GridBagLayout());
133 c = new GridBagConstraints();
134 c.gridx = 0; c.gridy = 0;
136 c.fill = GridBagConstraints.NONE;
137 c.anchor = GridBagConstraints.LINE_START;
139 product_label = new JLabel("Product:");
140 pane.add(product_label, c);
142 c = new GridBagConstraints();
143 c.gridx = 4; c.gridy = 0;
145 c.fill = GridBagConstraints.HORIZONTAL;
147 c.anchor = GridBagConstraints.LINE_START;
149 product_value = new JLabel("");
150 pane.add(product_value, c);
153 c = new GridBagConstraints();
154 c.gridx = 0; c.gridy = 1;
156 c.fill = GridBagConstraints.NONE;
157 c.anchor = GridBagConstraints.LINE_START;
160 version_label = new JLabel("Software version:");
161 pane.add(version_label, c);
163 c = new GridBagConstraints();
164 c.gridx = 4; c.gridy = 1;
166 c.fill = GridBagConstraints.HORIZONTAL;
168 c.anchor = GridBagConstraints.LINE_START;
171 version_value = new JLabel("");
172 pane.add(version_value, c);
175 c = new GridBagConstraints();
176 c.gridx = 0; c.gridy = 2;
178 c.fill = GridBagConstraints.NONE;
179 c.anchor = GridBagConstraints.LINE_START;
182 serial_label = new JLabel("Serial:");
183 pane.add(serial_label, c);
185 c = new GridBagConstraints();
186 c.gridx = 4; c.gridy = 2;
188 c.fill = GridBagConstraints.HORIZONTAL;
190 c.anchor = GridBagConstraints.LINE_START;
193 serial_value = new JLabel("");
194 pane.add(serial_value, c);
197 c = new GridBagConstraints();
198 c.gridx = 0; c.gridy = 3;
200 c.fill = GridBagConstraints.NONE;
201 c.anchor = GridBagConstraints.LINE_START;
204 main_deploy_label = new JLabel("Main Deploy Altitude(m):");
205 pane.add(main_deploy_label, c);
207 c = new GridBagConstraints();
208 c.gridx = 4; c.gridy = 3;
210 c.fill = GridBagConstraints.HORIZONTAL;
212 c.anchor = GridBagConstraints.LINE_START;
215 main_deploy_value = new JComboBox(main_deploy_values);
216 main_deploy_value.setEditable(true);
217 main_deploy_value.addItemListener(this);
218 pane.add(main_deploy_value, c);
221 c = new GridBagConstraints();
222 c.gridx = 0; c.gridy = 4;
224 c.fill = GridBagConstraints.NONE;
225 c.anchor = GridBagConstraints.LINE_START;
228 apogee_delay_label = new JLabel("Apogee Delay(s):");
229 pane.add(apogee_delay_label, c);
231 c = new GridBagConstraints();
232 c.gridx = 4; c.gridy = 4;
234 c.fill = GridBagConstraints.HORIZONTAL;
236 c.anchor = GridBagConstraints.LINE_START;
239 apogee_delay_value = new JComboBox(apogee_delay_values);
240 apogee_delay_value.setEditable(true);
241 apogee_delay_value.addItemListener(this);
242 pane.add(apogee_delay_value, c);
245 c = new GridBagConstraints();
246 c.gridx = 0; c.gridy = 5;
248 c.fill = GridBagConstraints.NONE;
249 c.anchor = GridBagConstraints.LINE_START;
252 radio_frequency_label = new JLabel("Frequency:");
253 pane.add(radio_frequency_label, c);
255 c = new GridBagConstraints();
256 c.gridx = 4; c.gridy = 5;
258 c.fill = GridBagConstraints.HORIZONTAL;
260 c.anchor = GridBagConstraints.LINE_START;
263 radio_frequency_value = new AltosFreqList();
264 radio_frequency_value.addItemListener(this);
265 pane.add(radio_frequency_value, c);
267 /* Radio Calibration */
268 c = new GridBagConstraints();
269 c.gridx = 0; c.gridy = 6;
271 c.fill = GridBagConstraints.NONE;
272 c.anchor = GridBagConstraints.LINE_START;
275 radio_calibration_label = new JLabel("RF Calibration:");
276 pane.add(radio_calibration_label, c);
278 c = new GridBagConstraints();
279 c.gridx = 4; c.gridy = 6;
281 c.fill = GridBagConstraints.HORIZONTAL;
283 c.anchor = GridBagConstraints.LINE_START;
286 radio_calibration_value = new JTextField(String.format("%d", 1186611));
287 radio_calibration_value.getDocument().addDocumentListener(this);
289 radio_calibration_value.setEnabled(false);
290 pane.add(radio_calibration_value, c);
293 c = new GridBagConstraints();
294 c.gridx = 0; c.gridy = 7;
296 c.fill = GridBagConstraints.NONE;
297 c.anchor = GridBagConstraints.LINE_START;
300 radio_enable_label = new JLabel("Telemetry/RDF Enable:");
301 pane.add(radio_enable_label, c);
303 c = new GridBagConstraints();
304 c.gridx = 4; c.gridy = 7;
306 c.fill = GridBagConstraints.HORIZONTAL;
308 c.anchor = GridBagConstraints.LINE_START;
311 radio_enable_value = new JRadioButton("Enabled");
312 radio_enable_value.addItemListener(this);
313 pane.add(radio_enable_value, c);
316 c = new GridBagConstraints();
317 c.gridx = 0; c.gridy = 8;
319 c.fill = GridBagConstraints.NONE;
320 c.anchor = GridBagConstraints.LINE_START;
323 callsign_label = new JLabel("Callsign:");
324 pane.add(callsign_label, c);
326 c = new GridBagConstraints();
327 c.gridx = 4; c.gridy = 8;
329 c.fill = GridBagConstraints.HORIZONTAL;
331 c.anchor = GridBagConstraints.LINE_START;
334 callsign_value = new JTextField(AltosPreferences.callsign());
335 callsign_value.getDocument().addDocumentListener(this);
336 pane.add(callsign_value, c);
339 c = new GridBagConstraints();
340 c.gridx = 0; c.gridy = 9;
342 c.fill = GridBagConstraints.NONE;
343 c.anchor = GridBagConstraints.LINE_START;
346 flight_log_max_label = new JLabel("Maximum Flight Log Size:");
347 pane.add(flight_log_max_label, c);
349 c = new GridBagConstraints();
350 c.gridx = 4; c.gridy = 9;
352 c.fill = GridBagConstraints.HORIZONTAL;
354 c.anchor = GridBagConstraints.LINE_START;
357 flight_log_max_value = new JComboBox(flight_log_max_values);
358 flight_log_max_value.setEditable(true);
359 flight_log_max_value.addItemListener(this);
360 pane.add(flight_log_max_value, c);
363 c = new GridBagConstraints();
364 c.gridx = 0; c.gridy = 10;
366 c.fill = GridBagConstraints.NONE;
367 c.anchor = GridBagConstraints.LINE_START;
370 ignite_mode_label = new JLabel("Igniter Firing Mode:");
371 pane.add(ignite_mode_label, c);
373 c = new GridBagConstraints();
374 c.gridx = 4; c.gridy = 10;
376 c.fill = GridBagConstraints.HORIZONTAL;
378 c.anchor = GridBagConstraints.LINE_START;
381 ignite_mode_value = new JComboBox(ignite_mode_values);
382 ignite_mode_value.setEditable(false);
383 ignite_mode_value.addItemListener(this);
384 pane.add(ignite_mode_value, c);
386 /* Pad orientation */
387 c = new GridBagConstraints();
388 c.gridx = 0; c.gridy = 11;
390 c.fill = GridBagConstraints.NONE;
391 c.anchor = GridBagConstraints.LINE_START;
394 pad_orientation_label = new JLabel("Pad Orientation:");
395 pane.add(pad_orientation_label, c);
397 c = new GridBagConstraints();
398 c.gridx = 4; c.gridy = 11;
400 c.fill = GridBagConstraints.HORIZONTAL;
402 c.anchor = GridBagConstraints.LINE_START;
405 pad_orientation_value = new JComboBox(pad_orientation_values);
406 pad_orientation_value.setEditable(false);
407 pad_orientation_value.addItemListener(this);
408 pane.add(pad_orientation_value, c);
411 c = new GridBagConstraints();
412 c.gridx = 0; c.gridy = 12;
414 c.fill = GridBagConstraints.NONE;
415 c.anchor = GridBagConstraints.LINE_START;
417 save = new JButton("Save");
419 save.addActionListener(this);
420 save.setActionCommand("Save");
422 c = new GridBagConstraints();
423 c.gridx = 2; c.gridy = 12;
425 c.fill = GridBagConstraints.NONE;
426 c.anchor = GridBagConstraints.CENTER;
428 reset = new JButton("Reset");
430 reset.addActionListener(this);
431 reset.setActionCommand("Reset");
433 c = new GridBagConstraints();
434 c.gridx = 4; c.gridy = 12;
436 c.fill = GridBagConstraints.NONE;
437 c.anchor = GridBagConstraints.CENTER;
439 reboot = new JButton("Reboot");
441 reboot.addActionListener(this);
442 reboot.setActionCommand("Reboot");
444 c = new GridBagConstraints();
445 c.gridx = 6; c.gridy = 12;
447 c.fill = GridBagConstraints.NONE;
448 c.anchor = GridBagConstraints.LINE_END;
450 close = new JButton("Close");
452 close.addActionListener(this);
453 close.setActionCommand("Close");
455 addWindowListener(new ConfigListener(this));
458 /* Once the initial values are set, the config code will show the dialog */
459 public void make_visible() {
461 setLocationRelativeTo(owner);
465 /* If any values have been changed, confirm before closing */
466 public boolean check_dirty(String operation) {
468 Object[] options = { String.format("%s anyway", operation), "Keep editing" };
470 i = JOptionPane.showOptionDialog(this,
471 String.format("Configuration modified. %s anyway?", operation),
472 "Configuration Modified",
473 JOptionPane.DEFAULT_OPTION,
474 JOptionPane.WARNING_MESSAGE,
475 null, options, options[1]);
482 /* Listen for events from our buttons */
483 public void actionPerformed(ActionEvent e) {
484 String cmd = e.getActionCommand();
486 if (cmd.equals("Close") || cmd.equals("Reboot"))
487 if (!check_dirty(cmd))
489 listener.actionPerformed(e);
490 if (cmd.equals("Close") || cmd.equals("Reboot")) {
497 /* ItemListener interface method */
498 public void itemStateChanged(ItemEvent e) {
502 /* DocumentListener interface methods */
503 public void changedUpdate(DocumentEvent e) {
507 public void insertUpdate(DocumentEvent e) {
511 public void removeUpdate(DocumentEvent e) {
515 /* Let the config code hook on a listener */
516 public void addActionListener(ActionListener l) {
520 /* set and get all of the dialog values */
521 public void set_product(String product) {
522 radio_frequency_value.set_product(product);
523 product_value.setText(product);
526 public void set_version(String version) {
527 version_value.setText(version);
530 public void set_serial(int serial) {
531 radio_frequency_value.set_serial(serial);
532 serial_value.setText(String.format("%d", serial));
535 public void set_main_deploy(int new_main_deploy) {
536 main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
539 public int main_deploy() {
540 return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
543 public void set_apogee_delay(int new_apogee_delay) {
544 apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
547 public int apogee_delay() {
548 return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
551 public void set_radio_frequency(double new_radio_frequency) {
553 for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
554 AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i);
556 if (f.close(new_radio_frequency)) {
557 radio_frequency_value.setSelectedIndex(i);
561 for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
562 AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i);
564 if (new_radio_frequency < f.frequency)
567 String description = String.format("%s serial %s",
568 product_value.getText(),
569 serial_value.getText());
570 AltosFrequency new_frequency = new AltosFrequency(new_radio_frequency, description);
571 AltosPreferences.add_common_frequency(new_frequency);
572 radio_frequency_value.insertItemAt(new_frequency, i);
575 public double radio_frequency() {
576 return radio_frequency_value.frequency();
579 public void set_radio_calibration(int new_radio_calibration) {
580 radio_calibration_value.setText(String.format("%d", new_radio_calibration));
583 public int radio_calibration() {
584 return Integer.parseInt(radio_calibration_value.getText());
587 public void set_radio_enable(int new_radio_enable) {
588 if (new_radio_enable >= 0)
589 radio_enable_value.setSelected(new_radio_enable > 0);
591 radio_enable_value.setSelected(true);
592 radio_enable_value.setEnabled(false);
596 public int radio_enable() {
597 if (radio_enable_value.isEnabled())
598 return radio_enable_value.isSelected() ? 1 : 0;
603 public void set_callsign(String new_callsign) {
604 callsign_value.setText(new_callsign);
607 public String callsign() {
608 return callsign_value.getText();
611 public void set_flight_log_max(int new_flight_log_max) {
612 if (new_flight_log_max == 0)
613 flight_log_max_value.setEnabled(false);
614 flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max));
617 public void set_flight_log_max_enabled(boolean enable) {
618 flight_log_max_value.setEnabled(enable);
621 public int flight_log_max() {
622 return Integer.parseInt(flight_log_max_value.getSelectedItem().toString());
625 public void set_flight_log_max_limit(int flight_log_max_limit) {
626 boolean any_added = false;
627 flight_log_max_value.removeAllItems();
628 for (int i = 0; i < flight_log_max_values.length; i++) {
629 if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){
630 flight_log_max_value.addItem(flight_log_max_values[i]);
634 flight_log_max_value.addItem(String.format("%d", flight_log_max_limit));
637 public void set_ignite_mode(int new_ignite_mode) {
638 if (new_ignite_mode < 0) {
639 ignite_mode_value.setEnabled(false);
642 ignite_mode_value.setEnabled(true);
644 ignite_mode_value.setSelectedIndex(new_ignite_mode);
647 public int ignite_mode() {
648 if (ignite_mode_value.isEnabled())
649 return ignite_mode_value.getSelectedIndex();
655 public void set_pad_orientation(int new_pad_orientation) {
656 if (new_pad_orientation < 0) {
657 pad_orientation_value.setEnabled(false);
658 new_pad_orientation = 0;
660 pad_orientation_value.setEnabled(true);
662 pad_orientation_value.setSelectedIndex(new_pad_orientation);
665 public int pad_orientation() {
666 if (pad_orientation_value.isEnabled())
667 return pad_orientation_value.getSelectedIndex();
672 public void set_clean() {