Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/virtuosotechnologies/asaph/standardgui/SongWindow.java


1   /*
2   ================================================================================
3   
4     FILE:  SongWindow.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      A window in the standard gui, for viewing and editing a single song
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.awt.Dimension;
46  import java.awt.BorderLayout;
47  import java.awt.print.PrinterJob;
48  import java.util.logging.Logger;
49  import javax.swing.JPanel;
50  import javax.swing.JOptionPane;
51  import javax.swing.SwingUtilities;
52  import javax.print.attribute.PrintRequestAttributeSet;
53  
54  import com.virtuosotechnologies.lib.command.CommandEvent;
55  import com.virtuosotechnologies.lib.basiccommand.BasicCommandNode;
56  import com.virtuosotechnologies.lib.basiccommand.BasicGroupCommandNode;
57  import com.virtuosotechnologies.lib.basiccommand.BasicContainerCommandNode;
58  import com.virtuosotechnologies.lib.basiccommand.BasicRadioGroupCommandNode;
59  import com.virtuosotechnologies.lib.basiccommand.BasicSeparatorCommandNode;
60  import com.virtuosotechnologies.lib.basiccommand.BasicItemCommandNode;
61  import com.virtuosotechnologies.lib.basiccommand.BasicToggleItemCommandNode;
62  import com.virtuosotechnologies.lib.util.ExceptionUtils;
63  import com.virtuosotechnologies.lib.swing.SwingUtils;
64  import com.virtuosotechnologies.lib.swing.DetailedMessageDialog;
65  import com.virtuosotechnologies.lib.swing.SizeConstrainingLayout;
66  import com.virtuosotechnologies.lib.asyncjob.AsyncJobRunner;
67  import com.virtuosotechnologies.lib.propertyset.PropertySetListener;
68  import com.virtuosotechnologies.lib.propertyset.PropertySetEvent;
69  import com.virtuosotechnologies.lib.platform.PlatformUtils;
70  
71  import com.virtuosotechnologies.asaph.model.SongID;
72  import com.virtuosotechnologies.asaph.model.Song;
73  import com.virtuosotechnologies.asaph.model.SongDatabase;
74  import com.virtuosotechnologies.asaph.model.SongDatabaseFailedException;
75  import com.virtuosotechnologies.asaph.model.SongDeletedException;
76  import com.virtuosotechnologies.asaph.model.SongNotFreshException;
77  import com.virtuosotechnologies.asaph.maingui.DatabaseManager;
78  import com.virtuosotechnologies.asaph.maingui.GuiEnvironmentManager;
79  import com.virtuosotechnologies.asaph.maingui.ListUpdateManager;
80  import com.virtuosotechnologies.asaph.maingui.PaneManager;
81  import com.virtuosotechnologies.asaph.maingui.PaneHandler;
82  import com.virtuosotechnologies.asaph.maingui.PaneController;
83  import com.virtuosotechnologies.asaph.modelutils.SongUtils;
84  import com.virtuosotechnologies.asaph.modelutils.DataTransferUtils;
85  import com.virtuosotechnologies.asaph.notationmanager.NotationManager;
86  
87  
88  /**
89   * A window in the standard gui, for viewing and editing a single song
90   */
91  /*package*/ class SongWindow
92  {
93    private static final String STR_menu_SongTitle =
94      ResourceAccess.Strings.buildString("menu_SongTitle");
95    private static final String STR_menu_Song_SaveItem =
96      ResourceAccess.Strings.buildString("menu_Song_SaveItem");
97    private static final String STR_menu_Song_CloseItem =
98      ResourceAccess.Strings.buildString("menu_Song_CloseItem");
99    private static final String STR_menu_Song_ToggleViewerItem =
100     ResourceAccess.Strings.buildString("menu_Song_ToggleViewerItem");
101   private static final String STR_menu_Song_ToggleEditorItem =
102     ResourceAccess.Strings.buildString("menu_Song_ToggleEditorItem");
103   
104   private static final String STR_menu_Song_SaveKeyStroke =
105     ResourceAccess.Strings.buildString("menu_Song_SaveKeyStroke");
106   private static final String STR_menu_Song_CloseKeyStroke =
107     ResourceAccess.Strings.buildString("menu_Song_CloseKeyStroke");
108   
109   private static final String STR_SongWindow_UntitledSongTitle =
110     ResourceAccess.Strings.buildString("SongWindow_UntitledSongTitle");
111   
112   private static final String STR_dialog_ErrorTitle =
113     ResourceAccess.Strings.buildString("dialog_ErrorTitle");
114   private static final String STR_dialog_ConfirmTitle =
115     ResourceAccess.Strings.buildString("dialog_ConfirmTitle");
116   private static final String STR_dialog_ErrorsHeader =
117     ResourceAccess.Strings.buildString("dialog_ErrorsHeader");
118   private static final String STR_dialog_FirstExceptionTemplate =
119     ResourceAccess.Strings.buildString("dialog_FirstExceptionTemplate");
120   private static final String STR_dialog_NextExceptionTemplate =
121     ResourceAccess.Strings.buildString("dialog_NextExceptionTemplate");
122   private static final String STR_message_SongVanishedOnSave =
123     ResourceAccess.Strings.buildString("message_SongVanishedOnSave");
124   private static final String STR_message_SongNotFreshOnSave =
125     ResourceAccess.Strings.buildString("message_SongNotFreshOnSave");
126   private static final String STR_message_SongRemovedOnSave =
127     ResourceAccess.Strings.buildString("message_SongRemovedOnSave");
128   private static final String STR_message_SaveSongError =
129     ResourceAccess.Strings.buildString("message_SaveSongError");
130   
131   
132   private Logger logger_;
133   
134   private StandardGuiPlugin plugin_;
135   private SongUtils songUtils_;
136   private DataTransferUtils dataTransferUtils_;
137   private NotationManager notationManager_;
138   private DatabaseManager databaseManager_;
139   private GuiEnvironmentManager guiEnvironmentManager_;
140   private ListUpdateManager listUpdateManager_;
141   private AsyncJobRunner jobRunner_;
142   
143   private SongID songID_;
144   private Song song_;
145   private String songTitle_;
146   private boolean dirty_;
147   
148   private RenderSettings renderSettings_;
149   
150   private PaneController paneController_;
151   private JPanel mainPanel_;
152   private BasicCommandNode commandGroup_;
153   private BasicCommandNode saveCommand_;
154   private BasicCommandNode viewerMode_;
155   private BasicCommandNode editorMode_;
156   
157   private SongViewer viewer_;
158   private SongEditor editor_;
159   
160   private EditorPrefs editorPrefs_;
161   private EditorPrefs.PrefsListener prefsListener_;
162   
163   
164   /**
165    * Constructor
166    */
167   /*package*/ SongWindow(
168     StandardGuiPlugin plugin,
169     SongID songID,
170     EditorPrefs editorPrefs,
171     DatabaseManager databaseManager,
172     GuiEnvironmentManager guiEnvironmentManager,
173     ListUpdateManager listUpdateManager,
174     PaneManager paneManager,
175     SongUtils songUtils,
176     DataTransferUtils dataTransferUtils,
177     NotationManager notationManager,
178     AsyncJobRunner jobRunner)
179   throws
180     SongDatabaseFailedException,
181     SongDeletedException
182   {
183     logger_ = Logger.getLogger("com.virtuosotechnologies.asaph.standardgui");
184     
185     plugin_ = plugin;
186     songUtils_ = songUtils;
187     dataTransferUtils_ = dataTransferUtils;
188     notationManager_ = notationManager;
189     databaseManager_ = databaseManager;
190     guiEnvironmentManager_ = guiEnvironmentManager;
191     listUpdateManager_ = listUpdateManager;
192     jobRunner_ = jobRunner;
193     
194     editorPrefs_ = editorPrefs;
195     editorPrefs_.addPrefsListener(
196       prefsListener_ = new EditorPrefs.PrefsListener()
197       {
198         public void prefsChanged(
199           EditorPrefs.PrefsChangedEvent ev)
200         {
201           if (editor_ != null)
202           {
203             editor_.setUndoLevels(editorPrefs_.getUndoLevels());
204           }
205         }
206       });
207     
208     renderSettings_ = new RenderSettings();
209     
210     songID_ = songID;
211     song_ = songID.getDatabase().checkOutSong(songID);
212     if (song_ == null)
213     {
214       throw new SongDeletedException();
215     }
216     boolean brandNew = songUtils_.prepareSongForEditing(song_);
217     dirty_ = false;
218     
219     // Set up containers
220     commandGroup_ = new BasicGroupCommandNode();
221     mainPanel_ = new JPanel(new SizeConstrainingLayout(
222       400, 300, Integer.MAX_VALUE, Integer.MAX_VALUE));
223     
224     // Set up song menu
225     BasicCommandNode songMenu = new BasicContainerCommandNode();
226     songMenu.setNameProperty(STR_menu_SongTitle);
227     commandGroup_.addChild(songMenu);
228     
229     BasicCommandNode modeGroup = new BasicRadioGroupCommandNode();
230     songMenu.addChild(modeGroup);
231     viewerMode_ = new ToggleViewerCommandNode();
232     editorMode_ = new ToggleEditorCommandNode();
233     modeGroup.addChild(viewerMode_);
234     modeGroup.addChild(editorMode_);
235     if (brandNew)
236     {
237       editorMode_.setSelectionStateProperty(true);
238     }
239     else
240     {
241       viewerMode_.setSelectionStateProperty(true);
242     }
243     
244     songMenu.addChild(BasicSeparatorCommandNode.getInstance());
245     
246     saveCommand_ = new BasicItemCommandNode()
247     {
248       public void commandInvoked(
249         CommandEvent ev)
250       {
251         handleSave();
252       }
253     };
254     saveCommand_.setNameProperty(STR_menu_Song_SaveItem);
255     saveCommand_.setDisabledProperty(true);
256     saveCommand_.setAcceleratorKeystrokeProperty(SwingUtils.buildAcceleratorKeyStroke(
257       STR_menu_Song_SaveKeyStroke));
258     songMenu.addChild(saveCommand_);
259     
260     BasicCommandNode closeNode = new BasicItemCommandNode()
261     {
262       public void commandInvoked(
263         CommandEvent ev)
264       {
265         if (handleClosing())
266         {
267           paneController_.close();
268         }
269       }
270     };
271     closeNode.setNameProperty(STR_menu_Song_CloseItem);
272     closeNode.setAcceleratorKeystrokeProperty(SwingUtils.buildAcceleratorKeyStroke(
273       STR_menu_Song_CloseKeyStroke));
274     songMenu.addChild(closeNode);
275     
276     // Set up pane
277     songTitle_ = songUtils_.getFieldValueAsString(song_, Song.MAINTITLE_FIELD);
278     if (songTitle_.length() == 0)
279     {
280       songTitle_ = STR_SongWindow_UntitledSongTitle;
281     }
282     paneController_ = paneManager.createPane(mainPanel_, songTitle_, commandGroup_,
283       new PaneHandler()
284       {
285         public boolean handlePaneClosing()
286         {
287           return handleClosing();
288         }
289       });
290     plugin_.registerWindow(this);
291   }
292   
293   
294   private class ToggleViewerCommandNode
295   extends BasicToggleItemCommandNode
296   implements PropertySetListener
297   {
298     private ToggleViewerCommandNode()
299     {
300       setNameProperty(STR_menu_Song_ToggleViewerItem);
301       addPropertySetListener(this);
302     }
303     
304     public void propertySetChanged(
305       PropertySetEvent ev)
306     {
307       if (ev.getKey() == BasicCommandNode.SELECTION_STATE_PROPERTY &&
308         Boolean.TRUE.equals(ev.getNewValue()))
309       {
310         switchToViewer();
311       }
312     }
313   }
314   
315   
316   private class ToggleEditorCommandNode
317   extends BasicToggleItemCommandNode
318   implements PropertySetListener
319   {
320     private ToggleEditorCommandNode()
321     {
322       setNameProperty(STR_menu_Song_ToggleEditorItem);
323       addPropertySetListener(this);
324     }
325     
326     public void propertySetChanged(
327       PropertySetEvent ev)
328     {
329       if (ev.getKey() == BasicCommandNode.SELECTION_STATE_PROPERTY &&
330         Boolean.TRUE.equals(ev.getNewValue()))
331       {
332         switchToEditor();
333       }
334     }
335   }
336   
337   
338   private void switchToViewer()
339   {
340     if (editor_ != null)
341     {
342       editor_.dispose();
343       editor_ = null;
344     }
345     viewer_ = new SongViewer(this, songUtils_, guiEnvironmentManager_,
346       jobRunner_, songID_, song_, renderSettings_);
347     mainPanel_.removeAll();
348     mainPanel_.add(viewer_.getJComponent(), BorderLayout.CENTER);
349     SwingUtilities.invokeLater(
350       new Runnable()
351       {
352         public void run()
353         {
354           viewer_.getJComponent().requestFocus();
355         }
356       });
357     if (commandGroup_.getNumChildren() > 1)
358     {
359       commandGroup_.removeNthChild(1);
360     }
361     commandGroup_.addChild(viewer_.getCommandNode());
362   }
363   
364   
365   private void switchToEditor()
366   {
367     if (viewer_ != null)
368     {
369       viewer_.dispose();
370       viewer_ = null;
371     }
372     editor_ = new SongEditor(this, songUtils_, editorPrefs_,
373       guiEnvironmentManager_, jobRunner_, songID_, song_);
374     editor_.setUndoLevels(editorPrefs_.getUndoLevels());
375     mainPanel_.removeAll();
376     mainPanel_.add(editor_.getJComponent(), BorderLayout.CENTER);
377     SwingUtilities.invokeLater(
378       new Runnable()
379       {
380         public void run()
381         {
382           editor_.getJComponent().requestFocus();
383         }
384       });
385     if (commandGroup_.getNumChildren() > 1)
386     {
387       commandGroup_.removeNthChild(1);
388     }
389     commandGroup_.addChild(editor_.getCommandNode());
390   }
391   
392   
393   /*package*/ SongUtils getSongUtils()
394   {
395     return songUtils_;
396   }
397   
398   
399   /*package*/ DataTransferUtils getDataTransferUtils()
400   {
401     return dataTransferUtils_;
402   }
403   
404   
405   /*package*/ NotationManager getNotationManager()
406   {
407     return notationManager_;
408   }
409   
410   
411   /**
412    * Handle database closing event
413    */
414   /*package*/ boolean databaseClosing(
415     SongDatabase database)
416   {
417     if (songID_.getDatabase().equals(database))
418     {
419       if (handleClosing())
420       {
421         paneController_.close();
422         return true;
423       }
424       else
425       {
426         return false;
427       }
428     }
429     else
430     {
431       return true;
432     }
433   }
434   
435   
436   /**
437    * Handle close request
438    */
439   private boolean handleClosing()
440   {
441     if (editor_ != null)
442     {
443       editor_.commitCurrentField();
444     }
445     if (dirty_)
446     {
447       int option = JOptionPane.showConfirmDialog(guiEnvironmentManager_.getDialogParent(),
448         ResourceAccess.Strings.buildString("message_SaveSongBeforeClosing", songTitle_),
449         STR_dialog_ConfirmTitle, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
450       if (option == JOptionPane.YES_OPTION)
451       {
452         if (!handleSave())
453         {
454           return false;
455         }
456       }
457       else if (option != JOptionPane.NO_OPTION)
458       {
459         return false;
460       }
461     }
462     editorPrefs_.removePrefsListener(prefsListener_);
463     plugin_.unregisterWindow(this);
464     return true;
465   }
466   
467   
468   /**
469    * Handle save request
470    */
471   private boolean handleSave()
472   {
473     if (editor_ != null)
474     {
475       editor_.commitCurrentField();
476     }
477     SongDatabase database = songID_.getDatabase();
478     try
479     {
480       try
481       {
482         try
483         {
484           database.commitSong(song_);
485         }
486         catch (SongNotFreshException ex)
487         {
488           int option = JOptionPane.showConfirmDialog(guiEnvironmentManager_.getDialogParent(),
489             STR_message_SongNotFreshOnSave, STR_dialog_ConfirmTitle,
490             JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
491           if (option != JOptionPane.YES_OPTION)
492           {
493             return false;
494           }
495           database.forceCommitSong(song_);
496         }
497         listUpdateManager_.reportSongChanged(songID_);
498       }
499       catch (SongDeletedException ex)
500       {
501         int option = JOptionPane.showConfirmDialog(guiEnvironmentManager_.getDialogParent(),
502           STR_message_SongRemovedOnSave, STR_dialog_ConfirmTitle,
503           JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
504         if (option != JOptionPane.YES_OPTION)
505         {
506           return false;
507         }
508         SongID newSongID = database.addCopyOfSong(song_);
509         listUpdateManager_.reportSongAdded(newSongID);
510         Song newSong = database.checkOutSong(newSongID);
511         if (newSong == null)
512         {
513           throw new SongDatabaseFailedException(STR_message_SongVanishedOnSave);
514         }
515         songID_ = newSongID;
516         song_ = newSong;
517         songUtils_.prepareSongForEditing(song_);
518         if (viewerMode_.getSelectionStateProperty())
519         {
520           switchToViewer();
521         }
522         else if (editorMode_.getSelectionStateProperty())
523         {
524           switchToEditor();
525         }
526       }
527       databaseManager_.setDatabaseDirtyBit(database);
528     }
529     catch (SongDatabaseFailedException ex)
530     {
531       DetailedMessageDialog dialog = DetailedMessageDialog.create(
532         guiEnvironmentManager_.getDialogParent(), STR_dialog_ErrorTitle,
533         STR_message_SaveSongError, STR_dialog_ErrorsHeader,
534         ExceptionUtils.getDescriptionFor(ex,
535           STR_dialog_FirstExceptionTemplate, STR_dialog_NextExceptionTemplate),
536         null);
537       dialog.show();
538       return false;
539     }
540     dirty_ = false;
541     saveCommand_.setDisabledProperty(true);
542     paneController_.putValue(PaneController.WINDOW_MODIFIED_KEY, Boolean.FALSE);
543     songTitle_ = songUtils_.getFieldValueAsString(song_, Song.MAINTITLE_FIELD);
544     if (songTitle_.length() == 0)
545     {
546       songTitle_ = STR_SongWindow_UntitledSongTitle;
547     }
548     paneController_.putValue(PaneController.TITLE_KEY, songTitle_);
549     return true;
550   }
551   
552   
553   /**
554    * Mark the song as dirty
555    */
556   /*package*/ void markDirty()
557   {
558     if (!dirty_)
559     {
560       dirty_ = true;
561       saveCommand_.setDisabledProperty(false);
562       paneController_.putValue(PaneController.WINDOW_MODIFIED_KEY, Boolean.TRUE);
563     }
564   }
565   
566   
567   /**
568    * Get PrinterJob
569    */
570   /*package*/ PrinterJob getPrinterJob()
571   {
572     return plugin_.getPrinterJob();
573   }
574   
575   
576   /**
577    * Get PrintRequestAttributeSet
578    */
579   /*package*/ PrintRequestAttributeSet getPrintAttributes()
580   {
581     return plugin_.getPrintAttributes();
582   }
583 }