6825b9a9894d62a3c80c1bd65baa2a18ef84b662
[fw/altos] / ao-tools / 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 altosui.Altos;
33 import altosui.AltosSerial;
34 import altosui.AltosSerialMonitor;
35 import altosui.AltosRecord;
36 import altosui.AltosTelemetry;
37 import altosui.AltosState;
38 import altosui.AltosDeviceDialog;
39 import altosui.AltosPreferences;
40 import altosui.AltosLog;
41 import altosui.AltosVoice;
42 import altosui.AltosFlightStatusTableModel;
43 import altosui.AltosFlightInfoTableModel;
44
45 import libaltosJNI.*;
46
47 public class AltosConfigUI
48         extends JDialog
49         implements ActionListener, ItemListener, DocumentListener
50 {
51
52         Container       pane;
53         Box             box;
54         JLabel          product_label;
55         JLabel          version_label;
56         JLabel          serial_label;
57         JLabel          main_deploy_label;
58         JLabel          apogee_delay_label;
59         JLabel          radio_channel_label;
60         JLabel          callsign_label;
61
62         public boolean          dirty;
63
64         JFrame          owner;
65         JLabel          product_value;
66         JLabel          version_value;
67         JLabel          serial_value;
68         JComboBox       main_deploy_value;
69         JComboBox       apogee_delay_value;
70         JComboBox       radio_channel_value;
71         JTextField      callsign_value;
72
73         JButton         save;
74         JButton         reset;
75         JButton         close;
76
77         ActionListener  listener;
78
79         static String[] main_deploy_values = {
80                 "100", "150", "200", "250", "300", "350",
81                 "400", "450", "500"
82         };
83
84         static String[] apogee_delay_values = {
85                 "0", "1", "2", "3", "4", "5"
86         };
87
88         static String[] radio_channel_values = new String[10];
89                 {
90                         for (int i = 0; i <= 9; i++)
91                                 radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)",
92                                                                         i, 434.550 + i * 0.1);
93                 }
94
95         /* A window listener to catch closing events and tell the config code */
96         class ConfigListener extends WindowAdapter {
97                 AltosConfigUI   ui;
98
99                 public ConfigListener(AltosConfigUI this_ui) {
100                         ui = this_ui;
101                 }
102
103                 public void windowClosing(WindowEvent e) {
104                         ui.actionPerformed(new ActionEvent(e.getSource(),
105                                                            ActionEvent.ACTION_PERFORMED,
106                                                            "close"));
107                 }
108         }
109
110         /* Build the UI using a grid bag */
111         public AltosConfigUI(JFrame in_owner) {
112                 super (in_owner, "Configure TeleMetrum", false);
113
114                 owner = in_owner;
115                 GridBagConstraints c;
116
117                 Insets il = new Insets(4,4,4,4);
118                 Insets ir = new Insets(4,4,4,4);
119
120                 pane = getContentPane();
121                 pane.setLayout(new GridBagLayout());
122
123                 /* Product */
124                 c = new GridBagConstraints();
125                 c.gridx = 0; c.gridy = 0;
126                 c.gridwidth = 3;
127                 c.fill = GridBagConstraints.NONE;
128                 c.anchor = GridBagConstraints.LINE_START;
129                 c.insets = il;
130                 product_label = new JLabel("Product:");
131                 pane.add(product_label, c);
132
133                 c = new GridBagConstraints();
134                 c.gridx = 3; c.gridy = 0;
135                 c.gridwidth = 3;
136                 c.fill = GridBagConstraints.HORIZONTAL;
137                 c.weightx = 1;
138                 c.anchor = GridBagConstraints.LINE_START;
139                 c.insets = ir;
140                 product_value = new JLabel("");
141                 pane.add(product_value, c);
142
143                 /* Version */
144                 c = new GridBagConstraints();
145                 c.gridx = 0; c.gridy = 1;
146                 c.gridwidth = 3;
147                 c.fill = GridBagConstraints.NONE;
148                 c.anchor = GridBagConstraints.LINE_START;
149                 c.insets = il;
150                 version_label = new JLabel("Software version:");
151                 pane.add(version_label, c);
152
153                 c = new GridBagConstraints();
154                 c.gridx = 3; c.gridy = 1;
155                 c.gridwidth = 3;
156                 c.fill = GridBagConstraints.HORIZONTAL;
157                 c.weightx = 1;
158                 c.anchor = GridBagConstraints.LINE_START;
159                 c.insets = ir;
160                 version_value = new JLabel("");
161                 pane.add(version_value, c);
162
163                 /* Serial */
164                 c = new GridBagConstraints();
165                 c.gridx = 0; c.gridy = 2;
166                 c.gridwidth = 3;
167                 c.fill = GridBagConstraints.NONE;
168                 c.anchor = GridBagConstraints.LINE_START;
169                 c.insets = il;
170                 serial_label = new JLabel("Serial:");
171                 pane.add(serial_label, c);
172
173                 c = new GridBagConstraints();
174                 c.gridx = 3; c.gridy = 2;
175                 c.gridwidth = 3;
176                 c.fill = GridBagConstraints.HORIZONTAL;
177                 c.weightx = 1;
178                 c.anchor = GridBagConstraints.LINE_START;
179                 c.insets = ir;
180                 serial_value = new JLabel("");
181                 pane.add(serial_value, c);
182
183                 /* Main deploy */
184                 c = new GridBagConstraints();
185                 c.gridx = 0; c.gridy = 3;
186                 c.gridwidth = 3;
187                 c.fill = GridBagConstraints.NONE;
188                 c.anchor = GridBagConstraints.LINE_START;
189                 c.insets = il;
190                 c.ipady = 3;
191                 main_deploy_label = new JLabel("Main Deploy Altitude(m):");
192                 pane.add(main_deploy_label, c);
193
194                 c = new GridBagConstraints();
195                 c.gridx = 3; c.gridy = 3;
196                 c.gridwidth = 3;
197                 c.fill = GridBagConstraints.HORIZONTAL;
198                 c.weightx = 1;
199                 c.anchor = GridBagConstraints.LINE_START;
200                 c.insets = ir;
201                 c.ipady = 5;
202                 main_deploy_value = new JComboBox(main_deploy_values);
203                 main_deploy_value.setEditable(true);
204                 main_deploy_value.addItemListener(this);
205                 pane.add(main_deploy_value, c);
206
207                 /* Apogee delay */
208                 c = new GridBagConstraints();
209                 c.gridx = 0; c.gridy = 4;
210                 c.gridwidth = 3;
211                 c.fill = GridBagConstraints.NONE;
212                 c.anchor = GridBagConstraints.LINE_START;
213                 c.insets = il;
214                 c.ipady = 5;
215                 apogee_delay_label = new JLabel("Apogee Delay(s):");
216                 pane.add(apogee_delay_label, c);
217
218                 c = new GridBagConstraints();
219                 c.gridx = 3; c.gridy = 4;
220                 c.gridwidth = 3;
221                 c.fill = GridBagConstraints.HORIZONTAL;
222                 c.weightx = 1;
223                 c.anchor = GridBagConstraints.LINE_START;
224                 c.insets = ir;
225                 c.ipady = 5;
226                 apogee_delay_value = new JComboBox(apogee_delay_values);
227                 apogee_delay_value.setEditable(true);
228                 apogee_delay_value.addItemListener(this);
229                 pane.add(apogee_delay_value, c);
230
231                 /* Radio channel */
232                 c = new GridBagConstraints();
233                 c.gridx = 0; c.gridy = 5;
234                 c.gridwidth = 3;
235                 c.fill = GridBagConstraints.NONE;
236                 c.anchor = GridBagConstraints.LINE_START;
237                 c.insets = il;
238                 c.ipady = 5;
239                 radio_channel_label = new JLabel("Radio Channel:");
240                 pane.add(radio_channel_label, c);
241
242                 c = new GridBagConstraints();
243                 c.gridx = 3; c.gridy = 5;
244                 c.gridwidth = 3;
245                 c.fill = GridBagConstraints.HORIZONTAL;
246                 c.weightx = 1;
247                 c.anchor = GridBagConstraints.LINE_START;
248                 c.insets = ir;
249                 c.ipady = 5;
250                 radio_channel_value = new JComboBox(radio_channel_values);
251                 radio_channel_value.setEditable(false);
252                 radio_channel_value.addItemListener(this);
253                 pane.add(radio_channel_value, c);
254
255                 /* Callsign */
256                 c = new GridBagConstraints();
257                 c.gridx = 0; c.gridy = 6;
258                 c.gridwidth = 3;
259                 c.fill = GridBagConstraints.NONE;
260                 c.anchor = GridBagConstraints.LINE_START;
261                 c.insets = il;
262                 c.ipady = 5;
263                 callsign_label = new JLabel("Callsign:");
264                 pane.add(callsign_label, c);
265
266                 c = new GridBagConstraints();
267                 c.gridx = 3; c.gridy = 6;
268                 c.gridwidth = 3;
269                 c.fill = GridBagConstraints.HORIZONTAL;
270                 c.weightx = 1;
271                 c.anchor = GridBagConstraints.LINE_START;
272                 c.insets = ir;
273                 c.ipady = 5;
274                 callsign_value = new JTextField("N0CALL");
275                 callsign_value.getDocument().addDocumentListener(this);
276                 pane.add(callsign_value, c);
277
278                 /* Buttons */
279                 c = new GridBagConstraints();
280                 c.gridx = 0; c.gridy = 7;
281                 c.gridwidth = 2;
282                 c.fill = GridBagConstraints.NONE;
283                 c.anchor = GridBagConstraints.LINE_START;
284                 c.insets = il;
285                 save = new JButton("Save");
286                 pane.add(save, c);
287                 save.addActionListener(this);
288                 save.setActionCommand("save");
289
290                 c = new GridBagConstraints();
291                 c.gridx = 2; c.gridy = 7;
292                 c.gridwidth = 2;
293                 c.fill = GridBagConstraints.NONE;
294                 c.anchor = GridBagConstraints.CENTER;
295                 c.insets = il;
296                 reset = new JButton("Reset");
297                 pane.add(reset, c);
298                 reset.addActionListener(this);
299                 reset.setActionCommand("reset");
300
301                 c = new GridBagConstraints();
302                 c.gridx = 4; c.gridy = 7;
303                 c.gridwidth = 2;
304                 c.fill = GridBagConstraints.NONE;
305                 c.anchor = GridBagConstraints.LINE_END;
306                 c.insets = il;
307                 close = new JButton("Close");
308                 pane.add(close, c);
309                 close.addActionListener(this);
310                 close.setActionCommand("close");
311
312                 addWindowListener(new ConfigListener(this));
313         }
314
315         /* Once the initial values are set, the config code will show the dialog */
316         public void make_visible() {
317                 pack();
318                 setLocationRelativeTo(owner);
319                 setVisible(true);
320         }
321
322         /* If any values have been changed, confirm before closing */
323         public boolean check_dirty() {
324                 if (dirty) {
325                         Object[] options = { "Close anyway", "Keep editing" };
326                         int i;
327                         i = JOptionPane.showOptionDialog(this,
328                                                          "Configuration modified, close anyway?",
329                                                          "Configuration Modified",
330                                                          JOptionPane.DEFAULT_OPTION,
331                                                          JOptionPane.WARNING_MESSAGE,
332                                                          null, options, options[1]);
333                         if (i != 0)
334                                 return false;
335                 }
336                 return true;
337         }
338
339         /* Listen for events from our buttons */
340         public void actionPerformed(ActionEvent e) {
341                 String  cmd = e.getActionCommand();
342
343                 if (cmd.equals("close"))
344                         if (!check_dirty())
345                                 return;
346                 listener.actionPerformed(e);
347                 if (cmd.equals("close")) {
348                         setVisible(false);
349                         dispose();
350                 }
351                 dirty = false;
352         }
353
354         /* ItemListener interface method */
355         public void itemStateChanged(ItemEvent e) {
356                 dirty = true;
357         }
358
359         /* DocumentListener interface methods */
360         public void changedUpdate(DocumentEvent e) {
361                 dirty = true;
362         }
363
364         public void insertUpdate(DocumentEvent e) {
365                 dirty = true;
366         }
367
368         public void removeUpdate(DocumentEvent e) {
369                 dirty = true;
370         }
371
372         /* Let the config code hook on a listener */
373         public void addActionListener(ActionListener l) {
374                 listener = l;
375         }
376
377         /* set and get all of the dialog values */
378         public void set_product(String product) {
379                 product_value.setText(product);
380         }
381
382         public void set_version(String version) {
383                 version_value.setText(version);
384         }
385
386         public void set_serial(int serial) {
387                 serial_value.setText(String.format("%d", serial));
388         }
389
390         public void set_main_deploy(int new_main_deploy) {
391                 main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
392         }
393
394         public int main_deploy() {
395                 return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
396         }
397
398         public void set_apogee_delay(int new_apogee_delay) {
399                 apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
400         }
401
402         public int apogee_delay() {
403                 return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
404         }
405
406         public void set_radio_channel(int new_radio_channel) {
407                 radio_channel_value.setSelectedIndex(new_radio_channel);
408         }
409
410         public int radio_channel() {
411                 return radio_channel_value.getSelectedIndex();
412         }
413
414         public void set_callsign(String new_callsign) {
415                 callsign_value.setText(new_callsign);
416         }
417
418         public String callsign() {
419                 return callsign_value.getText();
420         }
421
422         public void set_clean() {
423                 dirty = false;
424         }
425
426  }