Source code: com/virtuosotechnologies/asaph/standardgui/StandardGuiPlugin.java
1 /*
2 ================================================================================
3
4 FILE: StandardGuiPlugin.java
5
6 PROJECT:
7
8 Asaph
9
10 CONTENTS:
11
12 Plugin for the standard song viewer and editor
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.print.PrinterJob;
46 import java.awt.print.PrinterException;
47 import javax.print.attribute.PrintRequestAttributeSet;
48 import javax.print.attribute.HashPrintRequestAttributeSet;
49 import java.util.Set;
50 import java.util.HashSet;
51 import java.util.Collection;
52 import java.util.Iterator;
53 import java.util.logging.Logger;
54 import java.util.logging.Level;
55 import javax.swing.JOptionPane;
56
57 import com.virtuosotechnologies.lib.command.CommandEvent;
58 import com.virtuosotechnologies.lib.basiccommand.BasicCommandNode;
59 import com.virtuosotechnologies.lib.basiccommand.BasicItemCommandNode;
60 import com.virtuosotechnologies.lib.util.ExceptionUtils;
61 import com.virtuosotechnologies.lib.util.EventAbortedException;
62 import com.virtuosotechnologies.lib.asyncjob.AsyncJobRunner;
63 import com.virtuosotechnologies.lib.asyncjob.AsyncJobListener;
64 import com.virtuosotechnologies.lib.asyncjob.ThreadWorkerAsyncJobRunner;
65 import com.virtuosotechnologies.lib.asyncjob.BasicAsyncJobListener;
66 import com.virtuosotechnologies.lib.asyncjob.AsyncJobFailedEvent;
67 import com.virtuosotechnologies.lib.asyncjob.AsyncJobException;
68 import com.virtuosotechnologies.lib.asyncjob.AsyncJob;
69 import com.virtuosotechnologies.lib.asyncjob.AbstractAsyncJob;
70 import com.virtuosotechnologies.lib.asyncjob.AsyncJobProgressReporter;
71 import com.virtuosotechnologies.lib.swing.SwingUtils;
72 import com.virtuosotechnologies.lib.swing.DetailedMessageDialog;
73 import com.virtuosotechnologies.lib.plugin.PluginLinker;
74 import com.virtuosotechnologies.lib.plugin.PluginInitializer;
75 import com.virtuosotechnologies.lib.plugin.PluginInitializerException;
76
77 import com.virtuosotechnologies.asaph.model.SongDatabase;
78 import com.virtuosotechnologies.asaph.model.SongID;
79 import com.virtuosotechnologies.asaph.model.SongDeletedException;
80 import com.virtuosotechnologies.asaph.model.SongDatabaseFailedException;
81 import com.virtuosotechnologies.asaph.maingui.CommandManager;
82 import com.virtuosotechnologies.asaph.maingui.DatabaseManager;
83 import com.virtuosotechnologies.asaph.maingui.PrefsWindowManager;
84 import com.virtuosotechnologies.asaph.maingui.GuiEnvironmentManager;
85 import com.virtuosotechnologies.asaph.maingui.ListUpdateManager;
86 import com.virtuosotechnologies.asaph.maingui.PaneManager;
87 import com.virtuosotechnologies.asaph.maingui.SelectionManager;
88 import com.virtuosotechnologies.asaph.maingui.SelectionListener;
89 import com.virtuosotechnologies.asaph.maingui.DatabaseListener;
90 import com.virtuosotechnologies.asaph.maingui.DatabaseSelectionEvent;
91 import com.virtuosotechnologies.asaph.maingui.SongSelectionEvent;
92 import com.virtuosotechnologies.asaph.maingui.DatabaseEvent;
93 import com.virtuosotechnologies.asaph.modelutils.SongUtils;
94 import com.virtuosotechnologies.asaph.modelutils.DataTransferUtils;
95 import com.virtuosotechnologies.asaph.notationmanager.NotationManager;
96
97
98 /**
99 * Plugin for the standard song viewer and editor
100 */
101 public class StandardGuiPlugin
102 implements PluginInitializer
103 {
104 private static final String STR_dialog_ErrorTitle =
105 ResourceAccess.Strings.buildString("dialog_ErrorTitle");
106 private static final String STR_dialog_ErrorsHeader =
107 ResourceAccess.Strings.buildString("dialog_ErrorsHeader");
108 private static final String STR_dialog_FirstExceptionTemplate =
109 ResourceAccess.Strings.buildString("dialog_FirstExceptionTemplate");
110 private static final String STR_dialog_NextExceptionTemplate =
111 ResourceAccess.Strings.buildString("dialog_NextExceptionTemplate");
112 private static final String STR_message_SongRemovedOnOpen =
113 ResourceAccess.Strings.buildString("message_SongRemovedOnOpen");
114 private static final String STR_message_LoadSongError =
115 ResourceAccess.Strings.buildString("message_LoadSongError");
116 private static final String STR_message_PrinterError =
117 ResourceAccess.Strings.buildString("message_PrinterError");
118 private static final String STR_message_InternalError =
119 ResourceAccess.Strings.buildString("message_InternalError");
120
121 private static final String STR_StandardGuiPlugin_OpenSongJobName =
122 ResourceAccess.Strings.buildString("StandardGuiPlugin_OpenSongJobName");
123
124 private static final int DEFAULT_SONG_COMMAND_PRIORITY = 1;
125
126
127 private Logger logger_;
128
129 private CommandManager commandManager_;
130 private DatabaseManager databaseManager_;
131 private GuiEnvironmentManager guiEnvironmentManager_;
132 private ListUpdateManager listUpdateManager_;
133 private PaneManager paneManager_;
134 private SelectionManager selectionManager_;
135 private SongUtils songUtils_;
136 private DataTransferUtils dataTransferUtils_;
137 private NotationManager notationManager_;
138
139 private EditorPrefs editorPrefs_;
140
141 private AsyncJobRunner jobRunner_;
142 private AsyncJobListener jobListener_;
143
144 private BasicCommandNode openCommand_;
145
146 private SongID curSong_;
147 private Set windows_;
148
149 private PrinterJob printJob_;
150 private PrintRequestAttributeSet printAttributes_;
151
152 private SelectionListener selectionListener_;
153 private DatabaseListener databaseListener_;
154
155
156 /**
157 * Perform first initialization of the plugin. This is called after the plugin
158 * is instantiated, but before it is asked to provide any of its API implementations.
159 * Any APIs the plugin declared it needed for initialization will be available
160 * through the linker when this method is called.
161 * <p>
162 * Plugins should perform any time-consuming initialization in this method, rather
163 * than in the constructor or static initializers, and should use this method to
164 * report any fatal errors during initialization.
165 *
166 * @param linker the linker for this plugin.
167 * @exception PluginInitializerException thrown if the plugin could not
168 * initialize itself.
169 */
170 public void initialize(
171 PluginLinker linker)
172 throws
173 PluginInitializerException
174 {
175 logger_ = Logger.getLogger("com.virtuosotechnologies.asaph.standardgui");
176
177 commandManager_ = (CommandManager)
178 linker.getAPI(CommandManager.API_NAME).getImplementation();
179 databaseManager_ = (DatabaseManager)
180 linker.getAPI(DatabaseManager.API_NAME).getImplementation();
181 guiEnvironmentManager_ = (GuiEnvironmentManager)
182 linker.getAPI(GuiEnvironmentManager.API_NAME).getImplementation();
183 listUpdateManager_ = (ListUpdateManager)
184 linker.getAPI(ListUpdateManager.API_NAME).getImplementation();
185 paneManager_ = (PaneManager)
186 linker.getAPI(PaneManager.API_NAME).getImplementation();
187 selectionManager_ = (SelectionManager)
188 linker.getAPI(SelectionManager.API_NAME).getImplementation();
189 songUtils_ = (SongUtils)
190 linker.getAPI(SongUtils.API_NAME).getImplementation();
191 dataTransferUtils_ = (DataTransferUtils)
192 linker.getAPI(DataTransferUtils.API_NAME).getImplementation();
193 notationManager_ = (NotationManager)
194 linker.getAPI(NotationManager.API_NAME).getImplementation();
195 PrefsWindowManager prefsMgr = (PrefsWindowManager)
196 linker.getAPI(PrefsWindowManager.API_NAME).getImplementation();
197
198 editorPrefs_ = new EditorPrefs();
199 prefsMgr.registerPrefsPaneProvider(editorPrefs_,
200 ResourceAccess.Strings.buildString("EditorPrefs_Title"),
201 ResourceAccess.Strings.buildString("EditorPrefs_Description"));
202
203 curSong_ = null;
204 windows_ = new HashSet();
205
206 printJob_ = PrinterJob.getPrinterJob();
207 if (printJob_ == null)
208 {
209 logger_.log(Level.WARNING, "Unable to create PrinterJob");
210 throw new PluginInitializerException(ResourceAccess.Strings.buildString("err_PrinterInitFailed"));
211 }
212 printAttributes_ = new HashPrintRequestAttributeSet();
213
214 openCommand_ = new BasicItemCommandNode()
215 {
216 public void commandInvoked(
217 CommandEvent ev)
218 {
219 doOpenSong();
220 }
221 };
222 openCommand_.setNameProperty(ResourceAccess.Strings.buildString("menu_MainSong_OpenSong"));
223 openCommand_.setDisabledProperty(true);
224
225 SwingUtils.invokeOnSwingThread(
226 new Runnable()
227 {
228 public void run()
229 {
230 commandManager_.setDefaultSongCommand(openCommand_, DEFAULT_SONG_COMMAND_PRIORITY);
231 }
232 });
233
234 jobRunner_ = new ThreadWorkerAsyncJobRunner(1);
235 guiEnvironmentManager_.registerAsyncJobRunner(jobRunner_);
236 jobRunner_.addAsyncJobListener(
237 jobListener_ = new BasicAsyncJobListener()
238 {
239 public void jobFailed(
240 final AsyncJobFailedEvent ev)
241 {
242 SwingUtils.invokeOnSwingThread(
243 new Runnable()
244 {
245 public void run()
246 {
247 AsyncJobException ex = ev.getException();
248 Throwable cause = ex.getCause();
249 if (cause instanceof SongDeletedException)
250 {
251 JOptionPane.showMessageDialog(guiEnvironmentManager_.getDialogParent(),
252 STR_message_SongRemovedOnOpen, STR_dialog_ErrorTitle,
253 JOptionPane.ERROR_MESSAGE);
254 }
255 else if (cause instanceof SongDatabaseFailedException)
256 {
257 DetailedMessageDialog dialog = DetailedMessageDialog.create(
258 guiEnvironmentManager_.getDialogParent(), STR_dialog_ErrorTitle,
259 STR_message_LoadSongError, STR_dialog_ErrorsHeader,
260 ExceptionUtils.getDescriptionFor(cause,
261 STR_dialog_FirstExceptionTemplate, STR_dialog_NextExceptionTemplate),
262 null);
263 dialog.show();
264 }
265 else if (cause instanceof PrinterException)
266 {
267 DetailedMessageDialog dialog = DetailedMessageDialog.create(
268 guiEnvironmentManager_.getDialogParent(), STR_dialog_ErrorTitle,
269 STR_message_PrinterError, STR_dialog_ErrorsHeader,
270 ExceptionUtils.getDescriptionFor(cause,
271 STR_dialog_FirstExceptionTemplate, STR_dialog_NextExceptionTemplate),
272 null);
273 dialog.show();
274 }
275 else
276 {
277 DetailedMessageDialog dialog = DetailedMessageDialog.create(
278 guiEnvironmentManager_.getDialogParent(), STR_dialog_ErrorTitle,
279 STR_message_InternalError, STR_dialog_ErrorsHeader,
280 ExceptionUtils.getDescriptionFor(cause,
281 STR_dialog_FirstExceptionTemplate, STR_dialog_NextExceptionTemplate),
282 null);
283 dialog.show();
284 }
285 }
286 });
287 }
288 });
289
290 selectionManager_.addSelectionListener(
291 selectionListener_ = new SelectionListener()
292 {
293 public void databaseSelectionChanged(
294 DatabaseSelectionEvent ev)
295 {
296 }
297
298 public void songSelectionChanged(
299 SongSelectionEvent ev)
300 {
301 handleSongSelected(ev);
302 }
303 });
304
305 databaseManager_.addDatabaseListener(
306 databaseListener_ = new DatabaseListener()
307 {
308 public void databaseDirtyChanged(
309 DatabaseEvent ev)
310 {
311 }
312
313 public void databaseClosing(
314 DatabaseEvent ev)
315 throws
316 EventAbortedException
317 {
318 handleDatabaseClosing(ev);
319 }
320
321 public void databaseOpened(
322 DatabaseEvent ev)
323 {
324 }
325
326 public void databaseClosed(
327 DatabaseEvent ev)
328 {
329 }
330 });
331
332 RenderControls.initFonts();
333 }
334
335
336 /**
337 * A plugin must implement this method to provide the implementations of the APIs
338 * that it provides. This method is called after the initialize() method.
339 * Any APIs the plugin declared it needed in to implement this API will be available
340 * through the linker when this method is called.
341 * <p>
342 * Plugins should perform any time-consuming initialization in this method, rather
343 * than in the constructor or static initializers, and should use this method to
344 * report any fatal errors during initialization.
345 *
346 * @param apiName the name of the API to implement
347 * @param linker the linker for this plugin.
348 * @return an object implementing the API.
349 * @exception PluginInitializerException thrown if the plugin could not implement the API.
350 */
351 public Object getAPIImplementation(
352 String apiName,
353 PluginLinker linker)
354 throws
355 PluginInitializerException
356 {
357 throw new PluginInitializerException();
358 }
359
360
361 /**
362 * Get PrinterJob
363 */
364 /*package*/ PrinterJob getPrinterJob()
365 {
366 return printJob_;
367 }
368
369
370 /**
371 * Get PrintRequestAttributeSet
372 */
373 /*package*/ PrintRequestAttributeSet getPrintAttributes()
374 {
375 return printAttributes_;
376 }
377
378
379 /**
380 * Register a pane
381 */
382 /*package*/ void registerWindow(
383 SongWindow window)
384 {
385 windows_.add(window);
386 }
387
388
389 /**
390 * Unregister a pane
391 */
392 /*package*/ void unregisterWindow(
393 SongWindow window)
394 {
395 windows_.remove(window);
396 }
397
398
399 /**
400 * Database closing
401 */
402 private void handleDatabaseClosing(
403 DatabaseEvent ev)
404 throws
405 EventAbortedException
406 {
407 SongDatabase database = ev.getSongDatabase();
408 for (Iterator iter = windows_.iterator(); iter.hasNext(); )
409 {
410 SongWindow window = (SongWindow)iter.next();
411 if (!window.databaseClosing(database))
412 {
413 throw new EventAbortedException();
414 }
415 }
416 }
417
418
419 /**
420 * Song selection changed
421 */
422 private void handleSongSelected(
423 SongSelectionEvent ev)
424 {
425 Collection selection = ev.getNewSelection();
426 if (selection.size() == 1)
427 {
428 openCommand_.setDisabledProperty(false);
429 curSong_ = (SongID)selection.iterator().next();
430 }
431 else
432 {
433 openCommand_.setDisabledProperty(true);
434 curSong_ = null;
435 }
436 }
437
438
439 private void doOpenSong()
440 {
441 if (curSong_ == null)
442 {
443 return;
444 }
445 final SongID selectedSong = curSong_;
446 jobRunner_.startJob(
447 new AbstractAsyncJob(STR_StandardGuiPlugin_OpenSongJobName, false, AsyncJob.INDETERMINATE_PROGRESS, null)
448 {
449 public Object run(
450 AsyncJobProgressReporter reporter)
451 throws
452 AsyncJobException
453 {
454 try
455 {
456 new SongWindow(StandardGuiPlugin.this, selectedSong, editorPrefs_,
457 databaseManager_, guiEnvironmentManager_, listUpdateManager_, paneManager_,
458 songUtils_, dataTransferUtils_, notationManager_, jobRunner_);
459 }
460 catch (SongDeletedException ex)
461 {
462 throw new AsyncJobException(ex);
463 }
464 catch (SongDatabaseFailedException ex)
465 {
466 throw new AsyncJobException(ex);
467 }
468 return null;
469 }
470 });
471 }
472 }