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