altosui: Add dialogs to configure 'common' frequencies
[fw/altos] / altosui / AltosConfigFreqUI.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 javax.swing.event.*;
26 import javax.swing.plaf.basic.*;
27 import java.io.*;
28 import java.util.*;
29 import java.text.*;
30 import java.util.prefs.*;
31 import java.util.concurrent.*;
32
33 class AltosEditFreqUI extends JDialog implements ActionListener {
34         Frame           frame;
35         JTextField      frequency;
36         JTextField      description;
37         JButton         ok_button, cancel_button;
38         boolean         got_ok;
39
40         public void actionPerformed(ActionEvent e) {
41                 String  cmd = e.getActionCommand();
42
43                 if ("ok".equals(cmd)) {
44                         got_ok = true;
45                         setVisible(false);
46                 }
47                 if ("cancel".equals(cmd)) {
48                         got_ok = false;
49                         setVisible(false);
50                 }
51         }
52
53         public AltosFrequency get() {
54                 if (!got_ok)
55                         return null;
56
57                 String  f_s = frequency.getText();
58                 String  d_s = description.getText();
59
60                 try {
61                         double  f_d = Double.parseDouble(f_s);
62
63                         return new AltosFrequency(f_d, d_s);
64                 } catch (NumberFormatException ne) {
65                 }
66                 return null;
67         }
68
69         public AltosEditFreqUI(Frame in_frame, AltosFrequency existing) {
70                 super(in_frame, true);
71
72                 got_ok = false;
73                 frame = in_frame;
74
75                 Container pane = getContentPane();
76                 pane.setLayout(new GridBagLayout());
77
78                 GridBagConstraints c = new GridBagConstraints();
79                 c.insets = new Insets (4,4,4,4);
80                 
81                 c.fill = GridBagConstraints.NONE;
82                 c.anchor = GridBagConstraints.WEST;
83                 c.gridx = 0;
84                 c.gridy = 0;
85                 c.gridwidth = 1;
86                 c.gridheight = 1;
87                 c.weightx = 0;
88                 c.weighty = 0;
89                 pane.add(new JLabel("Frequency"), c);
90
91                 frequency = new JTextField(12);
92                 c.fill = GridBagConstraints.NONE;
93                 c.anchor = GridBagConstraints.WEST;
94                 c.gridx = 1;
95                 c.gridy = 0;
96                 c.gridwidth = 1;
97                 c.gridheight = 1;
98                 c.weightx = 0;
99                 c.weighty = 0;
100                 pane.add(frequency, c);
101
102                 c.fill = GridBagConstraints.NONE;
103                 c.anchor = GridBagConstraints.WEST;
104                 c.gridx = 0;
105                 c.gridy = 1;
106                 c.gridwidth = 1;
107                 c.gridheight = 1;
108                 c.weightx = 0;
109                 c.weighty = 0;
110                 pane.add(new JLabel("Description"), c);
111
112                 description = new JTextField(12);
113                 c.fill = GridBagConstraints.NONE;
114                 c.anchor = GridBagConstraints.WEST;
115                 c.gridx = 1;
116                 c.gridy = 1;
117                 c.gridwidth = 1;
118                 c.gridheight = 1;
119                 c.weightx = 0;
120                 c.weighty = 0;
121                 pane.add(description, c);
122
123                 ok_button = new JButton("OK");
124                 ok_button.setActionCommand("ok");
125                 ok_button.addActionListener(this);
126                 c.fill = GridBagConstraints.NONE;
127                 c.anchor = GridBagConstraints.WEST;
128                 c.gridx = 0;
129                 c.gridy = 2;
130                 c.gridwidth = 1;
131                 c.gridheight = 1;
132                 c.weightx = 0;
133                 c.weighty = 0;
134                 pane.add(ok_button, c);
135                 
136                 cancel_button = new JButton("Cancel");
137                 cancel_button.setActionCommand("cancel");
138                 cancel_button.addActionListener(this);
139                 c.fill = GridBagConstraints.NONE;
140                 c.anchor = GridBagConstraints.WEST;
141                 c.gridx = 1;
142                 c.gridy = 2;
143                 c.gridwidth = 1;
144                 c.gridheight = 1;
145                 c.weightx = 0;
146                 c.weighty = 0;
147                 pane.add(cancel_button, c);
148                 
149                 if (existing == null)
150                         setTitle("Add New Frequency");
151                 else {
152                         setTitle("Edit Existing Frequency");
153                         frequency.setText(String.format("%7.3f", existing.frequency));
154                         description.setText(existing.description);
155                 }
156                 getRootPane().setDefaultButton(ok_button);
157
158                 pack();
159                 setLocationRelativeTo(frame);
160                 
161         }
162
163         public AltosEditFreqUI(Frame in_frame) {
164                 this(in_frame, (AltosFrequency) null);
165         }
166 }
167
168 public class AltosConfigFreqUI extends JDialog implements ActionListener {
169
170         Frame frame;
171         LinkedList<ActionListener> listeners;
172
173         class FrequencyList extends JList {
174                 DefaultListModel list_model;
175
176                 public void add(AltosFrequency frequency) {
177                         int i;
178                         for (i = 0; i < list_model.size(); i++) {
179                                 AltosFrequency  f = (AltosFrequency) list_model.get(i);
180                                 if (f.frequency == frequency.frequency)
181                                         return;
182                                 if (f.frequency > frequency.frequency)
183                                         break;
184                         }
185                         list_model.insertElementAt(frequency, i);
186                 }
187
188                 public void remove(AltosFrequency frequency) {
189                         list_model.removeElement(frequency);
190                 }
191
192                 //Subclass JList to workaround bug 4832765, which can cause the
193                 //scroll pane to not let the user easily scroll up to the beginning
194                 //of the list.  An alternative would be to set the unitIncrement
195                 //of the JScrollBar to a fixed value. You wouldn't get the nice
196                 //aligned scrolling, but it should work.
197                 public int getScrollableUnitIncrement(Rectangle visibleRect,
198                                                       int orientation,
199                                                       int direction) {
200                         int row;
201                         if (orientation == SwingConstants.VERTICAL &&
202                             direction < 0 && (row = getFirstVisibleIndex()) != -1) {
203                                 Rectangle r = getCellBounds(row, row);
204                                 if ((r.y == visibleRect.y) && (row != 0))  {
205                                         Point loc = r.getLocation();
206                                         loc.y--;
207                                         int prevIndex = locationToIndex(loc);
208                                         Rectangle prevR = getCellBounds(prevIndex, prevIndex);
209
210                                         if (prevR == null || prevR.y >= r.y) {
211                                                 return 0;
212                                         }
213                                         return prevR.height;
214                                 }
215                         }
216                         return super.getScrollableUnitIncrement(
217                                 visibleRect, orientation, direction);
218                 }
219
220                 public AltosFrequency selected() {
221                         AltosFrequency  f = (AltosFrequency) getSelectedValue();
222                         return f;
223                 }
224
225                 public AltosFrequency[] frequencies() {
226                         AltosFrequency[]        ret;
227
228                         ret = new AltosFrequency[list_model.size()];
229                         for (int i = 0; i < list_model.size(); i++)
230                                 ret[i] = (AltosFrequency) list_model.get(i);
231                         return ret;
232                 }
233
234                 public FrequencyList(AltosFrequency[] in_frequencies) {
235                         list_model = new DefaultListModel();
236                         setModel(list_model);
237                         setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
238                         setLayoutOrientation(JList.HORIZONTAL_WRAP);
239                         for (int i = 0; i < in_frequencies.length; i++) {
240                                 add(in_frequencies[i]);
241                         }
242                         setVisibleRowCount(in_frequencies.length);
243                 }
244         }
245
246         FrequencyList   frequencies;
247
248         void save_frequencies() {
249                 AltosPreferences.set_common_frequencies(frequencies.frequencies());
250         }
251
252         JButton add, edit, remove;
253
254         JButton cancel, ok;
255
256         public void actionPerformed(ActionEvent e) {
257                 String  cmd = e.getActionCommand();
258
259                 if ("ok".equals(cmd)) {
260                         save_frequencies();
261                         setVisible(false);
262                 } else if ("cancel".equals(cmd)) {
263                         setVisible(false);
264                 } else if ("add".equals(cmd)) {
265                         AltosEditFreqUI ui = new AltosEditFreqUI(frame);
266                         ui.setVisible(true);
267                         AltosFrequency  f = ui.get();
268                         if (f != null)
269                                 frequencies.add(f);
270                 } else if ("edit".equals(cmd)) {
271                         AltosFrequency  old_f = frequencies.selected();
272                         if (old_f == null)
273                                 return;
274                         AltosEditFreqUI ui = new AltosEditFreqUI(frame, old_f);
275                         ui.setVisible(true);
276                         AltosFrequency  new_f = ui.get();
277                         if (new_f != null) {
278                                 if (old_f != null)
279                                         frequencies.remove(old_f);
280                                 frequencies.add(new_f);
281                         }
282                 } else if ("remove".equals(cmd)) {
283                         AltosFrequency  old_f = frequencies.selected();
284                         if (old_f == null)
285                                 return;
286                         int ret = JOptionPane.showConfirmDialog(this,
287                                                                 String.format("Remove frequency \"%s\"?",
288                                                                               old_f.toShortString()),
289                                                                 "Remove Frequency",
290                                                                 JOptionPane.YES_NO_OPTION);
291                         if (ret == JOptionPane.YES_OPTION)
292                                 frequencies.remove(old_f);
293                 }
294         }
295
296         public AltosFrequency[] frequencies() {
297                 return frequencies.frequencies();
298         }
299         
300         public AltosConfigFreqUI(Frame in_frame,
301                                  AltosFrequency[] in_frequencies) {
302                 super(in_frame, "Manage Frequencies", true);
303
304                 frame = in_frame;
305
306                 listeners = new LinkedList<ActionListener>();
307
308                 frequencies = new FrequencyList(in_frequencies);
309
310                 Container pane = getContentPane();
311                 pane.setLayout(new GridBagLayout());
312
313                 GridBagConstraints c = new GridBagConstraints();
314                 c.insets = new Insets(4,4,4,4);
315
316                 /*
317                  * Frequencies label and list
318                  */
319                 c.fill = GridBagConstraints.NONE;
320                 c.anchor = GridBagConstraints.WEST;
321                 c.gridx = 0;
322                 c.gridy = 0;
323                 c.gridwidth = 1;
324                 c.gridheight = 1;
325                 c.weightx = 0;
326                 c.weighty = 0;
327                 pane.add(new JLabel("Frequencies"), c);
328
329                 JScrollPane list_scroller = new JScrollPane(frequencies);
330                 list_scroller.setAlignmentX(LEFT_ALIGNMENT);
331                 c.fill = GridBagConstraints.BOTH;
332                 c.anchor = GridBagConstraints.WEST;
333                 c.gridx = 0;
334                 c.gridy = 1;
335                 c.gridwidth = 6;
336                 c.gridheight = 2;
337                 c.weightx = 1;
338                 c.weighty = 1;
339                 pane.add(list_scroller, c);
340
341                 add = new JButton("Add");
342                 add.setActionCommand("add");
343                 add.addActionListener(this);
344                 c.fill = GridBagConstraints.NONE;
345                 c.anchor = GridBagConstraints.CENTER;
346                 c.gridx = 0;
347                 c.gridy = 3;
348                 c.gridwidth = 2;
349                 c.gridheight = 1;
350                 c.weightx = 0;
351                 c.weighty = 0;
352                 pane.add(add, c);
353
354                 edit = new JButton("Edit");
355                 edit.setActionCommand("edit");
356                 edit.addActionListener(this);
357                 c.fill = GridBagConstraints.NONE;
358                 c.anchor = GridBagConstraints.CENTER;
359                 c.gridx = 2;
360                 c.gridy = 3;
361                 c.gridwidth = 2;
362                 c.gridheight = 1;
363                 c.weightx = 0;
364                 c.weighty = 0;
365                 pane.add(edit, c);
366
367                 remove = new JButton("Remove");
368                 remove.setActionCommand("remove");
369                 remove.addActionListener(this);
370                 c.fill = GridBagConstraints.NONE;
371                 c.anchor = GridBagConstraints.CENTER;
372                 c.gridx = 4;
373                 c.gridy = 3;
374                 c.gridwidth = 2;
375                 c.gridheight = 1;
376                 c.weightx = 0;
377                 c.weighty = 0;
378                 pane.add(remove, c);
379
380                 ok = new JButton("OK");
381                 ok.setActionCommand("ok");
382                 ok.addActionListener(this);
383                 c.fill = GridBagConstraints.NONE;
384                 c.anchor = GridBagConstraints.CENTER;
385                 c.gridx = 0;
386                 c.gridy = 4;
387                 c.gridwidth = 3;
388                 c.gridheight = 1;
389                 c.weightx = 0;
390                 c.weighty = 0;
391                 pane.add(ok, c);
392
393                 cancel = new JButton("Cancel");
394                 cancel.setActionCommand("cancel");
395                 cancel.addActionListener(this);
396                 c.fill = GridBagConstraints.NONE;
397                 c.anchor = GridBagConstraints.CENTER;
398                 c.gridx = 3;
399                 c.gridy = 4;
400                 c.gridwidth = 3;
401                 c.gridheight = 1;
402                 c.weightx = 0;
403                 c.weighty = 0;
404                 pane.add(cancel, c);
405
406                 pack();
407                 setLocationRelativeTo(frame);
408         }
409
410         public static void show(Component frameComp) {
411                 Frame   frame = JOptionPane.getFrameForComponent(frameComp);
412                 AltosConfigFreqUI       dialog;
413
414                 dialog = new AltosConfigFreqUI(frame, AltosPreferences.common_frequencies());
415                 dialog.setVisible(true);
416         }
417
418 }