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

Quick Search    Search Deep

Source code: com/virtuosotechnologies/asaph/maingui/CommandManagerImpl.java


1   /*
2   ================================================================================
3   
4     FILE:  CommandManagerImpl.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      Implementation of main menu commands
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.maingui;
43  
44  
45  import java.util.Iterator;
46  import java.util.Set;
47  import java.util.List;
48  import java.util.ArrayList;
49  import javax.swing.JComponent;
50  import javax.swing.JOptionPane;
51  
52  import com.virtuosotechnologies.lib.command.CommandEvent;
53  import com.virtuosotechnologies.lib.command.CommandNode;
54  import com.virtuosotechnologies.lib.basiccommand.BasicCommandNode;
55  import com.virtuosotechnologies.lib.basiccommand.BasicContainerCommandNode;
56  import com.virtuosotechnologies.lib.basiccommand.BasicGroupCommandNode;
57  import com.virtuosotechnologies.lib.basiccommand.BasicItemCommandNode;
58  import com.virtuosotechnologies.lib.basiccommand.BasicSeparatorCommandNode;
59  import com.virtuosotechnologies.lib.platform.PlatformListener;
60  import com.virtuosotechnologies.lib.platform.PlatformEvent;
61  import com.virtuosotechnologies.lib.platform.PlatformUtils;
62  import com.virtuosotechnologies.lib.swing.DetailedMessageDialog;
63  import com.virtuosotechnologies.lib.swing.SwingUtils;
64  import com.virtuosotechnologies.lib.util.ExceptionUtils;
65  import com.virtuosotechnologies.lib.util.ObjectUtils;
66  import com.virtuosotechnologies.lib.propertyset.PropertySet;
67  
68  import com.virtuosotechnologies.asaph.model.Song;
69  import com.virtuosotechnologies.asaph.model.SongID;
70  import com.virtuosotechnologies.asaph.model.SongDatabase;
71  import com.virtuosotechnologies.asaph.model.SongDatabaseFailedException;
72  import com.virtuosotechnologies.asaph.modelutils.SongUtils;
73  import com.virtuosotechnologies.asaph.launch.Launcher;
74  
75  
76  /**
77   * Implementation of main menu commands
78   */
79  /*package*/ class CommandManagerImpl
80  implements CommandManager
81  {
82    private static final String STR_Menu_Database_GetInfoUnnamedItem =
83      ResourceAccess.Strings.buildString("Menu_Database_GetInfoUnnamedItem");
84    private static final String STR_Menu_Database_CloseUnnamedItem =
85      ResourceAccess.Strings.buildString("Menu_Database_CloseUnnamedItem");
86    private static final String STR_Menu_Song_AddSongUnnamedItem =
87      ResourceAccess.Strings.buildString("Menu_Song_AddSongUnnamedItem");
88    private static final String STR_Dialog_DatabaseErrorTitle =
89      ResourceAccess.Strings.buildString("Dialog_DatabaseErrorTitle");
90    private static final String STR_Dialog_ErrorHeader =
91      ResourceAccess.Strings.buildString("Dialog_ErrorHeader");
92    private static final String STR_Dialog_FirstExceptionTemplate =
93      ResourceAccess.Strings.buildString("Dialog_FirstExceptionTemplate");
94    private static final String STR_Dialog_NextExceptionTemplate =
95      ResourceAccess.Strings.buildString("Dialog_NextExceptionTemplate");
96    private static final String STR_Message_InternalError =
97      ResourceAccess.Strings.buildString("Message_InternalError");
98    private static final String STR_Message_CopySongFailed =
99      ResourceAccess.Strings.buildString("Message_CopySongFailed");
100   private static final String STR_Message_PasteSongFailed =
101     ResourceAccess.Strings.buildString("Message_PasteSongFailed");
102   private static final String STR_Message_AddSongFailed =
103     ResourceAccess.Strings.buildString("Message_AddSongFailed");
104   private static final String STR_Message_ConfirmDeletePrompt =
105     ResourceAccess.Strings.buildString("Message_ConfirmDeletePrompt");
106   private static final String STR_Dialog_DeleteConfirmTitle =
107     ResourceAccess.Strings.buildString("Dialog_DeleteConfirmTitle");
108   private static final String STR_Message_ContinuePrompt =
109     ResourceAccess.Strings.buildString("Message_ContinuePrompt");
110   private static final String STR_Message_ContinuePrompt_ContinueButton =
111     ResourceAccess.Strings.buildString("Message_ContinuePrompt_ContinueButton");
112   private static final String STR_Message_ContinuePrompt_StopButton =
113     ResourceAccess.Strings.buildString("Message_ContinuePrompt_StopButton");
114   
115   
116   private BasicCommandNode menuBarRoot_;
117   private BasicCommandNode toolBarRoot_;
118   private BasicCommandNode openDatabaseGroup_;
119   private BasicCommandNode saveDatabaseGroup_;
120   private BasicCommandNode songMenuNode_;
121   private BasicCommandNode publishMenuNode_;
122   private BasicCommandNode windowsMenuNode_;
123   private BasicCommandNode dbInfoNode_;
124   private BasicCommandNode closeNode_;
125   private BasicCommandNode refreshSongListNode_;
126   private BasicCommandNode addSongNode_;
127   private BasicCommandNode deleteSongNode_;
128   private BasicCommandNode copySongNode_;
129   private BasicCommandNode pasteSongNode_;
130   private BasicCommandNode findSongsNode_;
131   private BasicCommandNode findAllSongsNode_;
132   private BasicCommandNode songGroup_;
133   private BasicCommandNode defaultSongGroup_;
134   
135   private CommandNode defaultSongNode_;
136   private int defaultSongPriority_;
137   
138   private int lastUntitledNumber_;
139   
140   private PlatformListener platformHandler_;
141   private SelectionListener selectionListener_;
142   
143   private JComponent dialogParent_;
144   private Launcher launcher_;
145   private DatabaseManagerImpl databaseManager_;
146   private GuiEnvironmentManager guiEnviron_;
147   private ListsImpl listsImpl_;
148   private PaneManagerImpl paneManager_;
149   private PrefsWindowManagerImpl prefsWindowManager_;
150   private MainGuiPlugin plugin_;
151   
152   private SearchGui searchGui_;
153   
154   private Song[] songClipboard_;
155   private SongDatabase songClipboardSource_;
156   
157   
158   /*package*/ CommandManagerImpl(
159     JComponent dialogParent,
160     Launcher launcher,
161     SongUtils songUtils,
162     DatabaseManagerImpl databaseManager,
163     GuiEnvironmentManager guiEnviron,
164     ListsImpl listsImpl,
165     PaneManagerImpl paneManager,
166     PrefsWindowManagerImpl prefsWindowManager,
167     MainGuiPlugin plugin)
168   {
169     dialogParent_ = dialogParent;
170     launcher_ = launcher;
171     databaseManager_ = databaseManager;
172     listsImpl_ = listsImpl;
173     paneManager_ = paneManager;
174     prefsWindowManager_ = prefsWindowManager;
175     plugin_ = plugin;
176     
177     songClipboard_ = new Song[0];
178     songClipboardSource_ = null;
179     
180     searchGui_ = new SearchGui(guiEnviron, listsImpl, songUtils);
181     
182     menuBarRoot_ = new BasicContainerCommandNode();
183     toolBarRoot_ = new BasicContainerCommandNode();
184     openDatabaseGroup_ = new BasicGroupCommandNode();
185     saveDatabaseGroup_ = new BasicGroupCommandNode();
186     songGroup_ = new BasicGroupCommandNode();
187     defaultSongGroup_ = new BasicGroupCommandNode();
188     defaultSongNode_ = null;
189     BasicCommandNode node;
190     
191     BasicCommandNode asaphMenuNode = new BasicContainerCommandNode();
192     asaphMenuNode.setNameProperty(ResourceAccess.Strings.buildString("Menu_AsaphTitle"));
193     if (!PlatformUtils.isUsingMacOSXScreenMenuBar())
194     {
195       menuBarRoot_.addChild(asaphMenuNode);
196     }
197     
198     BasicCommandNode fileMenuNode = new BasicContainerCommandNode();
199     fileMenuNode.setNameProperty(ResourceAccess.Strings.buildString("Menu_DatabaseTitle"));
200     menuBarRoot_.addChild(fileMenuNode);
201     
202     songMenuNode_ = new BasicContainerCommandNode();
203     songMenuNode_.setNameProperty(ResourceAccess.Strings.buildString("Menu_SongTitle"));
204     menuBarRoot_.addChild(songMenuNode_);
205     
206     publishMenuNode_ = new BasicContainerCommandNode();
207     publishMenuNode_.setNameProperty(ResourceAccess.Strings.buildString("Menu_ToolsTitle"));
208     menuBarRoot_.addChild(publishMenuNode_);
209     
210     windowsMenuNode_ = new BasicContainerCommandNode();
211     windowsMenuNode_.setNameProperty(ResourceAccess.Strings.buildString("Menu_WindowsTitle"));
212     menuBarRoot_.addChild(windowsMenuNode_);
213     
214     // Create asaph menu
215     node = new BasicItemCommandNode()
216     {
217       public void commandInvoked(
218         CommandEvent ev)
219       {
220         doAbout();
221       }
222     };
223     node.setNameProperty(ResourceAccess.Strings.buildString("Menu_Asaph_AboutItem"));
224     asaphMenuNode.addChild(node);
225     
226     asaphMenuNode.addChild(BasicSeparatorCommandNode.getInstance());
227     
228     node = new BasicItemCommandNode()
229     {
230       public void commandInvoked(
231         CommandEvent ev)
232       {
233         doPrefs();
234       }
235     };
236     node.setNameProperty(ResourceAccess.Strings.buildString("Menu_Asaph_PrefsItem"));
237     asaphMenuNode.addChild(node);
238     
239     asaphMenuNode.addChild(BasicSeparatorCommandNode.getInstance());
240     
241     node = new BasicItemCommandNode()
242     {
243       public void commandInvoked(
244         CommandEvent ev)
245       {
246         doSafeQuit();
247       }
248     };
249     node.setNameProperty(ResourceAccess.Strings.buildString("Menu_Asaph_QuitItem"));
250     node.setAcceleratorKeystrokeProperty(SwingUtils.buildAcceleratorKeyStroke(
251       ResourceAccess.Strings.buildString("Menu_Asaph_QuitKeyStroke")));
252     asaphMenuNode.addChild(node);
253     
254     // Create file menu
255     fileMenuNode.addChild(openDatabaseGroup_);
256     
257     fileMenuNode.addChild(BasicSeparatorCommandNode.getInstance());
258     
259     dbInfoNode_ = new BasicItemCommandNode()
260     {
261       public void commandInvoked(
262         CommandEvent ev)
263       {
264         doGetDBInfo();
265       }
266     };
267     dbInfoNode_.setNameProperty(STR_Menu_Database_GetInfoUnnamedItem);
268     dbInfoNode_.setDisabledProperty(true);
269     fileMenuNode.addChild(dbInfoNode_);
270     
271     closeNode_ = new BasicItemCommandNode()
272     {
273       public void commandInvoked(
274         CommandEvent ev)
275       {
276         doSafeClose();
277       }
278     };
279     closeNode_.setNameProperty(STR_Menu_Database_CloseUnnamedItem);
280     closeNode_.setAcceleratorKeystrokeProperty(SwingUtils.buildAcceleratorKeyStroke(
281       ResourceAccess.Strings.buildString("Menu_Database_CloseKeyStroke")));
282     closeNode_.setDisabledProperty(true);
283     fileMenuNode.addChild(closeNode_);
284     
285     fileMenuNode.addChild(BasicSeparatorCommandNode.getInstance());
286     
287     fileMenuNode.addChild(saveDatabaseGroup_);
288     
289     fileMenuNode.addChild(BasicSeparatorCommandNode.getInstance());
290     
291     refreshSongListNode_ = new BasicItemCommandNode()
292     {
293       public void commandInvoked(
294         CommandEvent ev)
295       {
296         doRefreshIndex();
297       }
298     };
299     refreshSongListNode_.setNameProperty(
300       ResourceAccess.Strings.buildString("Menu_Database_RefreshItem"));
301     refreshSongListNode_.setAcceleratorKeystrokeProperty(SwingUtils.buildAcceleratorKeyStroke(
302       ResourceAccess.Strings.buildString("Menu_Database_RefreshKeyStroke")));
303     refreshSongListNode_.setDisabledProperty(true);
304     fileMenuNode.addChild(refreshSongListNode_);
305     
306     // Create song menu
307     addSongNode_ = new BasicItemCommandNode()
308     {
309       public void commandInvoked(
310         CommandEvent ev)
311       {
312         doAddSong();
313       }
314     };
315     addSongNode_.setNameProperty(STR_Menu_Song_AddSongUnnamedItem);
316     addSongNode_.setAcceleratorKeystrokeProperty(SwingUtils.buildAcceleratorKeyStroke(
317       ResourceAccess.Strings.buildString("Menu_Song_AddSongKeyStroke")));
318     addSongNode_.setDisabledProperty(true);
319     songMenuNode_.addChild(addSongNode_);
320     
321     deleteSongNode_ = new BasicItemCommandNode()
322     {
323       public void commandInvoked(
324         CommandEvent ev)
325       {
326         doDeleteSongs();
327       }
328     };
329     deleteSongNode_.setNameProperty(
330       ResourceAccess.Strings.buildString("Menu_Song_DeleteSongsItem"));
331     deleteSongNode_.setDisabledProperty(true);
332     songMenuNode_.addChild(deleteSongNode_);
333     
334     copySongNode_ = new BasicItemCommandNode()
335     {
336       public void commandInvoked(
337         CommandEvent ev)
338       {
339         doCopySongs();
340       }
341     };
342     copySongNode_.setNameProperty(
343       ResourceAccess.Strings.buildString("Menu_Song_CopySongsItem"));
344     copySongNode_.setDisabledProperty(true);
345     songMenuNode_.addChild(copySongNode_);
346     
347     pasteSongNode_ = new BasicItemCommandNode()
348     {
349       public void commandInvoked(
350         CommandEvent ev)
351       {
352         doPasteSongs();
353       }
354     };
355     pasteSongNode_.setNameProperty(
356       ResourceAccess.Strings.buildString("Menu_Song_PasteSongsItemDisabled"));
357     pasteSongNode_.setDisabledProperty(true);
358     songMenuNode_.addChild(pasteSongNode_);
359     
360     songMenuNode_.addChild(BasicSeparatorCommandNode.getInstance());
361     
362     findSongsNode_ = new BasicItemCommandNode()
363     {
364       public void commandInvoked(
365         CommandEvent ev)
366       {
367         searchGui_.doFindSongs();
368       }
369     };
370     findSongsNode_.setNameProperty(
371       ResourceAccess.Strings.buildString("Menu_Song_FindSongsItem"));
372     findSongsNode_.setDisabledProperty(true);
373     songMenuNode_.addChild(findSongsNode_);
374     
375     findAllSongsNode_ = new BasicItemCommandNode()
376     {
377       public void commandInvoked(
378         CommandEvent ev)
379       {
380         searchGui_.doFindAllSongs();
381       }
382     };
383     findAllSongsNode_.setNameProperty(
384       ResourceAccess.Strings.buildString("Menu_Song_FindAllSongsItem"));
385     findAllSongsNode_.setDisabledProperty(true);
386     songMenuNode_.addChild(findAllSongsNode_);
387     
388     songMenuNode_.addChild(BasicSeparatorCommandNode.getInstance());
389     defaultSongGroup_.setDisabledProperty(true);
390     songMenuNode_.addChild(defaultSongGroup_);
391     songMenuNode_.addChild(BasicSeparatorCommandNode.getInstance());
392     songGroup_.setDisabledProperty(true);
393     songMenuNode_.addChild(songGroup_);
394     
395     // Platform events (currently only affects Mac OS X)
396     platformHandler_ = new PlatformListener()
397     {
398       public void platformEventHappened(
399         PlatformEvent ev)
400       {
401         if (ev.getType() == PlatformUtils.QUIT_EVENT)
402         {
403           doSafeQuit();
404         }
405         else if (ev.getType() == PlatformUtils.OPEN_ABOUTBOX_EVENT)
406         {
407           doAbout();
408           ev.setHandled();
409         }
410         else if (ev.getType() == PlatformUtils.OPEN_PREFERENCES_EVENT)
411         {
412           doPrefs();
413           ev.setHandled();
414         }
415       }
416     };
417     PlatformUtils.addPlatformListener(platformHandler_);
418     PlatformUtils.setSystemPreferencesMenuItemEnabled(true);
419     
420     listsImpl_.addSelectionListener(
421       selectionListener_ = new SelectionListener()
422       {
423         public void databaseSelectionChanged(
424           DatabaseSelectionEvent ev)
425         {
426           if (ev.getNewSelection() == null)
427           {
428             dbInfoNode_.setDisabledProperty(true);
429             dbInfoNode_.setNameProperty(STR_Menu_Database_GetInfoUnnamedItem);
430             closeNode_.setDisabledProperty(true);
431             closeNode_.setNameProperty(STR_Menu_Database_CloseUnnamedItem);
432             refreshSongListNode_.setDisabledProperty(true);
433             findSongsNode_.setDisabledProperty(true);
434             findAllSongsNode_.setDisabledProperty(true);
435             addSongNode_.setDisabledProperty(true);
436             addSongNode_.setNameProperty(STR_Menu_Song_AddSongUnnamedItem);
437             pasteSongNode_.setNameProperty(ResourceAccess.Strings.buildString(
438               "Menu_Song_PasteSongsItemDisabled"));
439             pasteSongNode_.setDisabledProperty(true);
440             saveDatabaseGroup_.setDisabledProperty(true);
441           }
442           else
443           {
444             SongDatabase newSelection = ev.getNewSelection();
445             PropertySet properties = databaseManager_.getDatabaseProperties(newSelection);
446             String name = (String)properties.getValue(DatabaseManager.DATABASE_NAME_KEY);
447             dbInfoNode_.setDisabledProperty(false);
448             dbInfoNode_.setNameProperty(ResourceAccess.Strings.buildString(
449               "Menu_Database_GetInfoNamedItem", name));
450             closeNode_.setDisabledProperty(false);
451             closeNode_.setNameProperty(ResourceAccess.Strings.buildString(
452               "Menu_Database_CloseNamedItem", name));
453             refreshSongListNode_.setDisabledProperty(false);
454             findSongsNode_.setDisabledProperty(false);
455             findAllSongsNode_.setDisabledProperty(false);
456             addSongNode_.setDisabledProperty(!newSelection.isWritable());
457             addSongNode_.setNameProperty(ResourceAccess.Strings.buildString(
458               "Menu_Song_AddSongNamedItem", name));
459             if (songClipboardSource_ == null || songClipboardSource_.equals(newSelection))
460             {
461               pasteSongNode_.setNameProperty(ResourceAccess.Strings.buildString(
462                 "Menu_Song_PasteSongsItemDisabled"));
463               pasteSongNode_.setDisabledProperty(true);
464             }
465             else
466             {
467               pasteSongNode_.setNameProperty(ResourceAccess.Strings.buildString(
468                 "Menu_Song_PasteSongsItem", new Integer(songClipboard_.length), name));
469               pasteSongNode_.setDisabledProperty(false);
470             }
471             saveDatabaseGroup_.setDisabledProperty(false);
472           }
473         }
474         
475         public void songSelectionChanged(
476           SongSelectionEvent ev)
477         {
478           if (ev.getNewSelection().isEmpty())
479           {
480             deleteSongNode_.setDisabledProperty(true);
481             defaultSongGroup_.setDisabledProperty(true);
482             songGroup_.setDisabledProperty(true);
483             copySongNode_.setDisabledProperty(true);
484           }
485           else
486           {
487             deleteSongNode_.setDisabledProperty(!ev.getDatabase().isWritable());
488             defaultSongGroup_.setDisabledProperty(true);
489             songGroup_.setDisabledProperty(false);
490             copySongNode_.setDisabledProperty(false);
491           }
492         }
493       });
494   }
495   
496   
497   /*package*/ BasicCommandNode getMenuBarRoot()
498   {
499     return menuBarRoot_;
500   }
501   
502   
503   /*package*/ BasicCommandNode getToolBarRoot()
504   {
505     return toolBarRoot_;
506   }
507   
508   
509   /*package*/ BasicCommandNode getWindowsMenuNode()
510   {
511     return windowsMenuNode_;
512   }
513   
514   
515   private void doAbout()
516   {
517     launcher_.openAboutBox(dialogParent_);
518   }
519   
520   
521   private void doHelp()
522   {
523     // TODO
524   }
525   
526   
527   private void doPrefs()
528   {
529     prefsWindowManager_.openPrefsWindow();
530   }
531   
532   
533   /*package*/ void doSafeQuit()
534   {
535     if (!paneManager_.shutDown())
536     {
537       return;
538     }
539     if (!databaseManager_.shutDown())
540     {
541       return;
542     }
543     prefsWindowManager_.closePrefsWindow();
544     plugin_.shutDown();
545     System.exit(0);
546   }
547   
548   
549   private void doGetDBInfo()
550   {
551     listsImpl_.getSelectedDatabaseHandler().handleDatabaseGetInfo();
552   }
553   
554   
555   /*package*/ void doDefaultSongCommand()
556   {
557     if (defaultSongNode_ != null)
558     {
559       defaultSongNode_.commandInvoked(new CommandEvent(defaultSongNode_));
560     }
561   }
562   
563   
564   private void doSafeClose()
565   {
566     databaseManager_.removeDatabase(listsImpl_.getSelectedDatabase());
567   }
568   
569   
570   private void doRefreshIndex()
571   {
572     SongDatabase database = listsImpl_.getSelectedDatabase();
573     try
574     {
575       listsImpl_.refreshDatabaseIndex(database);
576     }
577     catch (SongDatabaseFailedException ex)
578     {
579       PropertySet properties = databaseManager_.getDatabaseProperties(database);
580       String name = (String)properties.getValue(DatabaseManager.DATABASE_NAME_KEY);
581       DetailedMessageDialog dialog = DetailedMessageDialog.create(
582         dialogParent_, STR_Dialog_DatabaseErrorTitle,
583         ResourceAccess.Strings.buildString("Message_FetchIndexFailed", name),
584         STR_Dialog_ErrorHeader,
585         ExceptionUtils.getDescriptionFor(ex,
586           STR_Dialog_FirstExceptionTemplate, STR_Dialog_NextExceptionTemplate),
587         null);
588       dialog.show();
589     }
590   }
591   
592   
593   private void doAddSong()
594   {
595     SongDatabase database = listsImpl_.getSelectedDatabase();
596     try
597     {
598       SongID songID = database.addEmptySong(
599         ResourceAccess.Strings.buildString("InitialSongTitle",
600           Integer.toString(++lastUntitledNumber_)), null);
601       listsImpl_.reportSongAdded(songID);
602       databaseManager_.setDatabaseDirtyBit(database);
603     }
604     catch (SongDatabaseFailedException ex)
605     {
606       DetailedMessageDialog dialog = DetailedMessageDialog.create(
607         dialogParent_, STR_Dialog_DatabaseErrorTitle,
608         STR_Message_AddSongFailed, STR_Dialog_ErrorHeader,
609         ExceptionUtils.getDescriptionFor(ex,
610           STR_Dialog_FirstExceptionTemplate, STR_Dialog_NextExceptionTemplate),
611         null);
612       dialog.show();
613     }
614   }
615   
616   
617   private void doDeleteSongs()
618   {
619     int option = JOptionPane.showConfirmDialog(dialogParent_,
620       STR_Message_ConfirmDeletePrompt, STR_Dialog_DeleteConfirmTitle,
621       JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
622     if (option == JOptionPane.YES_OPTION)
623     {
624       SongDatabase database = listsImpl_.getSelectedDatabase();
625       Set selectedSongs = listsImpl_.getSelectedSongSet();
626       for (Iterator iter = selectedSongs.iterator(); iter.hasNext(); )
627       {
628         SongID songID = (SongID)iter.next();
629         try
630         {
631           database.removeSong(songID);
632           listsImpl_.reportSongRemoved(songID);
633           databaseManager_.setDatabaseDirtyBit(database);
634         }
635         catch (SongDatabaseFailedException ex)
636         {
637           if (!iter.hasNext())
638           {
639             DetailedMessageDialog dialog = DetailedMessageDialog.create(
640               dialogParent_, STR_Dialog_DatabaseErrorTitle,
641               ResourceAccess.Strings.buildString("Message_DeleteSongFailed",
642                 listsImpl_.getNameForSongID(songID)),
643               STR_Dialog_ErrorHeader,
644               ExceptionUtils.getDescriptionFor(ex,
645                 STR_Dialog_FirstExceptionTemplate, STR_Dialog_NextExceptionTemplate),
646               null);
647             dialog.show();
648           }
649           else
650           {
651             DetailedMessageDialog dialog = DetailedMessageDialog.create(
652               dialogParent_, STR_Dialog_DatabaseErrorTitle,
653               ResourceAccess.Strings.buildString("Message_DeleteSongFailed",
654                 listsImpl_.getNameForSongID(songID)),
655               STR_Dialog_ErrorHeader,
656               ExceptionUtils.getDescriptionFor(ex,
657                 STR_Dialog_FirstExceptionTemplate, STR_Dialog_NextExceptionTemplate),
658               STR_Message_ContinuePrompt,
659               new String[]{STR_Message_ContinuePrompt_ContinueButton,
660                 STR_Message_ContinuePrompt_StopButton});
661             dialog.show();
662             if (!ObjectUtils.safeEquals(dialog.getSelection(),
663               STR_Message_ContinuePrompt_ContinueButton))
664             {
665               break;
666             }
667           }
668         }
669       }
670     }
671   }
672   
673   
674   private void doCopySongs()
675   {
676     SongDatabase database = listsImpl_.getSelectedDatabase();
677     Set selectedSongs = listsImpl_.getSelectedSongSet();
678     try
679     {
680       List list = new ArrayList();
681       for (Iterator iter = selectedSongs.iterator(); iter.hasNext(); )
682       {
683         SongID songID = (SongID)iter.next();
684         list.add(database.checkOutSong(songID));
685       }
686       if (list.isEmpty())
687       {
688         songClipboard_ = new Song[0];
689         songClipboardSource_ = null;
690       }
691       else
692       {
693         songClipboard_ = new Song[list.size()];
694         list.toArray(songClipboard_);
695         songClipboardSource_ = database;
696       }
697     }
698     catch (SongDatabaseFailedException ex)
699     {
700       DetailedMessageDialog dialog = DetailedMessageDialog.create(
701         dialogParent_, STR_Dialog_DatabaseErrorTitle,
702         STR_Message_CopySongFailed, STR_Dialog_ErrorHeader,
703         ExceptionUtils.getDescriptionFor(ex,
704           STR_Dialog_FirstExceptionTemplate, STR_Dialog_NextExceptionTemplate),
705         null);
706       dialog.show();
707     }
708   }
709   
710   
711   private void doPasteSongs()
712   {
713     SongDatabase database = listsImpl_.getSelectedDatabase();
714     try
715     {
716       for (int i=0; i<songClipboard_.length; ++i)
717       {
718         SongID songID = database.addCopyOfSong(songClipboard_[i]);
719         listsImpl_.reportSongAdded(songID);
720         databaseManager_.setDatabaseDirtyBit(database);
721       }
722     }
723     catch (SongDatabaseFailedException ex)
724     {
725       DetailedMessageDialog dialog = DetailedMessageDialog.create(
726         dialogParent_, STR_Dialog_DatabaseErrorTitle,
727         STR_Message_PasteSongFailed, STR_Dialog_ErrorHeader,
728         ExceptionUtils.getDescriptionFor(ex,
729           STR_Dialog_FirstExceptionTemplate, STR_Dialog_NextExceptionTemplate),
730         null);
731       dialog.show();
732     }
733   }
734   
735   
736   /**
737    * Returns a group-flavored CommandNode that can be filled with commands
738    * which a plugin wants to submit to the menu system.
739    * Commands are separated into categories, identified by the constants
740    * OPEN_COMMANDS, SAVE_COMMANDS, SONG_COMMANDS and TOOL_COMMANDS.
741    * See the comments for the various key constants for more information
742    * about command categories.
743    *
744    * @param category a category for the command
745    * @return a group-flavored CommandNode, or null if category not recognized
746    */
747   public CommandNode createCommandGroup(
748     CommandCategory category)
749   {
750     if (category == OPEN_COMMANDS)
751     {
752       BasicCommandNode node = new BasicGroupCommandNode();
753       openDatabaseGroup_.addChild(node);
754       return node;
755     }
756     if (category == SAVE_COMMANDS)
757     {
758       BasicCommandNode node = new BasicGroupCommandNode();
759       saveDatabaseGroup_.addChild(node);
760       return node;
761     }
762     if (category == SONG_COMMANDS)
763     {
764       BasicCommandNode node = new BasicGroupCommandNode();
765       songGroup_.addChild(node);
766       return node;
767     }
768     if (category == TOOL_COMMANDS)
769     {
770       BasicCommandNode node = new BasicGroupCommandNode();
771       publishMenuNode_.addChild(node);
772       return node;
773     }
774     return null;
775   }
776   
777   
778   /**
779    * Sets the default song command. If a command is already present, the one with
780    * the higher priority will be taken.
781    * Returns true if the command was set, or false if not.
782    *
783    * @param node a CommandNode for the default song command
784    * @param priority priority of this command
785    * @return true if successful
786    */
787   public boolean setDefaultSongCommand(
788     CommandNode node,
789     int priority)
790   {
791     if (defaultSongNode_ != null)
792     {
793       if (priority <= defaultSongPriority_)
794       {
795         return false;
796       }
797       else
798       {
799         defaultSongGroup_.removeAllChildren();
800       }
801     }
802     defaultSongNode_ = node;
803     defaultSongPriority_ = priority;
804     defaultSongGroup_.addChild(defaultSongNode_);
805     return true;
806   }
807 }