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