altos/test: Adjust CRC error rate after FEC fix
[fw/altos] / altosui / AltosConfigPyroUI.java
1 /*
2  * Copyright © 2012 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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 package altosui;
20
21 import java.text.*;
22 import java.awt.*;
23 import java.awt.event.*;
24 import javax.swing.*;
25 import javax.swing.event.*;
26 import org.altusmetrum.altoslib_14.*;
27 import org.altusmetrum.altosuilib_14.*;
28
29 public class AltosConfigPyroUI
30         extends AltosUIDialog
31         implements ItemListener, DocumentListener, AltosUnitsListener, ActionListener
32 {
33         AltosConfigFCUI owner;
34         Container       pane;
35
36         static Insets il = new Insets(4,4,4,4);
37         static Insets ir = new Insets(4,4,4,4);
38
39         static String[] state_names;
40
41         static void make_state_names() {
42                 if (state_names == null) {
43
44                         state_names = new String[AltosLib.ao_flight_landed - AltosLib.ao_flight_boost + 1];
45                         for (int state = AltosLib.ao_flight_boost; state <= AltosLib.ao_flight_landed; state++)
46                                 state_names[state - AltosLib.ao_flight_boost] = AltosLib.state_name_capital(state);
47                 }
48         }
49
50         class PyroItem implements ItemListener, DocumentListener, AltosUnitsListener
51         {
52                 public int              flag;
53                 public JCheckBox        enable;
54                 public JTextField       value;
55                 public JComboBox<String>        combo;
56                 AltosConfigPyroUI       ui;
57                 boolean                 setting;
58
59                 public void set_enable(boolean enable) {
60                         if (value != null)
61                                 value.setEnabled(enable);
62                         if (combo != null)
63                                 combo.setEnabled(enable);
64                 }
65
66                 public void itemStateChanged(ItemEvent e) {
67                         set_enable(enable.isSelected());
68                         if (!setting)
69                                 ui.set_dirty();
70                 }
71
72                 public void changedUpdate(DocumentEvent e) {
73                         if (!setting)
74                                 ui.set_dirty();
75                 }
76
77                 public void insertUpdate(DocumentEvent e) {
78                         if (!setting)
79                                 ui.set_dirty();
80                 }
81
82                 public void removeUpdate(DocumentEvent e) {
83                         if (!setting)
84                                 ui.set_dirty();
85                 }
86
87                 public void units_changed(boolean imperial_units) {
88                         AltosUnits units = AltosPyro.pyro_to_units(flag);
89
90                         if (units != null) {
91                                 try {
92                                         double v = units.parse_locale(value.getText(), !imperial_units);
93                                         set(enabled(), v);
94                                 } catch (ParseException pe) {
95                                         set(enabled(), 0.0);
96                                 }
97                         }
98                 }
99
100                 public void set(boolean new_enable, double new_value) {
101                         setting = true;
102                         enable.setSelected(new_enable);
103                         set_enable(new_enable);
104                         if (value != null) {
105                                 double  scale = AltosPyro.pyro_to_scale(flag);
106                                 double  unit_value = new_value;
107                                 AltosUnits units = AltosPyro.pyro_to_units(flag);
108                                 if (units != null)
109                                         unit_value = units.parse_value(new_value);
110                                 String  format;
111                                 if (scale >= 100)
112                                         format = "%6.2f";
113                                 else if (scale >= 10)
114                                         format = "%6.1f";
115                                 else
116                                         format = "%6.0f";
117                                 value.setText(String.format(format, unit_value));
118                         }
119                         if (combo != null)
120                                 if (new_value >= AltosLib.ao_flight_boost && new_value <= AltosLib.ao_flight_landed)
121                                         combo.setSelectedIndex((int) new_value - AltosLib.ao_flight_boost);
122                         setting = false;
123                 }
124
125                 public boolean enabled() {
126                         return enable.isSelected();
127                 }
128
129                 public double value() throws AltosConfigDataException {
130                         if (value != null) {
131                                 AltosUnits units = AltosPyro.pyro_to_units(flag);
132                                 try {
133                                         if (units != null)
134                                                 return units.parse_locale(value.getText());
135                                         return AltosParse.parse_double_locale(value.getText());
136                                 } catch (ParseException e) {
137                                         throw new AltosConfigDataException("\"%s\": %s\n", value.getText(), e.getMessage());
138                                 }
139                         }
140                         if (combo != null)
141                                 return combo.getSelectedIndex() + AltosLib.ao_flight_boost;
142                         return 0;
143                 }
144
145                 public PyroItem(AltosConfigPyroUI in_ui, int in_flag, int x, int y) {
146
147                         ui = in_ui;
148                         flag = in_flag;
149
150                         GridBagConstraints      c;
151                         c = new GridBagConstraints();
152                         c.gridx = x; c.gridy = y;
153                         c.gridwidth = 1;
154                         c.fill = GridBagConstraints.NONE;
155                         c.anchor = GridBagConstraints.LINE_START;
156                         c.insets = il;
157                         enable = new JCheckBox();
158                         enable.addItemListener(this);
159                         pane.add(enable, c);
160
161                         if ((flag & AltosPyro.pyro_no_value) == 0) {
162                                 c = new GridBagConstraints();
163                                 c.gridx = x+1; c.gridy = y;
164                                 c.gridwidth = 1;
165                                 c.fill = GridBagConstraints.NONE;
166                                 c.anchor = GridBagConstraints.LINE_START;
167                                 c.insets = il;
168                                 if ((flag & AltosPyro.pyro_state_value) != 0) {
169                                         make_state_names();
170                                         combo = new JComboBox<String>(state_names);
171                                         combo.addItemListener(this);
172                                         pane.add(combo, c);
173                                 } else {
174                                         value = new JTextField(10);
175                                         value.getDocument().addDocumentListener(this);
176                                         pane.add(value, c);
177                                 }
178                         }
179                 }
180         }
181
182         class PyroColumn implements AltosUnitsListener {
183                 public PyroItem[]       items;
184                 public JLabel           label;
185                 int                     channel;
186
187                 public void set(AltosPyro pyro) {
188                         int row = 0;
189                         if ((pyro.flags & AltosPyro.pyro_deprecate) != 0) {
190                                 JOptionPane.showMessageDialog(owner,
191                                                               String.format("Pyro settings “Ascending” and “Descending” are deprecated.\n" +
192                                                                             "Clearing %s configuration.", AltosLib.igniter_name(pyro.channel)),
193                                                               "Deprecated Pyro Settings",
194                                                               JOptionPane.ERROR_MESSAGE);
195                                 pyro.flags = 0;
196                                 owner.set_dirty();
197                         }
198                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
199                                 if ((AltosPyro.pyro_all_useful & flag) != 0) {
200                                         items[row].set((pyro.flags & flag) != 0,
201                                                        pyro.get_value(flag));
202                                         row++;
203                                 }
204                         }
205                 }
206
207                 public AltosPyro get() throws AltosConfigDataException {
208                         AltosPyro       p = new AltosPyro(channel);
209
210                         int row = 0;
211                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
212                                 if ((AltosPyro.pyro_all_useful & flag) != 0) {
213                                         if (items[row].enabled()) {
214                                                 try {
215                                                 p.flags |= flag;
216                                                 p.set_value(flag, items[row].value());
217                                                 } catch (AltosConfigDataException ae) {
218                                                         throw new AltosConfigDataException("%s, %s",
219                                                                                            AltosPyro.pyro_to_name(flag),
220                                                                                            ae.getMessage());
221                                                 }
222                                         }
223                                         row++;
224                                 }
225                         }
226                         return p;
227                 }
228
229                 public void units_changed(boolean imperial_units) {
230                         int row = 0;
231                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
232                                 if ((AltosPyro.pyro_all_useful & flag) != 0) {
233                                         items[row].units_changed(imperial_units);
234                                         row++;
235                                 }
236                         }
237                 }
238
239                 public PyroColumn(AltosConfigPyroUI ui, int x, int y, int in_channel) {
240
241                         channel = in_channel;
242
243                         int     nrow = 0;
244                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
245                                 if ((flag & AltosPyro.pyro_all_useful) != 0)
246                                         nrow++;
247
248                         items = new PyroItem[nrow];
249                         int row = 0;
250
251                         GridBagConstraints      c;
252                         c = new GridBagConstraints();
253                         c.gridx = x; c.gridy = y;
254                         c.gridwidth = 2;
255                         c.fill = GridBagConstraints.NONE;
256                         c.anchor = GridBagConstraints.CENTER;
257                         c.insets = il;
258                         label = new JLabel(String.format("Pyro Channel %c", 'A' + channel));
259                         pane.add(label, c);
260                         y++;
261
262                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
263                                 if ((flag & AltosPyro.pyro_all_useful) != 0) {
264                                         items[row] = new PyroItem(ui, flag, x, y + row);
265                                         row++;
266                                 }
267                 }
268         }
269
270         PyroColumn[]    columns;
271         JLabel[]        labels;
272
273         public void set_pyros(AltosPyro[] pyros) {
274                 for (int i = 0; i < pyros.length; i++) {
275                         if (pyros[i].channel < columns.length)
276                                 columns[pyros[i].channel].set(pyros[i]);
277                 }
278         }
279
280         public AltosPyro[] get_pyros() throws AltosConfigDataException {
281                 AltosPyro[]     pyros = new AltosPyro[columns.length];
282                 for (int c = 0; c < columns.length; c++) {
283                         try {
284                                 pyros[c] = columns[c].get();
285                         } catch (AltosConfigDataException ae) {
286                                 throw new AltosConfigDataException ("Channel %c, %s", c + 'A', ae.getMessage());
287                         }
288                 }
289                 return pyros;
290         }
291
292         JLabel                  pyro_firing_time_label;
293         JComboBox<String>       pyro_firing_time_value;
294
295         static String[]         pyro_firing_time_values = {
296                 "0.050", "0.100", "0.250", "0.500", "1.0", "2.0"
297         };
298
299         boolean initializing;
300
301         public void set_pyro_firing_time(double new_pyro_firing_time) {
302                 initializing = true;
303                 pyro_firing_time_value.setSelectedItem(Double.toString(new_pyro_firing_time));
304                 pyro_firing_time_value.setEnabled(new_pyro_firing_time >= 0);
305                 initializing = false;
306         }
307
308         public double get_pyro_firing_time() throws AltosConfigDataException {
309                 String  v = pyro_firing_time_value.getSelectedItem().toString();
310
311                 try {
312                         return AltosParse.parse_double_locale(v);
313                 } catch (ParseException e) {
314                         throw new AltosConfigDataException("Invalid pyro firing time \"%s\"", v);
315                 }
316         }
317
318         public void set_dirty() {
319                 if (!initializing)
320                         owner.set_dirty();
321         }
322
323         public void itemStateChanged(ItemEvent e) {
324                 if (!initializing)
325                         owner.set_dirty();
326         }
327
328         public void changedUpdate(DocumentEvent e) {
329                 if (!initializing)
330                         owner.set_dirty();
331         }
332
333         public void insertUpdate(DocumentEvent e) {
334                 if (!initializing)
335                         owner.set_dirty();
336         }
337
338         public void removeUpdate(DocumentEvent e) {
339                 if (!initializing)
340                         owner.set_dirty();
341         }
342
343         public void units_changed(boolean imperial_units) {
344                 for (int c = 0; c < columns.length; c++)
345                         columns[c].units_changed(imperial_units);
346                 int r = 0;
347                 for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
348                         if ((flag & AltosPyro.pyro_all_useful) != 0) {
349                                 String n = AltosPyro.pyro_to_name(flag);
350                                 if (n != null) {
351                                         labels[r].setText(n);
352                                         r++;
353                                 }
354                         }
355                 }
356         }
357
358         /* A window listener to catch closing events and tell the config code */
359         class ConfigListener extends WindowAdapter {
360                 AltosConfigPyroUI       ui;
361                 AltosConfigFCUI         owner;
362
363                 public ConfigListener(AltosConfigPyroUI this_ui, AltosConfigFCUI this_owner) {
364                         ui = this_ui;
365                         owner = this_owner;
366                 }
367
368                 public void windowClosing(WindowEvent e) {
369                         ui.setVisible(false);
370                 }
371         }
372
373         /* Listen for events from our buttons */
374         public void actionPerformed(ActionEvent e) {
375                 String  cmd = e.getActionCommand();
376
377                 if (cmd.equals("Close"))
378                         setVisible(false);
379         }
380
381         public AltosConfigPyroUI(AltosConfigFCUI in_owner, AltosPyro[] pyros, double pyro_firing_time) {
382
383                 super(in_owner, "Configure Pyro Channels", false);
384
385                 owner = in_owner;
386
387                 GridBagConstraints      c;
388
389                 pane = getScrollablePane();
390                 pane.setLayout(new GridBagLayout());
391
392                 int     nrow = 0;
393                 for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
394                         if ((flag & AltosPyro.pyro_all_useful) != 0)
395                                 nrow++;
396
397                 labels = new JLabel[nrow];
398
399                 int     row = 1;
400
401                 for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
402                         String  n;
403
404                         if ((flag & AltosPyro.pyro_all_useful) != 0) {
405                                 n = AltosPyro.pyro_to_name(flag);
406                                 if (n != null) {
407                                         c = new GridBagConstraints();
408                                         c.gridx = 0; c.gridy = row;
409                                         c.gridwidth = 1;
410                                         c.fill = GridBagConstraints.NONE;
411                                         c.anchor = GridBagConstraints.LINE_START;
412                                         c.insets = il;
413                                         JLabel label = new JLabel(n);
414                                         pane.add(label, c);
415                                         labels[row-1] = label;
416                                         row++;
417                                 }
418                         }
419                 }
420
421                 columns = new PyroColumn[pyros.length];
422
423                 for (int i = 0; i < pyros.length; i++) {
424                         columns[i] = new PyroColumn(this, i*2 + 1, 0, i);
425                         columns[i].set(pyros[i]);
426                 }
427
428                 /* Pyro firing time */
429                 c = new GridBagConstraints();
430                 c.gridx = 0; c.gridy = row;
431                 c.gridwidth = 2;
432                 c.fill = GridBagConstraints.NONE;
433                 c.anchor = GridBagConstraints.LINE_START;
434                 c.insets = il;
435                 c.ipady = 5;
436                 pyro_firing_time_label = new JLabel("Pyro Firing Time(s):");
437                 pane.add(pyro_firing_time_label, c);
438
439                 c = new GridBagConstraints();
440                 c.gridx = 2; c.gridy = row;
441                 c.gridwidth = 7;
442                 c.fill = GridBagConstraints.HORIZONTAL;
443                 c.weightx = 1;
444                 c.anchor = GridBagConstraints.LINE_START;
445                 c.insets = ir;
446                 c.ipady = 5;
447                 pyro_firing_time_value = new JComboBox<String>(pyro_firing_time_values);
448                 pyro_firing_time_value.setEditable(true);
449                 pyro_firing_time_value.addItemListener(this);
450                 set_pyro_firing_time(pyro_firing_time);
451                 pane.add(pyro_firing_time_value, c);
452                 pyro_firing_time_value.setToolTipText("Length of extra pyro channel firing pulse");
453
454                 c = new GridBagConstraints();
455                 c.gridx = pyros.length*2-1;
456                 c.fill = GridBagConstraints.HORIZONTAL;
457                 c.gridwidth = 2;
458                 c.gridy = 1000;
459                 JButton close = new JButton("Close");
460                 pane.add(close, c);
461                 close.addActionListener(this);
462                 close.setActionCommand("Close");
463
464                 addWindowListener(new ConfigListener(this, owner));
465                 AltosPreferences.register_units_listener(this);
466         }
467
468         public void dispose() {
469                 AltosPreferences.unregister_units_listener(this);
470                 super.dispose();
471         }
472
473         public void make_visible() {
474                 pack();
475                 setVisible(true);
476         }
477 }