altosui: remove un-used import
[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.plaf.basic.*;
24 import java.util.*;
25 import java.util.concurrent.*;
26
27 public class AltosBTManage extends AltosDialog implements ActionListener, Iterable<AltosBTDevice> {
28         LinkedBlockingQueue<AltosBTDevice> found_devices;
29         Frame frame;
30         LinkedList<ActionListener> listeners;
31         AltosBTKnown    bt_known;
32
33         class DeviceList extends JList implements Iterable<AltosBTDevice> {
34                 LinkedList<AltosBTDevice> devices;
35                 DefaultListModel        list_model;
36
37                 public void add (AltosBTDevice device) {
38                         if (!devices.contains(device)) {
39                                 devices.add(device);
40                                 list_model.addElement(device);
41                         }
42                 }
43
44                 public void remove (AltosBTDevice device) {
45                         if (devices.contains(device)) {
46                                 devices.remove(device);
47                                 list_model.removeElement(device);
48                         }
49                 }
50
51                 public boolean contains(AltosBTDevice device) {
52                         return devices.contains(device);
53                 }
54
55                 //Subclass JList to workaround bug 4832765, which can cause the
56                 //scroll pane to not let the user easily scroll up to the beginning
57                 //of the list.  An alternative would be to set the unitIncrement
58                 //of the JScrollBar to a fixed value. You wouldn't get the nice
59                 //aligned scrolling, but it should work.
60                 public int getScrollableUnitIncrement(Rectangle visibleRect,
61                                                       int orientation,
62                                                       int direction) {
63                         int row;
64                         if (orientation == SwingConstants.VERTICAL &&
65                             direction < 0 && (row = getFirstVisibleIndex()) != -1) {
66                                 Rectangle r = getCellBounds(row, row);
67                                 if ((r.y == visibleRect.y) && (row != 0))  {
68                                         Point loc = r.getLocation();
69                                         loc.y--;
70                                         int prevIndex = locationToIndex(loc);
71                                         Rectangle prevR = getCellBounds(prevIndex, prevIndex);
72
73                                         if (prevR == null || prevR.y >= r.y) {
74                                                 return 0;
75                                         }
76                                         return prevR.height;
77                                 }
78                         }
79                         return super.getScrollableUnitIncrement(
80                                 visibleRect, orientation, direction);
81                 }
82
83                 public Iterator<AltosBTDevice> iterator() {
84                         return devices.iterator();
85                 }
86
87                 public java.util.List<AltosBTDevice> selected_list() {
88                         java.util.LinkedList<AltosBTDevice> l = new java.util.LinkedList<AltosBTDevice>();
89                         Object[] a = getSelectedValues();
90                         for (int i = 0; i < a.length; i++)
91                                 l.add((AltosBTDevice)a[i]);
92                         return l;
93                 }
94
95                 public DeviceList() {
96                         devices = new LinkedList<AltosBTDevice>();
97                         list_model = new DefaultListModel();
98                         setModel(list_model);
99                         setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
100                         setLayoutOrientation(JList.HORIZONTAL_WRAP);
101                         setVisibleRowCount(-1);
102                 }
103         }
104
105         DeviceList      visible_devices;
106
107         DeviceList      known_devices;
108         Thread          bt_thread;
109
110         public Iterator<AltosBTDevice> iterator() {
111                 return known_devices.iterator();
112         }
113
114         public void commit() {
115                 bt_known.set(this);
116         }
117
118         public void add_known() {
119                 for (AltosBTDevice device : visible_devices.selected_list()) {
120                         known_devices.add(device);
121                         visible_devices.remove(device);
122                 }
123         }
124
125         public void remove_known() {
126                 for (AltosBTDevice device : known_devices.selected_list()) {
127                         known_devices.remove(device);
128                         visible_devices.add(device);
129                 }
130         }
131
132         public void addActionListener(ActionListener l) {
133                 listeners.add(l);
134         }
135
136         private void forwardAction(ActionEvent e) {
137                 for (ActionListener l : listeners)
138                         l.actionPerformed(e);
139         }
140
141         public void actionPerformed(ActionEvent e) {
142                 String  command = e.getActionCommand();
143                 if ("ok".equals(command)) {
144                         bt_thread.interrupt();
145                         commit();
146                         setVisible(false);
147                         forwardAction(e);
148                 } else if ("cancel".equals(command)) {
149                         bt_thread.interrupt();
150                         setVisible(false);
151                         forwardAction(e);
152                 } else if ("select".equals(command)) {
153                         add_known();
154                 } else if ("deselect".equals(command)) {
155                         remove_known();
156                 }
157         }
158
159         public void got_visible_device() {
160                 while (!found_devices.isEmpty()) {
161                         AltosBTDevice   device = found_devices.remove();
162                         if (!known_devices.contains(device))
163                                 visible_devices.add(device);
164                 }
165         }
166
167         class BTGetVisibleDevices implements Runnable {
168                 public void run () {
169                         for (;;)
170                                 for (int time = 1; time <= 8; time <<= 1) {
171                                         AltosBTDeviceIterator   i = new AltosBTDeviceIterator(time);
172                                         AltosBTDevice           device;
173
174                                         if (Thread.interrupted())
175                                                 return;
176                                         try {
177                                                 while ((device = i.next()) != null) {
178                                                         Runnable r;
179
180                                                         if (Thread.interrupted())
181                                                                 return;
182                                                         found_devices.add(device);
183                                                         r = new Runnable() {
184                                                                         public void run() {
185                                                                                 got_visible_device();
186                                                                         }
187                                                                 };
188                                                         SwingUtilities.invokeLater(r);
189                                                 }
190                                         } catch (Exception e) {
191                                                 System.out.printf("uh-oh, exception %s\n", e.toString());
192                                         }
193                                 }
194                 }
195         }
196
197         public static void show(Component frameComp, AltosBTKnown known) {
198                 Frame   frame = JOptionPane.getFrameForComponent(frameComp);
199                 AltosBTManage   dialog;
200
201                 dialog = new AltosBTManage(frame, known);
202                 dialog.setVisible(true);
203         }
204
205         public AltosBTManage(Frame in_frame, AltosBTKnown in_known) {
206                 super(in_frame, "Manage Bluetooth Devices", true);
207
208                 frame = in_frame;
209                 bt_known = in_known;
210                 BTGetVisibleDevices     get_visible_devices = new BTGetVisibleDevices();
211                 bt_thread = new Thread(get_visible_devices);
212                 bt_thread.start();
213
214                 listeners = new LinkedList<ActionListener>();
215
216                 found_devices = new LinkedBlockingQueue<AltosBTDevice>();
217
218                 Container pane = getContentPane();
219                 pane.setLayout(new GridBagLayout());
220
221                 GridBagConstraints c = new GridBagConstraints();
222                 c.insets = new Insets(4,4,4,4);
223
224                 /*
225                  * Known devices label and list
226                  */
227                 c.fill = GridBagConstraints.NONE;
228                 c.anchor = GridBagConstraints.WEST;
229                 c.gridx = 0;
230                 c.gridy = 0;
231                 c.gridwidth = 1;
232                 c.gridheight = 1;
233                 c.weightx = 0;
234                 c.weighty = 0;
235                 pane.add(new JLabel("Known Devices"), c);
236
237                 known_devices = new DeviceList();
238                 for (AltosBTDevice device : bt_known)
239                         known_devices.add(device);
240
241                 JScrollPane known_list_scroller = new JScrollPane(known_devices);
242                 known_list_scroller.setPreferredSize(new Dimension(400, 80));
243                 known_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
244                 c.fill = GridBagConstraints.BOTH;
245                 c.anchor = GridBagConstraints.WEST;
246                 c.gridx = 0;
247                 c.gridy = 1;
248                 c.gridwidth = 1;
249                 c.gridheight = 2;
250                 c.weightx = 1;
251                 c.weighty = 1;
252                 pane.add(known_list_scroller, c);
253
254                 /*
255                  * Visible devices label and list
256                  */
257                 c.fill = GridBagConstraints.NONE;
258                 c.anchor = GridBagConstraints.WEST;
259                 c.gridx = 2;
260                 c.gridy = 0;
261                 c.gridwidth = 1;
262                 c.gridheight = 1;
263                 c.weightx = 0;
264                 c.weighty = 0;
265
266                 pane.add(new JLabel("Visible Devices"), c);
267
268                 visible_devices = new DeviceList();
269                 JScrollPane visible_list_scroller = new JScrollPane(visible_devices);
270                 visible_list_scroller.setPreferredSize(new Dimension(400, 80));
271                 visible_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
272                 c.fill = GridBagConstraints.BOTH;
273                 c.anchor = GridBagConstraints.WEST;
274                 c.gridx = 2;
275                 c.gridy = 1;
276                 c.gridheight = 2;
277                 c.gridwidth = 1;
278                 c.weightx = 1;
279                 c.weighty = 1;
280                 pane.add(visible_list_scroller, c);
281
282                 /*
283                  * Arrows between the two lists
284                  */
285                 BasicArrowButton select_arrow = new BasicArrowButton(SwingConstants.WEST);
286                 select_arrow.setActionCommand("select");
287                 select_arrow.addActionListener(this);
288                 c.fill = GridBagConstraints.NONE;
289                 c.anchor = GridBagConstraints.SOUTH;
290                 c.gridx = 1;
291                 c.gridy = 1;
292                 c.gridheight = 1;
293                 c.gridwidth = 1;
294                 c.weightx = 0;
295                 c.weighty = 0;
296                 pane.add(select_arrow, c);
297
298                 BasicArrowButton deselect_arrow = new BasicArrowButton(SwingConstants.EAST);
299                 deselect_arrow.setActionCommand("deselect");
300                 deselect_arrow.addActionListener(this);
301                 c.fill = GridBagConstraints.NONE;
302                 c.anchor = GridBagConstraints.NORTH;
303                 c.gridx = 1;
304                 c.gridy = 2;
305                 c.gridheight = 1;
306                 c.gridwidth = 1;
307                 c.weightx = 0;
308                 c.weighty = 0;
309                 pane.add(deselect_arrow, c);
310
311                 JButton cancel_button = new JButton("Cancel");
312                 cancel_button.setActionCommand("cancel");
313                 cancel_button.addActionListener(this);
314                 c.fill = GridBagConstraints.NONE;
315                 c.anchor = GridBagConstraints.CENTER;
316                 c.gridx = 0;
317                 c.gridy = 3;
318                 c.gridheight = 1;
319                 c.gridwidth = 1;
320                 c.weightx = 0;
321                 c.weighty = 0;
322                 pane.add(cancel_button, c);
323
324                 JButton ok_button = new JButton("OK");
325                 ok_button.setActionCommand("ok");
326                 ok_button.addActionListener(this);
327                 c.fill = GridBagConstraints.NONE;
328                 c.anchor = GridBagConstraints.CENTER;
329                 c.gridx = 2;
330                 c.gridy = 3;
331                 c.gridheight = 1;
332                 c.gridwidth = 1;
333                 c.weightx = 0;
334                 c.weighty = 0;
335                 pane.add(ok_button, c);
336
337                 getRootPane().setDefaultButton(ok_button);
338
339                 pack();
340                 setLocationRelativeTo(frame);
341                 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
342                 addWindowListener(new WindowAdapter() {
343                         @Override
344                         public void windowClosing(WindowEvent e) {
345                                 bt_thread.interrupt();
346                                 setVisible(false);
347                         }
348                 });
349         }
350 }