altosui: Add primitive bluetooth device manager UI.
[fw/altos] / altosui / AltosBTManage.java
1 /*
2  * Copyright © 2011 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 java.io.*;
26 import java.util.*;
27 import java.text.*;
28 import java.util.prefs.*;
29 import java.util.concurrent.*;
30
31 import libaltosJNI.*;
32
33 public class AltosBTManage extends JDialog implements ActionListener {
34         String  product;
35         LinkedBlockingQueue<AltosBTDevice> found_devices;
36         JFrame frame;
37
38         class DeviceList extends JList implements Iterable<AltosBTDevice> {
39                 LinkedList<AltosBTDevice> devices;
40                 DefaultListModel        list_model;
41
42                 public void add (AltosBTDevice device) {
43                         devices.add(device);
44                         list_model.addElement(device);
45                 }
46
47                 //Subclass JList to workaround bug 4832765, which can cause the
48                 //scroll pane to not let the user easily scroll up to the beginning
49                 //of the list.  An alternative would be to set the unitIncrement
50                 //of the JScrollBar to a fixed value. You wouldn't get the nice
51                 //aligned scrolling, but it should work.
52                 public int getScrollableUnitIncrement(Rectangle visibleRect,
53                                                       int orientation,
54                                                       int direction) {
55                         int row;
56                         if (orientation == SwingConstants.VERTICAL &&
57                             direction < 0 && (row = getFirstVisibleIndex()) != -1) {
58                                 Rectangle r = getCellBounds(row, row);
59                                 if ((r.y == visibleRect.y) && (row != 0))  {
60                                         Point loc = r.getLocation();
61                                         loc.y--;
62                                         int prevIndex = locationToIndex(loc);
63                                         Rectangle prevR = getCellBounds(prevIndex, prevIndex);
64
65                                         if (prevR == null || prevR.y >= r.y) {
66                                                 return 0;
67                                         }
68                                         return prevR.height;
69                                 }
70                         }
71                         return super.getScrollableUnitIncrement(
72                                 visibleRect, orientation, direction);
73                 }
74
75                 public Iterator<AltosBTDevice> iterator() {
76                         return devices.iterator();
77                 }
78
79                 public DeviceList() {
80                         devices = new LinkedList<AltosBTDevice>();
81                         list_model = new DefaultListModel();
82                         setModel(list_model);
83                         setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
84                         setLayoutOrientation(JList.HORIZONTAL_WRAP);
85                         setVisibleRowCount(-1);
86                 }
87         }
88
89         DeviceList      visible_devices;
90
91         DeviceList      selected_devices;
92
93         public void actionPerformed(ActionEvent e) {
94         }
95
96         public void got_visible_device() {
97                 while (!found_devices.isEmpty()) {
98                         AltosBTDevice   device = found_devices.remove();
99                         visible_devices.add(device);
100                 }
101         }
102
103         class BTGetVisibleDevices implements Runnable {
104                 public void run () {
105
106                         try {
107                                 AltosBTDeviceIterator   i = new AltosBTDeviceIterator(product);
108                                 AltosBTDevice           device;
109
110                                 while ((device = i.next()) != null) {
111                                         Runnable r;
112
113                                         found_devices.add(device);
114                                         r = new Runnable() {
115                                                         public void run() {
116                                                                 got_visible_device();
117                                                         }
118                                                 };
119                                         SwingUtilities.invokeLater(r);
120                                 }
121                         } catch (Exception e) {
122                                 System.out.printf("uh-oh, exception %s\n", e.toString());
123                         }
124                 }
125         }
126
127         public AltosBTManage(String product, JFrame in_frame) {
128                 frame = in_frame;
129                 BTGetVisibleDevices     get_visible_devices = new BTGetVisibleDevices();
130                 Thread t = new Thread(get_visible_devices);
131                 t.start();
132
133                 found_devices = new LinkedBlockingQueue<AltosBTDevice>();
134
135                 JButton cancelButton = new JButton("Cancel");
136                 cancelButton.addActionListener(this);
137
138                 final JButton selectButton = new JButton("Select");
139                 selectButton.setActionCommand("select");
140                 selectButton.addActionListener(this);
141                 getRootPane().setDefaultButton(selectButton);
142
143                 selected_devices = new DeviceList();
144                 JScrollPane selected_list_scroller = new JScrollPane(selected_devices);
145                 selected_list_scroller.setPreferredSize(new Dimension(400, 80));
146                 selected_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
147
148                 visible_devices = new DeviceList();
149                 JScrollPane visible_list_scroller = new JScrollPane(visible_devices);
150                 visible_list_scroller.setPreferredSize(new Dimension(400, 80));
151                 visible_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
152
153                 //Create a container so that we can add a title around
154                 //the scroll pane.  Can't add a title directly to the
155                 //scroll pane because its background would be white.
156                 //Lay out the label and scroll pane from top to bottom.
157                 JPanel listPane = new JPanel();
158                 listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
159
160                 JLabel label = new JLabel("Select Device");
161                 label.setLabelFor(selected_devices);
162                 listPane.add(label);
163                 listPane.add(Box.createRigidArea(new Dimension(0,5)));
164                 listPane.add(selected_list_scroller);
165                 listPane.add(visible_list_scroller);
166                 listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
167
168                 //Lay out the buttons from left to right.
169                 JPanel buttonPane = new JPanel();
170                 buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
171                 buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
172                 buttonPane.add(Box.createHorizontalGlue());
173                 buttonPane.add(cancelButton);
174                 buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
175                 buttonPane.add(selectButton);
176
177                 //Put everything together, using the content pane's BorderLayout.
178                 Container contentPane = getContentPane();
179                 contentPane.add(listPane, BorderLayout.CENTER);
180                 contentPane.add(buttonPane, BorderLayout.PAGE_END);
181
182                 //Initialize values.
183 //              list.setSelectedValue(initial, true);
184                 pack();
185                 setLocationRelativeTo(frame);
186                 setVisible(true);
187         }
188 }