Source code: com/virtuosotechnologies/asaph/standardgui/ChordSetListEditor.java
1 /*
2 ================================================================================
3
4 FILE: ChordSetListEditor.java
5
6 PROJECT:
7
8 Asaph
9
10 CONTENTS:
11
12 Editor swing components for the chord set list
13
14 PROGRAMMERS:
15
16 Daniel Azuma (DA) <dazuma@kagi.com>
17
18 COPYRIGHT:
19
20 Copyright (C) 2003 Daniel Azuma (dazuma@kagi.com)
21
22 This program is free software; you can redistribute it and/or
23 modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2
25 of the License, or (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public
33 License along with this program; if not, write to
34 Free Software Foundation, Inc.
35 59 Temple Place, Suite 330
36 Boston, MA 02111-1307 USA
37
38 ================================================================================
39 */
40
41
42 package com.virtuosotechnologies.asaph.standardgui;
43
44
45 import java.util.List;
46 import java.util.ArrayList;
47 import java.util.Map;
48 import java.util.HashMap;
49 import java.awt.GridBagLayout;
50 import java.awt.GridBagConstraints;
51 import java.awt.BorderLayout;
52 import java.awt.Insets;
53 import java.awt.event.ActionListener;
54 import java.awt.event.ActionEvent;
55 import javax.swing.JPanel;
56 import javax.swing.JLabel;
57 import javax.swing.JButton;
58 import javax.swing.JCheckBox;
59 import javax.swing.JTextField;
60 import javax.swing.BorderFactory;
61 import javax.swing.SwingUtilities;
62 import javax.swing.undo.UndoableEdit;
63 import javax.swing.undo.AbstractUndoableEdit;
64 import javax.swing.undo.CannotUndoException;
65 import javax.swing.undo.CannotRedoException;
66 import javax.swing.event.UndoableEditListener;
67 import javax.swing.event.UndoableEditEvent;
68
69 import com.virtuosotechnologies.lib.util.CollectingCompoundEdit;
70 import com.virtuosotechnologies.lib.util.ObjectUtils;
71
72 import com.virtuosotechnologies.asaph.model.Song;
73 import com.virtuosotechnologies.asaph.model.ChordSet;
74 import com.virtuosotechnologies.asaph.model.notation.Note;
75 import com.virtuosotechnologies.asaph.model.notation.NotationFactory;
76 import com.virtuosotechnologies.asaph.modelutils.SongUtils;
77 import com.virtuosotechnologies.asaph.notationmanager.NotationManager;
78
79
80 /**
81 * Editor swing components for the chord set list
82 */
83 /*package*/ class ChordSetListEditor
84 extends JPanel
85 {
86 private static final String STR_ChordSetListEditor_MainLabel =
87 ResourceAccess.Strings.buildString("ChordSetListEditor_MainLabel");
88 private static final String STR_ChordSetListEditor_AddButton =
89 ResourceAccess.Strings.buildString("ChordSetListEditor_AddButton");
90 private static final String STR_ChordSetListEditor_DeleteButton =
91 ResourceAccess.Strings.buildString("ChordSetListEditor_DeleteButton");
92 private static final String STR_ChordSetListEditor_NameLabel =
93 ResourceAccess.Strings.buildString("ChordSetListEditor_NameLabel");
94 private static final String STR_ChordSetListEditor_InitialTypeString =
95 ResourceAccess.Strings.buildString("ChordSetListEditor_InitialTypeString");
96 private static final String STR_ChordSetListEditor_DefaultCheckbox =
97 ResourceAccess.Strings.buildString("ChordSetListEditor_DefaultCheckbox");
98
99
100 private Song song_;
101 private SongEditor editor_;
102 private UndoableEditListener undoListener_;
103 private SongUtils songUtils_;
104 private NotationFactory notationFactory_;
105
106 private JPanel contentPanel_;
107 private GridBagConstraints contentGbc_;
108 private Map defaultChecks_;
109
110
111 /**
112 * Constructor
113 */
114 /*package*/ ChordSetListEditor(
115 SongUtils songUtils,
116 NotationManager notationManager,
117 Song song,
118 SongEditor editor,
119 UndoableEditListener undoListener)
120 {
121 super(new BorderLayout());
122 song_ = song;
123 editor_ = editor;
124 undoListener_ = undoListener;
125 defaultChecks_ = new HashMap();
126 songUtils_ = songUtils;
127 notationFactory_ = notationManager.getNotationFactoryForLocale(song.getLocale());
128
129 JPanel headerPanel = new JPanel(new GridBagLayout());
130 add(headerPanel, BorderLayout.NORTH);
131 GridBagConstraints gbc = new GridBagConstraints();
132 gbc.gridy = 0;
133 gbc.anchor = GridBagConstraints.WEST;
134 gbc.weighty = 1;
135
136 JLabel label = new JLabel(STR_ChordSetListEditor_MainLabel);
137 gbc.weightx = 0;
138 gbc.insets = new Insets(0, 0, 2, 0);
139 headerPanel.add(label, gbc);
140
141 JButton button = new JButton(STR_ChordSetListEditor_AddButton);
142 button.addActionListener(
143 new ActionListener()
144 {
145 public void actionPerformed(
146 ActionEvent ev)
147 {
148 CollectingCompoundEdit editCollector = new CollectingCompoundEdit();
149 ChordSet newSet = song_.addChordSet(
150 STR_ChordSetListEditor_InitialTypeString,
151 notationFactory_.getDefaultNote(), editCollector);
152 if (song_.getDefaultChordSet() == null)
153 {
154 song_.setDefaultChordSet(newSet, editCollector);
155 }
156 editCollector.end();
157 performAdd(editCollector);
158 }
159 });
160 button.setMargin(new Insets(0, 3, 0, 3));
161 gbc.weightx = 1;
162 gbc.insets = new Insets(0, 10, 2, 0);
163 headerPanel.add(button, gbc);
164
165 contentPanel_ = new JPanel(new GridBagLayout());
166 add(contentPanel_, BorderLayout.CENTER);
167
168 // Populate contentPanel_.
169 contentGbc_ = new GridBagConstraints();
170 contentGbc_.fill = GridBagConstraints.HORIZONTAL;
171 contentGbc_.anchor = GridBagConstraints.WEST;
172 contentGbc_.gridx = 0;
173 contentGbc_.weightx = 1;
174 contentGbc_.insets = new Insets(3, 15, 1, 0);
175
176 for (ChordSet cs = song_.getNextChordSet(null);
177 cs != null; cs = song_.getNextChordSet(cs))
178 {
179 addChordSetGui(cs);
180 }
181 }
182
183
184 private void addChordSetGui(
185 final ChordSet cs)
186 {
187 JPanel csPanel = new JPanel(new GridBagLayout());
188 csPanel.setBorder(BorderFactory.createCompoundBorder(
189 BorderFactory.createLoweredBevelBorder(),
190 BorderFactory.createEmptyBorder(5, 5, 5, 5)));
191 contentPanel_.add(csPanel, contentGbc_);
192
193 GridBagConstraints gbc = new GridBagConstraints();
194 gbc.weighty = 1;
195
196 final JCheckBox defaultCheck = new JCheckBox(STR_ChordSetListEditor_DefaultCheckbox,
197 ObjectUtils.safeEquals(song_.getDefaultChordSet(), cs));
198 gbc.gridx = 0;
199 gbc.gridy = 0;
200 gbc.weightx = 0;
201 gbc.gridwidth = 2;
202 gbc.fill = GridBagConstraints.NONE;
203 gbc.anchor = GridBagConstraints.WEST;
204 gbc.insets = new Insets(0, 0, 3, 10);
205 csPanel.add(defaultCheck, gbc);
206 defaultChecks_.put(cs, defaultCheck);
207 defaultCheck.addActionListener(
208 new ActionListener()
209 {
210 public void actionPerformed(
211 ActionEvent ev)
212 {
213 ChordSet oldDefaultCS = song_.getDefaultChordSet();
214 JCheckBox oldCheck = (JCheckBox)defaultChecks_.get(oldDefaultCS);
215 if (defaultCheck.isSelected())
216 {
217 if (oldCheck != null)
218 {
219 oldCheck.setSelected(false);
220 }
221 song_.setDefaultChordSet(cs,
222 new SetDefaultListener(oldCheck, defaultCheck));
223 }
224 else if (oldCheck == defaultCheck)
225 {
226 song_.setDefaultChordSet(null,
227 new SetDefaultListener(oldCheck, null));
228 }
229 }
230 });
231
232 final JButton deleteButton = new JButton(STR_ChordSetListEditor_DeleteButton);
233 gbc.gridx = 2;
234 gbc.gridy = 0;
235 gbc.weightx = 1;
236 gbc.gridwidth = 1;
237 gbc.fill = GridBagConstraints.NONE;
238 gbc.anchor = GridBagConstraints.EAST;
239 gbc.insets = new Insets(0, 0, 3, 0);
240 csPanel.add(deleteButton, gbc);
241 deleteButton.setMargin(new Insets(0, 3, 0, 3));
242 deleteButton.addActionListener(
243 new ActionListener()
244 {
245 public void actionPerformed(
246 ActionEvent ev)
247 {
248 int deleteIndex = 0;
249 for (ChordSet set = song_.getNextChordSet(null);
250 set != null; set = song_.getNextChordSet(set))
251 {
252 if (cs.equals(set))
253 {
254 break;
255 }
256 ++deleteIndex;
257 }
258 DeleteListener deleter = new DeleteListener(deleteIndex);
259 song_.removeChordSet(cs, deleter);
260 songUtils_.compactSong(song_, deleter);
261 deleter.finish();
262 }
263 });
264
265 JLabel label = new JLabel(STR_ChordSetListEditor_NameLabel);
266 gbc.gridx = 0;
267 gbc.gridy = 1;
268 gbc.weightx = 0;
269 gbc.gridwidth = 1;
270 gbc.fill = GridBagConstraints.NONE;
271 gbc.anchor = GridBagConstraints.WEST;
272 gbc.insets = new Insets(0, 0, 5, 5);
273 csPanel.add(label, gbc);
274
275 final JTextField nameField = new JTextField(cs.getName().getString());
276 StringUpdater.install(nameField, cs.getName(), editor_, undoListener_);
277 gbc.gridx = 1;
278 gbc.gridy = 1;
279 gbc.weightx = 0;
280 gbc.gridwidth = 2;
281 gbc.fill = GridBagConstraints.HORIZONTAL;
282 gbc.anchor = GridBagConstraints.WEST;
283 gbc.insets = new Insets(0, 0, 5, 0);
284 csPanel.add(nameField, gbc);
285
286 KeySignatureListEditor keySigList = new KeySignatureListEditor(
287 cs, editor_, undoListener_, notationFactory_);
288 gbc.gridx = 0;
289 gbc.gridy = 2;
290 gbc.weightx = 0;
291 gbc.gridwidth = 3;
292 gbc.fill = GridBagConstraints.HORIZONTAL;
293 gbc.anchor = GridBagConstraints.WEST;
294 gbc.insets = new Insets(0, 0, 0, 0);
295 csPanel.add(keySigList, gbc);
296 }
297
298
299 private class SetDefaultListener
300 implements UndoableEditListener
301 {
302 private JCheckBox oldCheck_;
303 private JCheckBox newCheck_;
304
305 private SetDefaultListener(
306 JCheckBox oldCheck,
307 JCheckBox newCheck)
308 {
309 oldCheck_ = oldCheck;
310 newCheck_ = newCheck;
311 }
312
313 public void undoableEditHappened(
314 UndoableEditEvent ev)
315 {
316 final UndoableEdit delegate = ev.getEdit();
317
318 undoListener_.undoableEditHappened(new UndoableEditEvent(
319 ev.getSource(),
320 new AbstractUndoableEdit()
321 {
322 public void undo()
323 throws CannotUndoException
324 {
325 super.undo();
326 delegate.undo();
327 // Update view
328 if (oldCheck_ != null)
329 {
330 oldCheck_.setSelected(true);
331 }
332 if (newCheck_ != null)
333 {
334 newCheck_.setSelected(false);
335 }
336 }
337
338 public void redo()
339 throws CannotRedoException
340 {
341 super.redo();
342 delegate.redo();
343 // Update view
344 if (oldCheck_ != null)
345 {
346 oldCheck_.setSelected(false);
347 }
348 if (newCheck_ != null)
349 {
350 newCheck_.setSelected(true);
351 }
352 }
353 }));
354 }
355 }
356
357
358 private void performAdd(
359 final UndoableEdit edit)
360 {
361 // Update view
362 final ChordSet cs = song_.getPreviousChordSet(null);
363 final int index = song_.getChordSetCount()-1;
364 addChordSetGui(cs);
365 final JPanel panel = (JPanel)contentPanel_.getComponent(index);
366 revalidate();
367
368 undoListener_.undoableEditHappened(new UndoableEditEvent(this,
369 new AbstractUndoableEdit()
370 {
371 public void undo()
372 throws CannotUndoException
373 {
374 super.undo();
375 edit.undo();
376 // Update view
377 contentPanel_.remove(index);
378 revalidate();
379 resetFocus();
380 }
381
382 public void redo()
383 throws CannotRedoException
384 {
385 super.redo();
386 edit.redo();
387 // Update view
388 contentPanel_.add(panel, contentGbc_, index);
389 revalidate();
390 }
391 }));
392 }
393
394
395 private class DeleteListener
396 implements UndoableEditListener
397 {
398 private int deleteIndex_;
399 private List edits_;
400 private Object source_;
401
402 private DeleteListener(
403 int index)
404 {
405 deleteIndex_ = index;
406 edits_ = new ArrayList();
407 }
408
409 public void undoableEditHappened(
410 UndoableEditEvent ev)
411 {
412 edits_.add(ev.getEdit());
413 if (source_ == null)
414 {
415 source_ = ev.getSource();
416 }
417 }
418
419 /*package*/ final void finish()
420 {
421 // Update view
422 final JPanel panel = (JPanel)contentPanel_.getComponent(deleteIndex_);
423 contentPanel_.remove(deleteIndex_);
424 revalidate();
425 resetFocus();
426 final UndoableEdit[] editArray = new UndoableEdit[edits_.size()];
427 edits_.toArray(editArray);
428
429 undoListener_.undoableEditHappened(new UndoableEditEvent(source_,
430 new AbstractUndoableEdit()
431 {
432 public void undo()
433 throws CannotUndoException
434 {
435 super.undo();
436 for (int i=editArray.length-1; i>=0; --i)
437 {
438 editArray[i].undo();
439 }
440 // Update view
441 contentPanel_.add(panel, contentGbc_, deleteIndex_);
442 revalidate();
443 }
444
445 public void redo()
446 throws CannotRedoException
447 {
448 super.redo();
449 for (int i=0; i<editArray.length; ++i)
450 {
451 editArray[i].redo();
452 }
453 // Update view
454 contentPanel_.remove(deleteIndex_);
455 revalidate();
456 resetFocus();
457 }
458 }));
459 }
460 }
461
462
463 private void resetFocus()
464 {
465 SwingUtilities.invokeLater(
466 new Runnable()
467 {
468 public void run()
469 {
470 contentPanel_.requestFocus();
471 }
472 });
473 }
474 }