Source code: com/virtuosotechnologies/asaph/standardgui/KeySignatureListEditor.java
1 /*
2 ================================================================================
3
4 FILE: KeySignatureListEditor.java
5
6 PROJECT:
7
8 Asaph
9
10 CONTENTS:
11
12 Editor swing components for the key signature section of the
13 chord set editor
14
15 PROGRAMMERS:
16
17 Daniel Azuma (DA) <dazuma@kagi.com>
18
19 COPYRIGHT:
20
21 Copyright (C) 2003 Daniel Azuma (dazuma@kagi.com)
22
23 This program is free software; you can redistribute it and/or
24 modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation; either version 2
26 of the License, or (at your option) any later version.
27
28 This program is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
32
33 You should have received a copy of the GNU General Public
34 License along with this program; if not, write to
35 Free Software Foundation, Inc.
36 59 Temple Place, Suite 330
37 Boston, MA 02111-1307 USA
38
39 ================================================================================
40 */
41
42
43 package com.virtuosotechnologies.asaph.standardgui;
44
45
46 import java.awt.GridBagConstraints;
47 import java.awt.GridBagLayout;
48 import java.awt.Insets;
49 import java.awt.event.ActionListener;
50 import java.awt.event.ActionEvent;
51 import java.util.Collection;
52 import java.util.ArrayList;
53 import java.util.Iterator;
54 import javax.swing.JPanel;
55 import javax.swing.JLabel;
56 import javax.swing.JSeparator;
57 import javax.swing.JComboBox;
58 import javax.swing.JTextField;
59 import javax.swing.JButton;
60 import javax.swing.SwingUtilities;
61 import javax.swing.undo.UndoableEdit;
62 import javax.swing.undo.AbstractUndoableEdit;
63 import javax.swing.undo.CannotUndoException;
64 import javax.swing.undo.CannotRedoException;
65 import javax.swing.event.UndoableEditListener;
66 import javax.swing.event.UndoableEditEvent;
67
68 import com.virtuosotechnologies.asaph.model.ChordSet;
69 import com.virtuosotechnologies.asaph.model.ChordSetKey;
70 import com.virtuosotechnologies.asaph.model.notation.Note;
71 import com.virtuosotechnologies.asaph.model.notation.NoteModifier;
72 import com.virtuosotechnologies.asaph.model.notation.NotationFactory;
73
74
75 /**
76 * Editor swing components for the key signature section of the chord set editor
77 */
78 /*package*/ class KeySignatureListEditor
79 extends JPanel
80 {
81 private static final String STR_KeySignatureListEditor_DefaultKeyLabel =
82 ResourceAccess.Strings.buildString("KeySignatureListEditor_DefaultKeyLabel");
83 private static final String STR_KeySignatureListEditor_InfoLabel =
84 ResourceAccess.Strings.buildString("KeySignatureListEditor_InfoLabel");
85 private static final String STR_KeySignatureListEditor_AltKeysLabel =
86 ResourceAccess.Strings.buildString("KeySignatureListEditor_AltKeysLabel");
87 private static final String STR_KeySignatureListEditor_AddButton =
88 ResourceAccess.Strings.buildString("KeySignatureListEditor_AddButton");
89 private static final String STR_KeySignatureListEditor_DeleteButton =
90 ResourceAccess.Strings.buildString("KeySignatureListEditor_DeleteButton");
91 private static final String STR_KeySignatureListEditor_OpenParen =
92 ResourceAccess.Strings.buildString("KeySignatureListEditor_OpenParen");
93 private static final String STR_KeySignatureListEditor_CloseParen =
94 ResourceAccess.Strings.buildString("KeySignatureListEditor_CloseParen");
95
96 private static final String[] noteChoices_ =
97 new String[] {"A", "B", "C", "D", "E", "F", "G"};
98 private static final String[] accidentalChoices_ =
99 new String[] {"", "#", "b"};
100
101 private ChordSet chordSet_;
102 private SongEditor editor_;
103 private NotationFactory notationFactory_;
104 private UndoableEditListener undoListener_;
105
106 private JPanel contentPanel_;
107 private GridBagConstraints contentGbc_;
108 private Collection sigTypeLabels_;
109
110
111 /**
112 * Constructor
113 */
114 /*package*/ KeySignatureListEditor(
115 final ChordSet chordSet,
116 SongEditor editor,
117 UndoableEditListener undoListener,
118 NotationFactory notationFactory)
119 {
120 super(new GridBagLayout());
121
122 chordSet_ = chordSet;
123 editor_ = editor;
124 undoListener_ = undoListener;
125 notationFactory_ = notationFactory;
126
127 JLabel label;
128
129 // Toplevel layout
130 GridBagConstraints gbc = new GridBagConstraints();
131 gbc.gridx = 0;
132 gbc.weightx = 1;
133 gbc.weighty = 1;
134 gbc.fill = GridBagConstraints.HORIZONTAL;
135
136 JPanel defaultKeyPanel = new JPanel(new GridBagLayout());
137 add(defaultKeyPanel, gbc);
138
139 gbc.insets = new Insets(5, 0, 5, 0);
140 add(new JSeparator(), gbc);
141 gbc.insets = new Insets(0, 0, 0, 0);
142
143 JPanel altKeysPanel = new JPanel(new GridBagLayout());
144 add(altKeysPanel, gbc);
145
146 contentPanel_ = new JPanel(new GridBagLayout());
147 add(contentPanel_, gbc);
148
149 // DefaultKeyPanel layout
150 gbc = new GridBagConstraints();
151 gbc.weighty = 1;
152 gbc.anchor = GridBagConstraints.EAST;
153 gbc.fill = GridBagConstraints.NONE;
154
155 label = new JLabel(STR_KeySignatureListEditor_DefaultKeyLabel);
156 gbc.gridx = 0;
157 gbc.gridy = 0;
158 gbc.weightx = 0;
159 gbc.insets = new Insets(0, 0, 3, 5);
160 defaultKeyPanel.add(label, gbc);
161
162 label = new JLabel(STR_KeySignatureListEditor_InfoLabel);
163 gbc.gridx = 0;
164 gbc.gridy = 1;
165 gbc.weightx = 0;
166 gbc.insets = new Insets(0, 0, 0, 5);
167 defaultKeyPanel.add(label, gbc);
168
169 gbc.anchor = GridBagConstraints.WEST;
170 gbc.fill = GridBagConstraints.HORIZONTAL;
171 final ChordSetKey defaultNativeKey = chordSet_.getNativeKey();
172 Note defaultKeyNote = defaultNativeKey.getKeyNote();
173
174 final JComboBox defaultNoteCombo = new JComboBox(notationFactory_.getBaseNotes());
175 defaultNoteCombo.setSelectedItem(defaultKeyNote.getBaseNote());
176 gbc.gridx = 1;
177 gbc.gridy = 0;
178 gbc.weightx = 0;
179 gbc.insets = new Insets(0, 0, 3, 3);
180 defaultKeyPanel.add(defaultNoteCombo, gbc);
181
182 final JComboBox defaultAccidentalCombo = new JComboBox(
183 notationFactory_.getCommonModifiersForNote(defaultKeyNote));
184 defaultAccidentalCombo.setSelectedItem(defaultKeyNote.getNoteModifier());
185 gbc.gridx = 2;
186 gbc.gridy = 0;
187 gbc.weightx = 0;
188 gbc.insets = new Insets(0, 0, 3, 3);
189 defaultKeyPanel.add(defaultAccidentalCombo, gbc);
190
191 ComboListener comboListener = new ComboListener(defaultNativeKey,
192 defaultNoteCombo, defaultAccidentalCombo);
193 defaultNoteCombo.addActionListener(comboListener);
194 defaultAccidentalCombo.addActionListener(comboListener);
195
196 final JTextField defaultSigTypeField = new JTextField(
197 chordSet_.getKeySignatureType().getString());
198 gbc.gridx = 3;
199 gbc.gridy = 0;
200 gbc.weightx = 1;
201 gbc.insets = new Insets(0, 0, 3, 0);
202 defaultKeyPanel.add(defaultSigTypeField, gbc);
203 StringUpdater.install(defaultSigTypeField, chordSet.getKeySignatureType(),
204 editor_, new KeySigTextListener());
205
206 final JTextField defaultInfoField = new JTextField(
207 defaultNativeKey.getInfoString().getString());
208 gbc.gridx = 1;
209 gbc.gridwidth = 3;
210 gbc.gridy = 1;
211 gbc.weightx = 0;
212 gbc.insets = new Insets(0, 0, 0, 0);
213 defaultKeyPanel.add(defaultInfoField, gbc);
214 StringUpdater.install(defaultInfoField, defaultNativeKey.getInfoString(),
215 editor_, undoListener_);
216
217 // AltKeysPanel layout
218 gbc = new GridBagConstraints();
219 gbc.gridy = 0;
220 gbc.anchor = GridBagConstraints.WEST;
221 gbc.weighty = 1;
222
223 label = new JLabel(STR_KeySignatureListEditor_AltKeysLabel);
224 gbc.weightx = 0;
225 gbc.insets = new Insets(0, 0, 3, 0);
226 altKeysPanel.add(label, gbc);
227
228 JButton button = new JButton(STR_KeySignatureListEditor_AddButton);
229 final AddListener addListener = new AddListener();
230 button.addActionListener(
231 new ActionListener()
232 {
233 public void actionPerformed(
234 ActionEvent ev)
235 {
236 chordSet_.addAlternateKey(notationFactory_.getDefaultNote(), addListener);
237 }
238 });
239 button.setMargin(new Insets(0, 3, 0, 3));
240 gbc.weightx = 1;
241 gbc.insets = new Insets(0, 10, 3, 0);
242 altKeysPanel.add(button, gbc);
243
244 // Populate contentPanel_.
245 sigTypeLabels_ = new ArrayList();
246 contentGbc_ = new GridBagConstraints();
247 contentGbc_.fill = GridBagConstraints.HORIZONTAL;
248 contentGbc_.anchor = GridBagConstraints.WEST;
249 contentGbc_.gridx = 0;
250 contentGbc_.weightx = 1;
251 contentGbc_.insets = new Insets(1, 15, 1, 0);
252
253 for (ChordSetKey csk = chordSet_.getNextAlternateKey(null);
254 csk != null; csk = chordSet_.getNextAlternateKey(csk))
255 {
256 addAltKeyGui(csk);
257 }
258 }
259
260
261 private void addAltKeyGui(
262 final ChordSetKey csk)
263 {
264 JPanel cskPanel = new JPanel(new GridBagLayout());
265 contentPanel_.add(cskPanel, contentGbc_);
266
267 GridBagConstraints gbc = new GridBagConstraints();
268 gbc.gridy = 0;
269 gbc.weighty = 1;
270 gbc.weightx = 0;
271 gbc.fill = GridBagConstraints.HORIZONTAL;
272
273 Note initialNote = csk.getKeyNote();
274 final JComboBox noteCombo = new JComboBox(notationFactory_.getBaseNotes());
275 noteCombo.setSelectedItem(initialNote.getBaseNote());
276 gbc.insets = new Insets(0, 0, 0, 0);
277 cskPanel.add(noteCombo, gbc);
278
279 final JComboBox accidentalCombo = new JComboBox(
280 notationFactory_.getCommonModifiersForNote(initialNote));
281 accidentalCombo.setSelectedItem(initialNote.getNoteModifier());
282 gbc.insets = new Insets(0, 3, 0, 0);
283 cskPanel.add(accidentalCombo, gbc);
284
285 ComboListener comboListener = new ComboListener(csk, noteCombo, accidentalCombo);
286 noteCombo.addActionListener(comboListener);
287 accidentalCombo.addActionListener(comboListener);
288
289 JLabel sigTypeLabel = new JLabel(chordSet_.getKeySignatureType().getString());
290 gbc.insets = new Insets(0, 2, 0, 0);
291 cskPanel.add(sigTypeLabel, gbc);
292 sigTypeLabels_.add(sigTypeLabel);
293
294 gbc.insets = new Insets(0, 5, 0, 2);
295 cskPanel.add(new JLabel(STR_KeySignatureListEditor_OpenParen), gbc);
296
297 final JTextField field = new JTextField(csk.getInfoString().getString());
298 StringUpdater.install(field, csk.getInfoString(), editor_, undoListener_);
299 gbc.weightx = 1;
300 gbc.insets = new Insets(0, 0, 0, 0);
301 cskPanel.add(field, gbc);
302
303 gbc.insets = new Insets(0, 2, 0, 0);
304 gbc.weightx = 0;
305 cskPanel.add(new JLabel(STR_KeySignatureListEditor_CloseParen), gbc);
306
307 JButton button = new JButton(STR_KeySignatureListEditor_DeleteButton);
308 button.addActionListener(
309 new ActionListener()
310 {
311 public void actionPerformed(
312 ActionEvent ev)
313 {
314 int deleteIndex = 0;
315 for (ChordSetKey k = chordSet_.getNextAlternateKey(null);
316 k != null; k = chordSet_.getNextAlternateKey(k))
317 {
318 if (csk.equals(k))
319 {
320 break;
321 }
322 ++deleteIndex;
323 }
324 chordSet_.removeAlternateKey(csk, new DeleteListener(deleteIndex));
325 }
326 });
327 button.setMargin(new Insets(0, 3, 0, 3));
328 gbc.insets = new Insets(0, 5, 0, 0);
329 cskPanel.add(button, gbc);
330 }
331
332
333 /*package*/ class ComboListener
334 implements
335 UndoableEditListener,
336 ActionListener
337 {
338 private ChordSetKey csk_;
339 private JComboBox noteCombo_;
340 private JComboBox accidentalCombo_;
341 private boolean comboListenerActive_;
342
343
344 /*package*/ ComboListener(
345 final ChordSetKey csk,
346 final JComboBox noteCombo,
347 final JComboBox accidentalCombo)
348 {
349 csk_ = csk;
350 noteCombo_ = noteCombo;
351 accidentalCombo_ = accidentalCombo;
352 comboListenerActive_ = true;
353 }
354
355
356 private void updateCombos()
357 {
358 comboListenerActive_ = false;
359 Note n = csk_.getKeyNote();
360 Note base = n.getBaseNote();
361 if (!noteCombo_.getSelectedItem().equals(base))
362 {
363 noteCombo_.setSelectedItem(base);
364 accidentalCombo_.removeAllItems();
365 NoteModifier[] mods = notationFactory_.getCommonModifiersForNote(n);
366 for (int i=0; i<mods.length; ++i)
367 {
368 accidentalCombo_.addItem(mods[i]);
369 }
370 }
371 accidentalCombo_.setSelectedItem(n.getNoteModifier());
372 comboListenerActive_ = true;
373 }
374
375
376 public void undoableEditHappened(
377 UndoableEditEvent ev)
378 {
379 updateCombos();
380 final UndoableEdit delegate = ev.getEdit();
381 undoListener_.undoableEditHappened(new UndoableEditEvent(
382 ev.getSource(),
383 new AbstractUndoableEdit()
384 {
385 public void undo()
386 throws CannotUndoException
387 {
388 super.undo();
389 delegate.undo();
390 updateCombos();
391 }
392
393 public void redo()
394 throws CannotRedoException
395 {
396 super.redo();
397 delegate.redo();
398 updateCombos();
399 }
400 }));
401 }
402
403
404 public void actionPerformed(
405 ActionEvent ev)
406 {
407 if (comboListenerActive_)
408 {
409 Note n = ((Note)noteCombo_.getSelectedItem()).getNoteWithModifier(
410 (NoteModifier)accidentalCombo_.getSelectedItem());
411 csk_.setKeyNote(n, ComboListener.this);
412 }
413 }
414 }
415
416
417 private class KeySigTextListener
418 implements UndoableEditListener
419 {
420 private void updateLabels()
421 {
422 String str = chordSet_.getKeySignatureType().getString();
423 for (Iterator iter = sigTypeLabels_.iterator(); iter.hasNext(); )
424 {
425 JLabel label = (JLabel)iter.next();
426 label.setText(str);
427 }
428 revalidate();
429 }
430
431 public void undoableEditHappened(
432 UndoableEditEvent ev)
433 {
434 updateLabels();
435
436 final UndoableEdit delegate = ev.getEdit();
437 undoListener_.undoableEditHappened(new UndoableEditEvent(
438 ev.getSource(),
439 new AbstractUndoableEdit()
440 {
441 public void undo()
442 throws CannotUndoException
443 {
444 super.undo();
445 delegate.undo();
446 updateLabels();
447 }
448
449 public void redo()
450 throws CannotRedoException
451 {
452 super.redo();
453 delegate.redo();
454 updateLabels();
455 }
456 }));
457 }
458 }
459
460
461 private class AddListener
462 implements UndoableEditListener
463 {
464 public void undoableEditHappened(
465 UndoableEditEvent ev)
466 {
467 final UndoableEdit delegate = ev.getEdit();
468
469 // Update view
470 final ChordSetKey csk = chordSet_.getPreviousAlternateKey(null);
471 final int index = chordSet_.getAlternateKeyCount()-1;
472 addAltKeyGui(csk);
473 final JPanel panel = (JPanel)contentPanel_.getComponent(index);
474 revalidate();
475
476 undoListener_.undoableEditHappened(new UndoableEditEvent(
477 ev.getSource(),
478 new AbstractUndoableEdit()
479 {
480 public void undo()
481 throws CannotUndoException
482 {
483 super.undo();
484 delegate.undo();
485 // Update view
486 contentPanel_.remove(index);
487 revalidate();
488 resetFocus();
489 }
490
491 public void redo()
492 throws CannotRedoException
493 {
494 super.redo();
495 delegate.redo();
496 // Update view
497 contentPanel_.add(panel, contentGbc_, index);
498 revalidate();
499 }
500 }));
501 }
502 }
503
504
505 private class DeleteListener
506 implements UndoableEditListener
507 {
508 private int deleteIndex_;
509
510 private DeleteListener(
511 int index)
512 {
513 deleteIndex_ = index;
514 }
515
516 public void undoableEditHappened(
517 UndoableEditEvent ev)
518 {
519 final UndoableEdit delegate = ev.getEdit();
520
521 // Update view
522 final JPanel panel = (JPanel)contentPanel_.getComponent(deleteIndex_);
523 contentPanel_.remove(deleteIndex_);
524 revalidate();
525 resetFocus();
526
527 undoListener_.undoableEditHappened(new UndoableEditEvent(
528 ev.getSource(),
529 new AbstractUndoableEdit()
530 {
531 public void undo()
532 throws CannotUndoException
533 {
534 super.undo();
535 delegate.undo();
536 // Update view
537 contentPanel_.add(panel, contentGbc_, deleteIndex_);
538 revalidate();
539 }
540
541 public void redo()
542 throws CannotRedoException
543 {
544 super.redo();
545 delegate.redo();
546 // Update view
547 contentPanel_.remove(deleteIndex_);
548 resetFocus();
549 revalidate();
550 }
551 }));
552 }
553 }
554
555
556 private void resetFocus()
557 {
558 SwingUtilities.invokeLater(
559 new Runnable()
560 {
561 public void run()
562 {
563 contentPanel_.requestFocus();
564 }
565 });
566 }
567 }