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