2 * Copyright © 2011 Keith Packard <keithp@keithp.com>
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.
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.
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.
21 import java.awt.event.*;
23 import javax.swing.filechooser.FileNameExtensionFilter;
24 import javax.swing.table.*;
28 import java.util.prefs.*;
29 import java.util.concurrent.*;
33 public class AltosBTManage extends JDialog implements ActionListener {
34 LinkedBlockingQueue<AltosBTDevice> found_devices;
37 class DeviceList extends JList implements Iterable<AltosBTDevice> {
38 LinkedList<AltosBTDevice> devices;
39 DefaultListModel list_model;
41 public void add (AltosBTDevice device) {
43 list_model.addElement(device);
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,
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();
61 int prevIndex = locationToIndex(loc);
62 Rectangle prevR = getCellBounds(prevIndex, prevIndex);
64 if (prevR == null || prevR.y >= r.y) {
70 return super.getScrollableUnitIncrement(
71 visibleRect, orientation, direction);
74 public Iterator<AltosBTDevice> iterator() {
75 return devices.iterator();
79 devices = new LinkedList<AltosBTDevice>();
80 list_model = new DefaultListModel();
82 setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
83 setLayoutOrientation(JList.HORIZONTAL_WRAP);
84 setVisibleRowCount(-1);
88 DeviceList visible_devices;
90 DeviceList selected_devices;
92 public void actionPerformed(ActionEvent e) {
95 public void got_visible_device() {
96 while (!found_devices.isEmpty()) {
97 AltosBTDevice device = found_devices.remove();
98 visible_devices.add(device);
102 class BTGetVisibleDevices implements Runnable {
106 AltosBTDeviceIterator i = new AltosBTDeviceIterator(Altos.product_any);
107 AltosBTDevice device;
109 while ((device = i.next()) != null) {
112 found_devices.add(device);
115 got_visible_device();
118 SwingUtilities.invokeLater(r);
120 } catch (Exception e) {
121 System.out.printf("uh-oh, exception %s\n", e.toString());
126 public static void show(Component frameComp) {
127 Frame frame = JOptionPane.getFrameForComponent(frameComp);
128 AltosBTManage dialog;
130 dialog = new AltosBTManage(frame);
131 dialog.setVisible(true);
134 public AltosBTManage(Frame in_frame) {
135 super(in_frame, "Manage Bluetooth Devices", true);
139 BTGetVisibleDevices get_visible_devices = new BTGetVisibleDevices();
141 Thread t = new Thread(get_visible_devices);
144 found_devices = new LinkedBlockingQueue<AltosBTDevice>();
146 JButton cancelButton = new JButton("Cancel");
147 cancelButton.addActionListener(this);
149 final JButton selectButton = new JButton("Select");
150 selectButton.setActionCommand("select");
151 selectButton.addActionListener(this);
152 getRootPane().setDefaultButton(selectButton);
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);
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);
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));
171 JLabel label = new JLabel("Select Device");
172 label.setLabelFor(selected_devices);
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));
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);
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);
194 // list.setSelectedValue(initial, true);