Document the need for ~/altusmetrumllc/google-maps-api-key
[fw/altos] / altosui / AltosBTManage.java
index 8e9e0f73f37d242a91f9575d3f1f1898527124b9..e6e7efd4bf9743bc8c593f2487774d7e73c37b72 100644 (file)
@@ -20,28 +20,37 @@ package altosui;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
+import javax.swing.plaf.basic.*;
 import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
 import java.util.concurrent.*;
+import org.altusmetrum.altosuilib_2.*;
 
-import libaltosJNI.*;
-
-public class AltosBTManage extends JDialog implements ActionListener {
-       String  product;
+public class AltosBTManage extends AltosUIDialog implements ActionListener, Iterable<AltosBTDevice> {
        LinkedBlockingQueue<AltosBTDevice> found_devices;
-       JFrame frame;
+       Frame frame;
+       LinkedList<ActionListener> listeners;
+       AltosBTKnown    bt_known;
 
-       class DeviceList extends JList implements Iterable<AltosBTDevice> {
-               LinkedList<AltosBTDevice> devices;
-               DefaultListModel        list_model;
+       class DeviceList extends JList<AltosBTDevice> implements Iterable<AltosBTDevice> {
+               LinkedList<AltosBTDevice>       devices;
+               DefaultListModel<AltosBTDevice> list_model;
 
                public void add (AltosBTDevice device) {
-                       devices.add(device);
-                       list_model.addElement(device);
+                       if (!devices.contains(device)) {
+                               devices.add(device);
+                               list_model.addElement(device);
+                       }
+               }
+
+               public void remove (AltosBTDevice device) {
+                       if (devices.contains(device)) {
+                               devices.remove(device);
+                               list_model.removeElement(device);
+                       }
+               }
+
+               public boolean contains(AltosBTDevice device) {
+                       return devices.contains(device);
                }
 
                //Subclass JList to workaround bug 4832765, which can cause the
@@ -76,9 +85,13 @@ public class AltosBTManage extends JDialog implements ActionListener {
                        return devices.iterator();
                }
 
+               public java.util.List<AltosBTDevice> selected_list() throws InterruptedException {
+                       return getSelectedValuesList();
+               }
+
                public DeviceList() {
                        devices = new LinkedList<AltosBTDevice>();
-                       list_model = new DefaultListModel();
+                       list_model = new DefaultListModel<AltosBTDevice>();
                        setModel(list_model);
                        setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
                        setLayoutOrientation(JList.HORIZONTAL_WRAP);
@@ -88,101 +101,253 @@ public class AltosBTManage extends JDialog implements ActionListener {
 
        DeviceList      visible_devices;
 
-       DeviceList      selected_devices;
+       DeviceList      known_devices;
+       Thread          bt_thread;
+
+       public Iterator<AltosBTDevice> iterator() {
+               return known_devices.iterator();
+       }
+
+       public void commit() {
+               bt_known.set(this);
+       }
+
+       public void add_known() {
+               try {
+                       for (AltosBTDevice device : visible_devices.selected_list()) {
+                               known_devices.add(device);
+                               visible_devices.remove(device);
+                       }
+               } catch (InterruptedException ie) {
+               }
+       }
+
+       public void remove_known() {
+               try {
+                       for (AltosBTDevice device : known_devices.selected_list()) {
+                               known_devices.remove(device);
+                               visible_devices.add(device);
+                       }
+               } catch (InterruptedException ie) {
+               }
+       }
+
+       public void addActionListener(ActionListener l) {
+               listeners.add(l);
+       }
+
+       private void forwardAction(ActionEvent e) {
+               for (ActionListener l : listeners)
+                       l.actionPerformed(e);
+       }
 
        public void actionPerformed(ActionEvent e) {
+               String  command = e.getActionCommand();
+               if ("ok".equals(command)) {
+                       bt_thread.interrupt();
+                       commit();
+                       setVisible(false);
+                       forwardAction(e);
+               } else if ("cancel".equals(command)) {
+                       bt_thread.interrupt();
+                       setVisible(false);
+                       forwardAction(e);
+               } else if ("select".equals(command)) {
+                       add_known();
+               } else if ("deselect".equals(command)) {
+                       remove_known();
+               }
        }
 
        public void got_visible_device() {
                while (!found_devices.isEmpty()) {
                        AltosBTDevice   device = found_devices.remove();
-                       visible_devices.add(device);
+                       if (!known_devices.contains(device))
+                               visible_devices.add(device);
                }
        }
 
        class BTGetVisibleDevices implements Runnable {
                public void run () {
+                       for (;;)
+                               for (int time = 1; time <= 8; time <<= 1) {
+                                       AltosBTDeviceIterator   i = new AltosBTDeviceIterator(time);
+                                       AltosBTDevice           device;
 
-                       try {
-                               AltosBTDeviceIterator   i = new AltosBTDeviceIterator(product);
-                               AltosBTDevice           device;
-
-                               while ((device = i.next()) != null) {
-                                       Runnable r;
+                                       if (Thread.interrupted())
+                                               return;
+                                       try {
+                                               while ((device = i.next()) != null) {
+                                                       Runnable r;
 
-                                       found_devices.add(device);
-                                       r = new Runnable() {
-                                                       public void run() {
-                                                               got_visible_device();
-                                                       }
-                                               };
-                                       SwingUtilities.invokeLater(r);
+                                                       if (Thread.interrupted())
+                                                               return;
+                                                       found_devices.add(device);
+                                                       r = new Runnable() {
+                                                                       public void run() {
+                                                                               got_visible_device();
+                                                                       }
+                                                               };
+                                                       SwingUtilities.invokeLater(r);
+                                               }
+                                       } catch (Exception e) {
+                                               System.out.printf("uh-oh, exception %s\n", e.toString());
+                                       }
                                }
-                       } catch (Exception e) {
-                               System.out.printf("uh-oh, exception %s\n", e.toString());
-                       }
                }
        }
 
-       public AltosBTManage(String product, JFrame in_frame) {
+       public static void show(Component frameComp, AltosBTKnown known) {
+               Frame   frame = JOptionPane.getFrameForComponent(frameComp);
+               AltosBTManage   dialog;
+
+               dialog = new AltosBTManage(frame, known);
+               dialog.setVisible(true);
+       }
+
+       public AltosBTManage(Frame in_frame, AltosBTKnown in_known) {
+               super(in_frame, "Manage Bluetooth Devices", true);
+
                frame = in_frame;
+               bt_known = in_known;
                BTGetVisibleDevices     get_visible_devices = new BTGetVisibleDevices();
-               Thread t = new Thread(get_visible_devices);
-               t.start();
+               bt_thread = new Thread(get_visible_devices);
+               bt_thread.start();
+
+               listeners = new LinkedList<ActionListener>();
 
                found_devices = new LinkedBlockingQueue<AltosBTDevice>();
 
-               JButton cancelButton = new JButton("Cancel");
-               cancelButton.addActionListener(this);
+               Container pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               GridBagConstraints c = new GridBagConstraints();
+               c.insets = new Insets(4,4,4,4);
+
+               /*
+                * Known devices label and list
+                */
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 0;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(new JLabel("Known Devices"), c);
 
-               final JButton selectButton = new JButton("Select");
-               selectButton.setActionCommand("select");
-               selectButton.addActionListener(this);
-               getRootPane().setDefaultButton(selectButton);
+               known_devices = new DeviceList();
+               for (AltosBTDevice device : bt_known)
+                       known_devices.add(device);
 
-               selected_devices = new DeviceList();
-               JScrollPane selected_list_scroller = new JScrollPane(selected_devices);
-               selected_list_scroller.setPreferredSize(new Dimension(400, 80));
-               selected_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
+               JScrollPane known_list_scroller = new JScrollPane(known_devices);
+               known_list_scroller.setPreferredSize(new Dimension(400, 80));
+               known_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 1;
+               c.gridwidth = 1;
+               c.gridheight = 2;
+               c.weightx = 1;
+               c.weighty = 1;
+               pane.add(known_list_scroller, c);
+
+               /*
+                * Visible devices label and list
+                */
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 2;
+               c.gridy = 0;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+
+               pane.add(new JLabel("Visible Devices"), c);
 
                visible_devices = new DeviceList();
                JScrollPane visible_list_scroller = new JScrollPane(visible_devices);
                visible_list_scroller.setPreferredSize(new Dimension(400, 80));
                visible_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 2;
+               c.gridy = 1;
+               c.gridheight = 2;
+               c.gridwidth = 1;
+               c.weightx = 1;
+               c.weighty = 1;
+               pane.add(visible_list_scroller, c);
+
+               /*
+                * Arrows between the two lists
+                */
+               BasicArrowButton select_arrow = new BasicArrowButton(SwingConstants.WEST);
+               select_arrow.setActionCommand("select");
+               select_arrow.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.SOUTH;
+               c.gridx = 1;
+               c.gridy = 1;
+               c.gridheight = 1;
+               c.gridwidth = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(select_arrow, c);
+
+               BasicArrowButton deselect_arrow = new BasicArrowButton(SwingConstants.EAST);
+               deselect_arrow.setActionCommand("deselect");
+               deselect_arrow.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.NORTH;
+               c.gridx = 1;
+               c.gridy = 2;
+               c.gridheight = 1;
+               c.gridwidth = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(deselect_arrow, c);
+
+               JButton cancel_button = new JButton("Cancel");
+               cancel_button.setActionCommand("cancel");
+               cancel_button.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0;
+               c.gridy = 3;
+               c.gridheight = 1;
+               c.gridwidth = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(cancel_button, c);
+
+               JButton ok_button = new JButton("OK");
+               ok_button.setActionCommand("ok");
+               ok_button.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 2;
+               c.gridy = 3;
+               c.gridheight = 1;
+               c.gridwidth = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(ok_button, c);
+
+               getRootPane().setDefaultButton(ok_button);
 
-               //Create a container so that we can add a title around
-               //the scroll pane.  Can't add a title directly to the
-               //scroll pane because its background would be white.
-               //Lay out the label and scroll pane from top to bottom.
-               JPanel listPane = new JPanel();
-               listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
-
-               JLabel label = new JLabel("Select Device");
-               label.setLabelFor(selected_devices);
-               listPane.add(label);
-               listPane.add(Box.createRigidArea(new Dimension(0,5)));
-               listPane.add(selected_list_scroller);
-               listPane.add(visible_list_scroller);
-               listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
-
-               //Lay out the buttons from left to right.
-               JPanel buttonPane = new JPanel();
-               buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
-               buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
-               buttonPane.add(Box.createHorizontalGlue());
-               buttonPane.add(cancelButton);
-               buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
-               buttonPane.add(selectButton);
-
-               //Put everything together, using the content pane's BorderLayout.
-               Container contentPane = getContentPane();
-               contentPane.add(listPane, BorderLayout.CENTER);
-               contentPane.add(buttonPane, BorderLayout.PAGE_END);
-
-               //Initialize values.
-//             list.setSelectedValue(initial, true);
                pack();
                setLocationRelativeTo(frame);
-               setVisible(true);
+               setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+               addWindowListener(new WindowAdapter() {
+                       @Override
+                       public void windowClosing(WindowEvent e) {
+                               bt_thread.interrupt();
+                               setVisible(false);
+                       }
+               });
        }
 }