Source code: com/virtuosotechnologies/asaph/maingui/ListsImpl.java
1 /*
2 ================================================================================
3
4 FILE: ListsImpl.java
5
6 PROJECT:
7
8 Asaph
9
10 CONTENTS:
11
12 Implementation of the database and song lists.
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.Map;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.ArrayList;
49 import java.util.Set;
50 import java.util.HashSet;
51 import java.util.Collection;
52 import java.util.Arrays;
53 import java.util.Iterator;
54 import java.util.prefs.Preferences;
55 import java.awt.Component;
56 import java.awt.Graphics;
57 import java.awt.Graphics2D;
58 import java.awt.Font;
59 import java.awt.Color;
60 import java.awt.Insets;
61 import java.awt.BorderLayout;
62 import java.awt.Dimension;
63 import java.awt.GridBagLayout;
64 import java.awt.GridBagConstraints;
65 import java.awt.event.MouseAdapter;
66 import java.awt.event.MouseEvent;
67 import java.awt.event.KeyAdapter;
68 import java.awt.event.KeyEvent;
69 import javax.swing.JList;
70 import javax.swing.JSplitPane;
71 import javax.swing.JScrollPane;
72 import javax.swing.JPanel;
73 import javax.swing.JTextArea;
74 import javax.swing.JComponent;
75 import javax.swing.BorderFactory;
76 import javax.swing.ListSelectionModel;
77 import javax.swing.ListModel;
78 import javax.swing.DefaultListModel;
79 import javax.swing.DefaultListCellRenderer;
80 import javax.swing.event.ListSelectionListener;
81 import javax.swing.event.ListSelectionEvent;
82
83 import com.virtuosotechnologies.lib.util.EventBroadcastHelper;
84 import com.virtuosotechnologies.lib.util.EventAbortedException;
85 import com.virtuosotechnologies.lib.util.ExceptionUtils;
86 import com.virtuosotechnologies.lib.swing.DetailedMessageDialog;
87 import com.virtuosotechnologies.lib.swing.ScrollablePanel;
88
89 import com.virtuosotechnologies.asaph.model.SongDatabaseFailedException;
90 import com.virtuosotechnologies.asaph.model.SongDatabase;
91 import com.virtuosotechnologies.asaph.model.Song;
92 import com.virtuosotechnologies.asaph.model.SongID;
93 import com.virtuosotechnologies.asaph.model.SongIDResultSet;
94 import com.virtuosotechnologies.asaph.model.opsemantics.NopSemantics;
95 import com.virtuosotechnologies.asaph.model.opsemantics.GetFieldAsStringSemantics;
96 import com.virtuosotechnologies.asaph.model.opsemantics.GetFieldAsStringArraySemantics;
97 import com.virtuosotechnologies.asaph.model.opsemantics.PredicateSemantics;
98 import com.virtuosotechnologies.asaph.model.opsemantics.TruePredicateSemantics;
99 import com.virtuosotechnologies.asaph.modelutils.SongUtils;
100
101
102 /**
103 * Implementation of the database and song lists.
104 */
105 /*package*/ class ListsImpl
106 implements SelectionManager, ListUpdateManager
107 {
108 private static final String STR_Dialog_DatabaseErrorTitle =
109 ResourceAccess.Strings.buildString("Dialog_DatabaseErrorTitle");
110 private static final String STR_Message_FetchIndexFailed =
111 ResourceAccess.Strings.buildString("Message_FetchIndexFailed");
112 private static final String STR_Dialog_ErrorHeader =
113 ResourceAccess.Strings.buildString("Dialog_ErrorHeader");
114 private static final String STR_Dialog_FirstExceptionTemplate =
115 ResourceAccess.Strings.buildString("Dialog_FirstExceptionTemplate");
116 private static final String STR_Dialog_NextExceptionTemplate =
117 ResourceAccess.Strings.buildString("Dialog_NextExceptionTemplate");
118 private static final String STR_InfoPane_AltTitlesHeader =
119 ResourceAccess.Strings.buildString("InfoPane_AltTitlesHeader");
120
121 private static final Font INFO_FONT = new Font("Dialog", Font.PLAIN, 12);
122 private static final Color INFO_COLOR = Color.black;
123
124 private static final String DETAILS_PREFSNODE = "detailsPane";
125 private static final String SHOW_COMMENT_PREF = "showComment";
126 private static final String SHOW_AUTHOR_PREF = "showAuthor";
127 private static final String SHOW_COPYRIGHT_PREF = "showCopyright";
128 private static final String SHOW_ALTTITLES_PREF = "showAltTitles";
129
130
131 private DatabaseManagerImpl databaseManager_;
132 private CommandManagerImpl commandManager_;
133 private SongUtils songUtils_;
134
135 private DatabaseManagerImpl.Item selectedDatabase_;
136 private SongListModel.Item[] selectedSongs_;
137 private Map songListModels_;
138
139 private HeaderPane songsHeader_;
140 private JList databasesList_;
141 private JList songsList_;
142 private JPanel infoPanel_;
143 private JSplitPane listsPanel_;
144 private JSplitPane upperSplit_;
145
146 private PredicateSemantics filterPredicate_;
147
148 private Preferences detailPanePrefs_;
149 private boolean showCommentDetail_;
150 private boolean showAuthorDetail_;
151 private boolean showCopyrightDetail_;
152 private boolean showAltTitlesDetail_;
153
154 private EventBroadcastHelper broadcaster_;
155
156 private DatabaseListener listener_;
157
158 private SongListModel.SizeChangeListener songsHeaderUpdater_;
159
160
161 /**
162 * Constructor
163 */
164 /*package*/ ListsImpl(
165 final SongUtils songUtils,
166 DatabaseManagerImpl databaseManager,
167 final JComponent dialogParent)
168 {
169 songUtils_ = songUtils;
170 databaseManager_ = databaseManager;
171 selectedDatabase_ = null;
172 songListModels_ = new HashMap();
173 filterPredicate_ = new TruePredicateSemantics.DefaultImplementation();
174
175 Preferences rootPrefs = Preferences.userNodeForPackage(ListsImpl.class);
176 detailPanePrefs_ = rootPrefs.node(DETAILS_PREFSNODE);
177 showCommentDetail_ = detailPanePrefs_.getBoolean(SHOW_COMMENT_PREF, true);
178 showAuthorDetail_ = detailPanePrefs_.getBoolean(SHOW_AUTHOR_PREF, true);
179 showCopyrightDetail_ = detailPanePrefs_.getBoolean(SHOW_COPYRIGHT_PREF, false);
180 showAltTitlesDetail_ = detailPanePrefs_.getBoolean(SHOW_ALTTITLES_PREF, true);
181
182 databaseManager_.addDatabaseListener(
183 listener_ = new DatabaseListener()
184 {
185 public void databaseDirtyChanged(
186 DatabaseEvent ev)
187 {
188 }
189
190 public void databaseClosing(
191 DatabaseEvent ev)
192 throws
193 EventAbortedException
194 {
195 }
196
197 public void databaseOpened(
198 DatabaseEvent ev)
199 {
200 SongListModel songListModel = new SongListModel(ev.getSongDatabase(), songUtils,
201 new TitleSortSongComparator(), filterPredicate_);
202 songListModels_.put(ev.getSongDatabase(), songListModel);
203 try
204 {
205 songListModel.addSongIDs(ev.getSongDatabase().performOperation(
206 new NopSemantics.DefaultImplementation(), null));
207 }
208 catch (SongDatabaseFailedException ex)
209 {
210 DetailedMessageDialog dialog = DetailedMessageDialog.create(
211 dialogParent, STR_Dialog_DatabaseErrorTitle,
212 STR_Message_FetchIndexFailed, STR_Dialog_ErrorHeader,
213 ExceptionUtils.getDescriptionFor(ex, STR_Dialog_FirstExceptionTemplate,
214 STR_Dialog_NextExceptionTemplate),
215 null);
216 dialog.show();
217 }
218 }
219
220 public void databaseClosed(
221 DatabaseEvent ev)
222 {
223 SongListModel songListModel = (SongListModel)
224 songListModels_.remove(ev.getSongDatabase());
225 songListModel.clear();
226 }
227 });
228
229 // Databases list
230 databasesList_ = new JList();
231 databasesList_.setModel(databaseManager_.getSwingListModel());
232 databasesList_.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
233 databasesList_.addListSelectionListener(
234 new ListSelectionListener()
235 {
236 public void valueChanged(
237 ListSelectionEvent ev)
238 {
239 DatabaseManagerImpl.Item old = selectedDatabase_;
240 selectedDatabase_ = (DatabaseManagerImpl.Item)databasesList_.getSelectedValue();
241 broadcaster_.fireEvent(SelectionListener.DATABASE_SELECTION_CHANGED_METHOD,
242 new DatabaseSelectionEvent(this,
243 old == null ? null : old.getDatabase(),
244 selectedDatabase_ == null ? null : selectedDatabase_.getDatabase()));
245 if (selectedDatabase_ == null)
246 {
247 ListModel oldModel = songsList_.getModel();
248 if (oldModel instanceof SongListModel)
249 {
250 ((SongListModel)oldModel).setSizeChangeListener(null);
251 }
252 songsList_.setModel(new DefaultListModel());
253 songsHeader_.setString(ResourceAccess.Strings.buildString("MainGui_EmptySongsHeader"));
254 }
255 else
256 {
257 ListModel oldModel = songsList_.getModel();
258 if (oldModel instanceof SongListModel)
259 {
260 ((SongListModel)oldModel).setSizeChangeListener(null);
261 }
262 SongListModel newModel = (SongListModel)songListModels_.get(selectedDatabase_.getDatabase());
263 songsList_.setModel(newModel);
264 newModel.setSizeChangeListener(songsHeaderUpdater_);
265 songsHeader_.setString(ResourceAccess.Strings.buildString("MainGui_SongsHeader",
266 new Integer(newModel.getSize()), new Integer(newModel.getTotalSize())));
267 }
268 }
269 });
270 databasesList_.setCellRenderer(
271 new DefaultListCellRenderer()
272 {
273 public Component getListCellRendererComponent(
274 JList list,
275 Object value,
276 int index,
277 boolean isSelected,
278 boolean cellHasFocus)
279 {
280 Component ret = super.getListCellRendererComponent(
281 list, value, index, isSelected, cellHasFocus);
282 setIcon(((DatabaseManagerImpl.Item)value).getIcon());
283 return ret;
284 }
285 });
286 databasesList_.addMouseListener(
287 new MouseAdapter()
288 {
289 public void mouseClicked(
290 MouseEvent ev)
291 {
292 if (ev.getClickCount() == 2)
293 {
294 int index = databasesList_.locationToIndex(ev.getPoint());
295 if (index >= 0 && index < databasesList_.getModel().getSize())
296 {
297 databaseManager_.getDatabaseHandler(index).handleDatabaseGetInfo();
298 }
299 }
300 }
301 });
302 databasesList_.addKeyListener(
303 new KeyAdapter()
304 {
305 public void keyPressed(
306 KeyEvent ev)
307 {
308 if (ev.getKeyCode() == KeyEvent.VK_ENTER && selectedDatabase_ != null)
309 {
310 selectedDatabase_.getHandler().handleDatabaseGetInfo();
311 }
312 }
313 });
314
315 // Song list
316 songsList_ = new JList();
317 songsList_.addListSelectionListener(
318 new ListSelectionListener()
319 {
320 public void valueChanged(
321 ListSelectionEvent ev)
322 {
323 List oldSel = new ArrayList(selectedSongs_.length);
324 for (int i=0; i<selectedSongs_.length; ++i)
325 {
326 oldSel.add(selectedSongs_[i].getSongID());
327 }
328 Collection old = Arrays.asList(selectedSongs_);
329 Object[] list = songsList_.getSelectedValues();
330 selectedSongs_ = new SongListModel.Item[list.length];
331 System.arraycopy(list, 0, selectedSongs_, 0, list.length);
332 List newSel = new ArrayList(selectedSongs_.length);
333 for (int i=0; i<selectedSongs_.length; ++i)
334 {
335 newSel.add(selectedSongs_[i].getSongID());
336 }
337 SongDatabase seldb = null;
338 if (selectedDatabase_ != null)
339 {
340 seldb = selectedDatabase_.getDatabase();
341 }
342 broadcaster_.fireEvent(SelectionListener.SONG_SELECTION_CHANGED_METHOD,
343 new SongSelectionEvent(this, seldb, oldSel, newSel));
344 if (newSel.size() == 1)
345 {
346 setupInfoPane((SongID)newSel.get(0));
347 }
348 else
349 {
350 setupInfoPane(newSel.size());
351 }
352 }
353 });
354 songsList_.addMouseListener(
355 new MouseAdapter()
356 {
357 public void mouseClicked(
358 MouseEvent ev)
359 {
360 if (ev.getClickCount() == 2)
361 {
362 int index = songsList_.locationToIndex(ev.getPoint());
363 if (index >= 0 && index < songsList_.getModel().getSize() &&
364 selectedSongs_.length == 1)
365 {
366 commandManager_.doDefaultSongCommand();
367 }
368 }
369 }
370 });
371 songsList_.addKeyListener(
372 new KeyAdapter()
373 {
374 public void keyPressed(
375 KeyEvent ev)
376 {
377 if (ev.getKeyCode() == KeyEvent.VK_ENTER && selectedSongs_.length == 1)
378 {
379 commandManager_.doDefaultSongCommand();
380 }
381 }
382 });
383 selectedSongs_ = new SongListModel.Item[0];
384
385 // Details panel
386 infoPanel_ = new JPanel(new GridBagLayout());
387 infoPanel_.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
388 ScrollablePanel infoPanelWrapper = new ScrollablePanel(new BorderLayout());
389 infoPanelWrapper.add(infoPanel_, BorderLayout.NORTH);
390
391 // Assemble gui
392 JPanel databasesOuterPane = new JPanel(new BorderLayout());
393 databasesOuterPane.add(new HeaderPane(ResourceAccess.Strings.buildString(
394 "MainGui_DatabasesHeader")), BorderLayout.NORTH);
395 databasesOuterPane.add(new JScrollPane(databasesList_), BorderLayout.CENTER);
396 JPanel songsOuterPane = new JPanel(new BorderLayout());
397 songsHeader_ = new HeaderPane(ResourceAccess.Strings.buildString(
398 "MainGui_EmptySongsHeader"));
399 songsOuterPane.add(songsHeader_, BorderLayout.NORTH);
400 songsOuterPane.add(new JScrollPane(songsList_), BorderLayout.CENTER);
401 JPanel infoOuterPane = new JPanel(new BorderLayout());
402 infoOuterPane.add(new HeaderPane(ResourceAccess.Strings.buildString(
403 "MainGui_InfoHeader")), BorderLayout.NORTH);
404 infoOuterPane.add(new JScrollPane(infoPanelWrapper), BorderLayout.CENTER);
405
406 // Songs header updater
407 songsHeaderUpdater_ = new SongListModel.SizeChangeListener()
408 {
409 public void sizeChanged(
410 SongListModel model)
411 {
412 songsHeader_.setString(ResourceAccess.Strings.buildString(
413 "MainGui_SongsHeader", new Integer(model.getSize()), new Integer(model.getTotalSize())));
414 }
415 };
416
417 upperSplit_ = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
418 databasesOuterPane, songsOuterPane);
419 upperSplit_.setDividerSize(6);
420 listsPanel_ = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
421 upperSplit_, infoOuterPane);
422 listsPanel_.setDividerSize(6);
423
424 broadcaster_ = new EventBroadcastHelper(SelectionListener.class);
425
426 setupInfoPane(0);
427 }
428
429
430 private void updateInfoPane()
431 {
432 if (selectedSongs_.length == 1)
433 {
434 setupInfoPane(selectedSongs_[0].getSongID());
435 }
436 else
437 {
438 setupInfoPane(selectedSongs_.length);
439 }
440 }
441
442
443 private void setupInfoPane(
444 int numSongs)
445 {
446 infoPanel_.removeAll();
447 GridBagConstraints gbc = new GridBagConstraints();
448 gbc.gridx = 0;
449 gbc.weighty = 1;
450 gbc.weightx = 1;
451 gbc.insets = new Insets(5, 5, 0, 5);
452 gbc.anchor = GridBagConstraints.WEST;
453 gbc.fill = GridBagConstraints.HORIZONTAL;
454
455 JTextArea field = new JTextArea(ResourceAccess.Strings.buildString(
456 "InfoPane_MultiSongs", new Integer(numSongs)));
457 field.setEditable(false);
458 field.setLineWrap(true);
459 field.setWrapStyleWord(true);
460 field.setFont(INFO_FONT);
461 field.setForeground(INFO_COLOR);
462 field.setBackground(infoPanel_.getBackground());
463 infoPanel_.add(field, gbc);
464
465 infoPanel_.revalidate();
466 }
467
468
469 private void setupInfoPane(
470 SongID songID)
471 {
472 infoPanel_.removeAll();
473 if (songID != null)
474 {
475 GridBagConstraints gbc = new GridBagConstraints();
476 gbc.gridx = 0;
477 gbc.weighty = 1;
478 gbc.weightx = 1;
479 gbc.insets = new Insets(5, 5, 0, 5);
480 gbc.anchor = GridBagConstraints.WEST;
481 gbc.fill = GridBagConstraints.HORIZONTAL;
482
483 SongDatabase database = songID.getDatabase();
484 SongIDResultSet resultSet = database.createEmptyResultSet();
485 resultSet.add(songID);
486 SongIDResultSet.Entry entry = resultSet.getEntryFor(songID);
487
488 try
489 {
490 database.performOperation(
491 new GetFieldAsStringSemantics.DefaultImplementation(
492 Song.MAINTITLE_FIELD, songUtils_),
493 resultSet);
494 String str = (String)entry.getData();
495 if (str != null)
496 {
497 JTextArea field = new JTextArea(ResourceAccess.Strings.buildString(
498 "InfoPane_TitleTemplate", str));
499 field.setEditable(false);
500 field.setLineWrap(true);
501 field.setWrapStyleWord(true);
502 field.setFont(INFO_FONT);
503 field.setForeground(INFO_COLOR);
504 field.setBackground(infoPanel_.getBackground());
505 infoPanel_.add(field, gbc);
506 }
507 }
508 catch (SongDatabaseFailedException ex)
509 {
510 }
511
512 if (showCommentDetail_)
513 {
514 try
515 {
516 database.performOperation(
517 new GetFieldAsStringSemantics.DefaultImplementation(
518 Song.COMMENT_FIELD, songUtils_),
519 resultSet);
520 String str = (String)entry.getData();
521 if (str != null && str.length() > 0)
522 {
523 JTextArea field = new JTextArea(ResourceAccess.Strings.buildString(
524 "InfoPane_CommentTemplate", str));
525 field.setEditable(false);
526 field.setLineWrap(true);
527 field.setWrapStyleWord(true);
528 field.setFont(INFO_FONT);
529 field.setForeground(INFO_COLOR);
530 field.setBackground(infoPanel_.getBackground());
531 infoPanel_.add(field, gbc);
532 }
533 }
534 catch (SongDatabaseFailedException ex)
535 {
536 }
537 }
538
539 if (showAuthorDetail_)
540 {
541 try
542 {
543 database.performOperation(
544 new GetFieldAsStringSemantics.DefaultImplementation(
545 Song.AUTHOR_FIELD, songUtils_),
546 resultSet);
547 String str = (String)entry.getData();
548 if (str != null && str.length() > 0)
549 {
550 JTextArea field = new JTextArea(ResourceAccess.Strings.buildString(
551 "InfoPane_AuthorTemplate", str));
552 field.setEditable(false);
553 field.setLineWrap(true);
554 field.setWrapStyleWord(true);
555 field.setFont(INFO_FONT);
556 field.setForeground(INFO_COLOR);
557 field.setBackground(infoPanel_.getBackground());
558 infoPanel_.add(field, gbc);
559 }
560 }
561 catch (SongDatabaseFailedException ex)
562 {
563 }
564 }
565
566 if (showCopyrightDetail_)
567 {
568 try
569 {
570 database.performOperation(
571 new GetFieldAsStringSemantics.DefaultImplementation(
572 Song.COPYRIGHT_FIELD, songUtils_),
573 resultSet);
574 String str = (String)entry.getData();
575 if (str != null && str.length() > 0)
576 {
577 JTextArea field = new JTextArea(ResourceAccess.Strings.buildString(
578 "InfoPane_CopyrightTemplate", str));
579 field.setEditable(false);
580 field.setLineWrap(true);
581 field.setWrapStyleWord(true);
582 field.setFont(INFO_FONT);
583 field.setForeground(INFO_COLOR);
584 field.setBackground(infoPanel_.getBackground());
585 infoPanel_.add(field, gbc);
586 }
587 }
588 catch (SongDatabaseFailedException ex)
589 {
590 }
591 }
592
593 if (showAltTitlesDetail_)
594 {
595 try
596 {
597 database.performOperation(
598 new GetFieldAsStringArraySemantics.DefaultImplementation(
599 Song.ALTERNATETITLELIST_FIELD, songUtils_),
600 resultSet);
601 String[] array = (String[])entry.getData();
602 if (array != null && array.length > 0)
603 {
604 StringBuffer buf = new StringBuffer(STR_InfoPane_AltTitlesHeader);
605 for (int i=0; i<array.length; ++i)
606 {
607 buf.append('\n');
608 buf.append(array[i]);
609 }
610 JTextArea field = new JTextArea(new String(buf));
611 field.setEditable(false);
612 field.setLineWrap(true);
613 field.setWrapStyleWord(true);
614 field.setFont(INFO_FONT);
615 field.setForeground(INFO_COLOR);
616 field.setBackground(infoPanel_.getBackground());
617 infoPanel_.add(field, gbc);
618 }
619 }
620 catch (SongDatabaseFailedException ex)
621 {
622 }
623 }
624 }
625 infoPanel_.revalidate();
626 }
627
628
629 /*package*/ void shutdown()
630 {
631 detailPanePrefs_.putBoolean(SHOW_COMMENT_PREF, showCommentDetail_);
632 detailPanePrefs_.putBoolean(SHOW_AUTHOR_PREF, showAuthorDetail_);
633 detailPanePrefs_.putBoolean(SHOW_COPYRIGHT_PREF, showCopyrightDetail_);
634 detailPanePrefs_.putBoolean(SHOW_ALTTITLES_PREF, showAltTitlesDetail_);
635 }
636
637
638 /*package*/ boolean isShowingCommentDetail()
639 {
640 return showCommentDetail_;
641 }
642
643
644 /*package*/ boolean isShowingAuthorDetail()
645 {
646 return showAuthorDetail_;
647 }
648
649
650 /*package*/ boolean isShowingCopyrightDetail()
651 {
652 return showCopyrightDetail_;
653 }
654
655
656 /*package*/ boolean isShowingAltTitlesDetail()
657 {
658 return showAltTitlesDetail_;
659 }
660
661
662 /*package*/ void setShowingCommentDetail(
663 boolean value)
664 {
665 showCommentDetail_ = value;
666 updateInfoPane();
667 }
668
669
670 /*package*/ void setShowingAuthorDetail(
671 boolean value)
672 {
673 showAuthorDetail_ = value;
674 updateInfoPane();
675 }
676
677
678 /*package*/ void setShowingCopyrightDetail(
679 boolean value)
680 {
681 showCopyrightDetail_ = value;
682 updateInfoPane();
683 }
684
685
686 /*package*/ void setShowingAltTitlesDetail(
687 boolean value)
688 {
689 showAltTitlesDetail_ = value;
690 updateInfoPane();
691 }
692
693
694 /*package*/ void setTopSplitPanePosition(
695 int pos)
696 {
697 upperSplit_.setDividerLocation(pos);
698 }
699
700
701 /*package*/ int getTopSplitPanePosition()
702 {
703 return upperSplit_.getDividerLocation();
704 }
705
706
707 /*package*/ void setBottomSplitPanePosition(
708 int pos)
709 {
710 if (pos > 0)
711 {
712 listsPanel_.setDividerLocation(pos);
713 }
714 }
715
716
717 /*package*/ int getBottomSplitPanePosition()
718 {
719 return listsPanel_.getDividerLocation();
720 }
721
722
723 /*package*/ JComponent getJComponent()
724 {
725 return listsPanel_;
726 }
727
728
729 /*package*/ DatabaseHandler getSelectedDatabaseHandler()
730 {
731 if (selectedDatabase_ == null)
732 {
733 return null;
734 }
735 return selectedDatabase_.getHandler();
736 }
737
738
739 /*package*/ String getNameForSongID(
740 SongID id)
741 {
742 SongListModel songListModel = (SongListModel)songListModels_.get(id.getDatabase());
743 return songListModel.getNameForSongID(id);
744 }
745
746
747 /*package*/ void refreshDatabaseIndex(
748 SongDatabase database)
749 throws
750 SongDatabaseFailedException
751 {
752 SongListModel songListModel = (SongListModel)songListModels_.get(database);
753 songListModel.clear();
754 songListModel.addSongIDs(database.performOperation(
755 new NopSemantics.DefaultImplementation(), null));
756 }
757
758
759 /*package*/ void setCommandManager(
760 CommandManagerImpl commandManager)
761 {
762 commandManager_ = commandManager;
763 }
764
765
766 /*package*/ void setFilter(
767 PredicateSemantics filter)
768 {
769 if (!filter.equals(filterPredicate_))
770 {
771 filterPredicate_ = filter;
772 for (Iterator iter = songListModels_.values().iterator(); iter.hasNext(); )
773 {
774 SongListModel model = (SongListModel)iter.next();
775 model.setFilter(filter);
776 }
777 }
778 }
779
780
781 /*package*/ PredicateSemantics getFilter()
782 {
783 return filterPredicate_;
784 }
785
786
787 /*package*/ void requestFocus()
788 {
789 songsList_.requestFocus();
790 }
791
792
793 /**
794 * Get the currently selected database.
795 *
796 * @return a SongDatabase, or null for no selection
797 */
798 public SongDatabase getSelectedDatabase()
799 {
800 if (selectedDatabase_ == null)
801 {
802 return null;
803 }
804 return selectedDatabase_.getDatabase();
805 }
806
807
808 /**
809 * Get the Set of currently selected songs.
810 *
811 * @return a Set of SongIDs. Returns the empty set for no selection
812 */
813 public Set getSelectedSongSet()
814 {
815 Set set = new HashSet();
816 for (int i=0; i<selectedSongs_.length; ++i)
817 {
818 set.add(selectedSongs_[i].getSongID());
819 }
820 return set;
821 }
822
823
824 /**
825 * Select the specified database in the gui.
826 *
827 * @param database the database to select
828 * @exception IllegalArgumentException the given database is not open.
829 */
830 public void selectDatabase(
831 SongDatabase database)
832 {
833 int index = databaseManager_.findDatabaseIndex(database);
834 if (index == -1)
835 {
836 throw new IllegalArgumentException("Database not opened");
837 }
838 databasesList_.setSelectedIndex(index);
839 }
840
841
842 /**
843 * Add a SelectionListener to the main gui.
844 * Note that it is added as a weak listener, so make sure it is strongly
845 * referenced elsewhere.
846 *
847 * @param listener SelectionListener
848 */
849 public void addSelectionListener(
850 SelectionListener listener)
851 {
852 broadcaster_.addListenerWeak(listener);
853 }
854
855
856 /**
857 * Remove a SelectionListener from the main gui. Does nothing if the
858 * listener is not added.
859 *
860 * @param listener SelectionListener
861 */
862 public void removeSelectionListener(
863 SelectionListener listener)
864 {
865 broadcaster_.removeListener(listener);
866 }
867
868
869 /**
870 * Notify the main gui that a song has been added by this plugin. This
871 * causes the main gui to update its song list appropriately.
872 * It isn't strictly necessary to use this callback, but failure to
873 * do so may cause the main gui to get out of sync with the database
874 * contents until the user explicitly refreshes the index.
875 *
876 * @param songID SongID of the added song.
877 */
878 public void reportSongAdded(
879 SongID songID)
880 {
881 SongListModel songListModel = (SongListModel)songListModels_.get(songID.getDatabase());
882 if (songListModel != null)
883 {
884 int index = songListModel.addSongID(songID);
885 if (index != -1 && songID.getDatabase().equals(selectedDatabase_.getDatabase()))
886 {
887 songsList_.setSelectedIndex(index);
888 songsList_.scrollRectToVisible(songsList_.getCellBounds(index, index));
889 }
890 }
891 }
892
893
894 /**
895 * Notify the main gui that a song has been removed by this plugin. This
896 * causes the main gui to update its song list appropriately.
897 * It isn't strictly necessary to use this callback, but failure to
898 * do so may cause the main gui to get out of sync with the database
899 * contents until the user explicitly refreshes the index.
900 *
901 * @param songID SongID of the removed song.
902 */
903 public void reportSongRemoved(
904 SongID songID)
905 {
906 SongListModel songListModel = (SongListModel)songListModels_.get(songID.getDatabase());
907 if (songListModel != null)
908 {
909 songListModel.removeSongID(songID);
910 }
911 }
912
913
914 /**
915 * Notify the main gui that a song has been changed by this plugin. This
916 * causes the main gui to update its song list appropriately.
917 * It isn't strictly necessary to use this callback, but failure to
918 * do so may cause the main gui to get out of sync with the database
919 * contents until the user explicitly refreshes the index.
920 *
921 * @param songID SongID of the changed song.
922 */
923 public void reportSongChanged(
924 SongID songID)
925 {
926 SongListModel songListModel = (SongListModel)songListModels_.get(songID.getDatabase());
927 if (songListModel != null)
928 {
929 songListModel.updateSongID(songID);
930 updateInfoPane();
931 }
932 }
933
934
935 /*package*/ static class HeaderPane
936 extends JComponent
937 {
938 private String str_;
939 private static final Font font_ = new Font("Dialog", Font.BOLD, 10);
940
941
942 private HeaderPane(
943 String str)
944 {
945 str_ = str;
946 setPreferredSize(new Dimension(0, 18));
947 }
948
949 public void paintComponent(
950 Graphics g)
951 {
952 Graphics2D gr = (Graphics2D)g;
953 gr.setColor(Color.gray);
954 gr.fill3DRect(0, 0, getWidth(), getHeight(), true);
955 gr.setColor(Color.white);
956 gr.setFont(font_);
957 gr.drawString(str_, 10, 13);
958 }
959
960 /*package*/ void setString(
961 String str)
962 {
963 str_ = str;
964 repaint();
965 }
966 }
967 }