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