Update java library versions
[fw/altos] / altosui / AltosIgniteUI.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 java.io.*;
24 import java.text.*;
25 import java.util.*;
26 import java.util.concurrent.*;
27 import org.altusmetrum.altoslib_9.*;
28 import org.altusmetrum.altosuilib_9.*;
29
30 public class AltosIgniteUI
31         extends AltosUIDialog
32         implements ActionListener
33 {
34         AltosDevice     device;
35         JFrame          owner;
36         JLabel          label;
37         JToggleButton   arm;
38         JButton         fire;
39         javax.swing.Timer       timer;
40         JButton         close;
41         ButtonGroup     group;
42         Boolean         opened;
43
44         int             npyro;
45
46         final static int        timeout = 1 * 1000;
47
48         int             time_remaining;
49         boolean         timer_running;
50
51         LinkedBlockingQueue<String>     command_queue;
52
53         class Igniter {
54                 JRadioButton    button;
55                 JLabel          status_label;
56                 String          name;
57                 int             status;
58
59                 void set_status (int status) {
60                         this.status = status;
61                         status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(status)));
62                 }
63
64                 Igniter(AltosIgniteUI ui, String label, String name, int y) {
65                         Container               pane = getContentPane();
66                         GridBagConstraints      c = new GridBagConstraints();
67                         Insets                  i = new Insets(4,4,4,4);
68
69                         this.name = name;
70                         this.status = AltosIgnite.Unknown;
71
72                         c.gridx = 0;
73                         c.gridy = y;
74                         c.gridwidth = 1;
75                         c.anchor = GridBagConstraints.WEST;
76                         button = new JRadioButton (label);
77                         pane.add(button, c);
78                         button.addActionListener(ui);
79                         button.setActionCommand(name);
80                         group.add(button);
81
82                         c.gridx = 1;
83                         c.gridy = y;
84                         c.gridwidth = 1;
85                         c.anchor = GridBagConstraints.WEST;
86                         status_label = new JLabel("plenty of text");
87                         pane.add(status_label, c);
88
89                         status = AltosIgnite.Unknown;
90                 }
91         }
92
93         Igniter igniters[];
94
95         void set_status(String _name, int _status) {
96
97                 final String name = _name;
98                 final int status = _status;
99                 Runnable r = new Runnable() {
100                                 public void run() {
101                                         for (int p = 0; p < igniters.length; p++)
102                                                 if (name.equals(igniters[p].name))
103                                                         igniters[p].set_status(status);
104                                 }
105                         };
106                 SwingUtilities.invokeLater(r);
107         }
108
109         class IgniteHandler implements Runnable {
110                 AltosIgnite     ignite;
111                 JFrame          owner;
112                 AltosLink       link;
113
114                 void send_exception(Exception e) {
115                         final Exception f_e = e;
116                         Runnable r = new Runnable() {
117                                         public void run() {
118                                                 ignite_exception(f_e);
119                                         }
120                                 };
121                         SwingUtilities.invokeLater(r);
122                 }
123
124                 public void run () {
125                         try {
126                                 ignite = new AltosIgnite(link,
127                                                          !device.matchProduct(Altos.product_altimeter));
128
129                         } catch (Exception e) {
130                                 send_exception(e);
131                                 return;
132                         }
133
134                         for (;;) {
135                                 Runnable        r;
136
137                                 try {
138                                         String          command = command_queue.take();
139                                         String          reply = null;
140
141                                         if (command.equals("get_status")) {
142                                                 HashMap<String,Integer> status_map = ignite.status();
143
144                                                 for (int p = 0; p < igniters.length; p++) {
145                                                         Integer i = status_map.get(igniters[p].name);
146                                                         if (i != null)
147                                                                 set_status(igniters[p].name, i);
148                                                 }
149                                                 reply = "status";
150                                         } else if (command.equals("get_npyro")) {
151                                                 reply = String.format("npyro %d", ignite.npyro());
152                                         } else if (command.equals("quit")) {
153                                                 ignite.close();
154                                                 break;
155                                         } else {
156                                                 ignite.fire(command);
157                                                 reply = "fired";
158                                         }
159                                         final String f_reply = reply;
160                                         r = new Runnable() {
161                                                         public void run() {
162                                                                 ignite_reply(f_reply);
163                                                         }
164                                                 };
165                                         SwingUtilities.invokeLater(r);
166                                 } catch (Exception e) {
167                                         send_exception(e);
168                                 }
169                         }
170                 }
171
172                 public IgniteHandler(JFrame in_owner, AltosLink in_link) {
173                         owner = in_owner;
174                         link = in_link;
175                 }
176         }
177
178         void ignite_exception(Exception e) {
179                 if (e instanceof FileNotFoundException) {
180                         JOptionPane.showMessageDialog(owner,
181                                                       ((FileNotFoundException) e).getMessage(),
182                                                       "Cannot open target device",
183                                                       JOptionPane.ERROR_MESSAGE);
184                 } else if (e instanceof AltosSerialInUseException) {
185                         JOptionPane.showMessageDialog(owner,
186                                                       String.format("Device \"%s\" already in use",
187                                                                     device.toShortString()),
188                                                       "Device in use",
189                                                       JOptionPane.ERROR_MESSAGE);
190                 } else if (e instanceof IOException) {
191                         IOException ee = (IOException) e;
192                         JOptionPane.showMessageDialog(owner,
193                                                       device.toShortString(),
194                                                       ee.getLocalizedMessage(),
195                                                       JOptionPane.ERROR_MESSAGE);
196                 } else {
197                         JOptionPane.showMessageDialog(owner,
198                                                       String.format("Connection to \"%s\" failed",
199                                                                     device.toShortString()),
200                                                       "Connection Failed",
201                                                       JOptionPane.ERROR_MESSAGE);
202                 }
203                 close();
204         }
205
206         void ignite_reply(String reply) {
207                 if (reply.equals("status")) {
208                         set_ignite_status();
209                 } else if (reply.equals("fired")) {
210                         fired();
211                 } else if (reply.startsWith("npyro")) {
212                         npyro = Integer.parseInt(reply.substring(6));
213                         make_ui();
214                 }
215         }
216
217         void set_arm_text() {
218                 if (arm.isSelected())
219                         arm.setText(String.format("%d", time_remaining));
220                 else
221                         arm.setText("Arm");
222         }
223
224         void start_timer() {
225                 time_remaining = 10;
226                 set_arm_text();
227                 timer_running = true;
228         }
229
230         void stop_timer() {
231                 time_remaining = 0;
232                 fire.setEnabled(false);
233                 timer_running = false;
234                 arm.setSelected(false);
235                 arm.setEnabled(false);
236                 set_arm_text();
237         }
238
239         void cancel () {
240                 group.clearSelection();
241                 fire.setEnabled(false);
242                 stop_timer();
243         }
244
245         void send_command(String command) {
246                 try {
247                         command_queue.put(command);
248                 } catch (Exception ex) {
249                         ignite_exception(ex);
250                 }
251         }
252
253         boolean getting_status = false;
254
255         boolean visible = false;
256
257         void set_ignite_status() {
258                 getting_status = false;
259                 if (!visible) {
260                         visible = true;
261                         setVisible(true);
262                 }
263         }
264
265         void poll_ignite_status() {
266                 if (!getting_status) {
267                         getting_status = true;
268                         send_command("get_status");
269                 }
270         }
271
272         boolean firing = false;
273
274         void start_fire(String which) {
275                 if (!firing) {
276                         firing = true;
277                         send_command(which);
278                 }
279         }
280
281         void fired() {
282                 firing = false;
283                 cancel();
284         }
285
286         void close() {
287                 if (opened) {
288                         send_command("quit");
289                 }
290                 if (timer != null)
291                         timer.stop();
292                 setVisible(false);
293                 dispose();
294         }
295
296         void tick_timer() {
297                 if (timer_running) {
298                         --time_remaining;
299                         if (time_remaining <= 0)
300                                 cancel();
301                         else
302                                 set_arm_text();
303                 }
304                 poll_ignite_status();
305         }
306
307         void fire() {
308                 if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
309                         String  igniter = "none";
310
311                         for (int p = 0; p < igniters.length; p++)
312                                 if (igniters[p].button.isSelected()) {
313                                         igniter = igniters[p].name;
314                                         break;
315                                 }
316                         send_command(igniter);
317                         cancel();
318                 }
319         }
320
321         public void actionPerformed(ActionEvent e) {
322                 String cmd = e.getActionCommand();
323
324                 for (int p = 0; p < igniters.length; p++)
325                         if (cmd.equals(igniters[p].name)) {
326                                 stop_timer();
327                                 arm.setEnabled(true);
328                                 break;
329                         }
330
331                 if (cmd.equals("arm")) {
332                         if (arm.isSelected()) {
333                                 fire.setEnabled(true);
334                                 start_timer();
335                         } else
336                                 cancel();
337                 }
338                 if (cmd.equals("fire"))
339                         fire();
340                 if (cmd.equals("tick"))
341                         tick_timer();
342                 if (cmd.equals("close"))
343                         close();
344         }
345
346         /* A window listener to catch closing events and tell the config code */
347         class ConfigListener extends WindowAdapter {
348                 AltosIgniteUI   ui;
349
350                 public ConfigListener(AltosIgniteUI this_ui) {
351                         ui = this_ui;
352                 }
353
354                 public void windowClosing(WindowEvent e) {
355                         ui.actionPerformed(new ActionEvent(e.getSource(),
356                                                            ActionEvent.ACTION_PERFORMED,
357                                                            "close"));
358                 }
359         }
360
361         private boolean open() {
362                 command_queue = new LinkedBlockingQueue<String>();
363
364                 opened = false;
365                 device = AltosDeviceUIDialog.show(owner, Altos.product_any);
366                 if (device != null) {
367                         try {
368                                 AltosSerial     serial = new AltosSerial(device);
369                                 serial.set_frame(owner);
370                                 IgniteHandler   handler = new IgniteHandler(owner, serial);
371                                 Thread          t = new Thread(handler);
372                                 t.start();
373                                 opened = true;
374                                 return true;
375                         } catch (Exception ex) {
376                                 ignite_exception(ex);
377                         }
378                 }
379                 return false;
380         }
381
382         private void make_ui() {
383                 group = new ButtonGroup();
384
385                 Container               pane = getContentPane();
386
387                 GridBagConstraints      c = new GridBagConstraints();
388                 Insets                  i = new Insets(4,4,4,4);
389
390                 timer = new javax.swing.Timer(timeout, this);
391                 timer.setActionCommand("tick");
392                 timer_running = false;
393                 timer.restart();
394
395                 pane.setLayout(new GridBagLayout());
396
397                 c.fill = GridBagConstraints.NONE;
398                 c.anchor = GridBagConstraints.CENTER;
399                 c.insets = i;
400                 c.weightx = 0;
401                 c.weighty = 0;
402
403                 int y = 0;
404
405                 c.gridx = 0;
406                 c.gridy = y;
407                 c.gridwidth = 2;
408                 c.anchor = GridBagConstraints.CENTER;
409                 label = new JLabel ("Fire Igniter");
410                 pane.add(label, c);
411
412                 y++;
413
414                 igniters = new Igniter[2 + npyro];
415
416                 igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++);
417                 igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++);
418
419                 for (int p = 0; p < npyro; p++) {
420                         String  name = String.format("%d", p);
421                         String  label = String.format("%c", 'A' + p);
422                         igniters[2+p] = new Igniter(this, label, name, y++);
423                 }
424
425                 c.gridx = 0;
426                 c.gridy = y;
427                 c.gridwidth = 1;
428                 c.anchor = GridBagConstraints.CENTER;
429                 arm = new JToggleButton ("Arm");
430                 pane.add(arm, c);
431                 arm.addActionListener(this);
432                 arm.setActionCommand("arm");
433                 arm.setEnabled(false);
434
435                 c.gridx = 1;
436                 c.gridy = y;
437                 c.gridwidth = 1;
438                 c.anchor = GridBagConstraints.CENTER;
439                 fire = new JButton ("Fire");
440                 fire.setEnabled(false);
441                 pane.add(fire, c);
442                 fire.addActionListener(this);
443                 fire.setActionCommand("fire");
444
445                 y++;
446
447                 c.gridx = 0;
448                 c.gridy = y;
449                 c.gridwidth = 2;
450                 c.anchor = GridBagConstraints.CENTER;
451                 close = new JButton ("Close");
452                 pane.add(close, c);
453                 close.addActionListener(this);
454                 close.setActionCommand("close");
455
456                 pack();
457                 setLocationRelativeTo(owner);
458
459                 addWindowListener(new ConfigListener(this));
460         }
461
462         public AltosIgniteUI(JFrame in_owner) {
463
464                 owner = in_owner;
465
466                 if (!open())
467                         return;
468
469                 send_command("get_npyro");
470         }
471 }