1 package be
.nikiroo
.fanfix
.reader
.ui
;
3 import java
.awt
.BorderLayout
;
5 import java
.awt
.event
.ActionEvent
;
6 import java
.awt
.event
.ActionListener
;
7 import java
.awt
.event
.KeyEvent
;
8 import java
.awt
.event
.WindowEvent
;
10 import java
.io
.IOException
;
11 import java
.util
.HashMap
;
12 import java
.util
.List
;
14 import java
.util
.Map
.Entry
;
16 import javax
.swing
.JFileChooser
;
17 import javax
.swing
.JFrame
;
18 import javax
.swing
.JMenu
;
19 import javax
.swing
.JMenuBar
;
20 import javax
.swing
.JMenuItem
;
21 import javax
.swing
.JOptionPane
;
22 import javax
.swing
.JPopupMenu
;
23 import javax
.swing
.SwingUtilities
;
24 import javax
.swing
.filechooser
.FileFilter
;
25 import javax
.swing
.filechooser
.FileNameExtensionFilter
;
27 import be
.nikiroo
.fanfix
.Instance
;
28 import be
.nikiroo
.fanfix
.bundles
.Config
;
29 import be
.nikiroo
.fanfix
.bundles
.StringIdGui
;
30 import be
.nikiroo
.fanfix
.bundles
.UiConfig
;
31 import be
.nikiroo
.fanfix
.data
.MetaData
;
32 import be
.nikiroo
.fanfix
.data
.Story
;
33 import be
.nikiroo
.fanfix
.library
.BasicLibrary
;
34 import be
.nikiroo
.fanfix
.library
.BasicLibrary
.Status
;
35 import be
.nikiroo
.fanfix
.library
.LocalLibrary
;
36 import be
.nikiroo
.fanfix
.output
.BasicOutput
.OutputType
;
37 import be
.nikiroo
.fanfix
.reader
.BasicReader
;
38 import be
.nikiroo
.fanfix
.reader
.ui
.GuiReaderMainPanel
.FrameHelper
;
39 import be
.nikiroo
.fanfix
.reader
.ui
.GuiReaderMainPanel
.MetaDataRunnable
;
40 import be
.nikiroo
.fanfix
.searchable
.BasicSearchable
;
41 import be
.nikiroo
.fanfix
.supported
.SupportType
;
42 import be
.nikiroo
.utils
.Progress
;
43 import be
.nikiroo
.utils
.Version
;
44 import be
.nikiroo
.utils
.ui
.ConfigEditor
;
47 * A {@link Frame} that will show a {@link GuiReaderBook} item for each
48 * {@link Story} in the main cache ({@link Instance#getCache()}), and offer a
49 * way to copy them to the {@link GuiReader} cache (
50 * {@link BasicReader#getLibrary()}), read them, delete them...
54 class GuiReaderFrame
extends JFrame
implements FrameHelper
{
55 private static final long serialVersionUID
= 1L;
56 private GuiReader reader
;
57 private GuiReaderMainPanel mainPanel
;
60 * The different modification actions you can use on {@link Story} items.
64 private enum ChangeAction
{
65 /** Change the source/type, that is, move it to another source. */
67 /** Change its name. */
69 /** Change its author. */
74 * Create a new {@link GuiReaderFrame}.
77 * the associated {@link GuiReader} to forward some commands and
78 * access its {@link LocalLibrary}
80 * the type of {@link Story} to load, or NULL for all types
82 public GuiReaderFrame(GuiReader reader
, String type
) {
83 super(getAppTitle(reader
.getLibrary().getLibraryName()));
87 mainPanel
= new GuiReaderMainPanel(this, type
);
90 setLayout(new BorderLayout());
91 add(mainPanel
, BorderLayout
.CENTER
);
95 public JPopupMenu
createBookPopup() {
96 Status status
= reader
.getLibrary().getStatus();
97 JPopupMenu popup
= new JPopupMenu();
98 popup
.add(createMenuItemOpenBook());
100 popup
.add(createMenuItemExport());
101 if (status
.isWritable()) {
102 popup
.add(createMenuItemMoveTo());
103 popup
.add(createMenuItemSetCoverForSource());
104 popup
.add(createMenuItemSetCoverForAuthor());
106 popup
.add(createMenuItemDownloadToCache());
107 popup
.add(createMenuItemClearCache());
108 if (status
.isWritable()) {
109 popup
.add(createMenuItemRedownload());
110 popup
.addSeparator();
111 popup
.add(createMenuItemRename());
112 popup
.add(createMenuItemSetAuthor());
113 popup
.addSeparator();
114 popup
.add(createMenuItemDelete());
116 popup
.addSeparator();
117 popup
.add(createMenuItemProperties());
122 public JPopupMenu
createSourceAuthorPopup() {
123 JPopupMenu popup
= new JPopupMenu();
124 popup
.add(createMenuItemOpenBook());
129 public void createMenu(Status status
) {
132 JMenuBar bar
= new JMenuBar();
134 JMenu file
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_FILE
));
135 file
.setMnemonic(KeyEvent
.VK_F
);
137 JMenuItem imprt
= new JMenuItem(
138 GuiReader
.trans(StringIdGui
.MENU_FILE_IMPORT_URL
),
140 imprt
.addActionListener(new ActionListener() {
142 public void actionPerformed(ActionEvent e
) {
143 mainPanel
.imprt(true);
146 JMenuItem imprtF
= new JMenuItem(
147 GuiReader
.trans(StringIdGui
.MENU_FILE_IMPORT_FILE
),
149 imprtF
.addActionListener(new ActionListener() {
151 public void actionPerformed(ActionEvent e
) {
152 mainPanel
.imprt(false);
155 JMenuItem exit
= new JMenuItem(
156 GuiReader
.trans(StringIdGui
.MENU_FILE_EXIT
), KeyEvent
.VK_X
);
157 exit
.addActionListener(new ActionListener() {
159 public void actionPerformed(ActionEvent e
) {
160 GuiReaderFrame
.this.dispatchEvent(new WindowEvent(
161 GuiReaderFrame
.this, WindowEvent
.WINDOW_CLOSING
));
165 file
.add(createMenuItemOpenBook());
166 file
.add(createMenuItemExport());
167 if (status
.isWritable()) {
168 file
.add(createMenuItemMoveTo());
173 file
.add(createMenuItemRename());
174 file
.add(createMenuItemSetAuthor());
177 file
.add(createMenuItemProperties());
183 JMenu edit
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_EDIT
));
184 edit
.setMnemonic(KeyEvent
.VK_E
);
186 edit
.add(createMenuItemSetCoverForSource());
187 edit
.add(createMenuItemSetCoverForAuthor());
188 edit
.add(createMenuItemDownloadToCache());
189 edit
.add(createMenuItemClearCache());
190 edit
.add(createMenuItemRedownload());
192 edit
.add(createMenuItemDelete());
196 JMenu search
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_SEARCH
));
197 search
.setMnemonic(KeyEvent
.VK_H
);
198 for (final SupportType type
: SupportType
.values()) {
199 BasicSearchable searchable
= BasicSearchable
.getSearchable(type
);
200 if (searchable
!= null) {
201 JMenuItem searchItem
= new JMenuItem(type
.getSourceName());
202 searchItem
.addActionListener(new ActionListener() {
204 public void actionPerformed(ActionEvent e
) {
205 reader
.search(type
, null, 1, 0, false);
208 search
.add(searchItem
);
214 JMenu view
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_VIEW
));
215 view
.setMnemonic(KeyEvent
.VK_V
);
216 JMenuItem vauthors
= new JMenuItem(
217 GuiReader
.trans(StringIdGui
.MENU_VIEW_AUTHOR
));
218 vauthors
.setMnemonic(KeyEvent
.VK_A
);
219 vauthors
.addActionListener(new ActionListener() {
221 public void actionPerformed(ActionEvent e
) {
222 mainPanel
.setWords(false);
223 mainPanel
.refreshBooks();
227 JMenuItem vwords
= new JMenuItem(
228 GuiReader
.trans(StringIdGui
.MENU_VIEW_WCOUNT
));
229 vwords
.setMnemonic(KeyEvent
.VK_W
);
230 vwords
.addActionListener(new ActionListener() {
232 public void actionPerformed(ActionEvent e
) {
233 mainPanel
.setWords(true);
234 mainPanel
.refreshBooks();
240 Map
<String
, List
<String
>> groupedSources
= new HashMap
<String
, List
<String
>>();
241 if (status
.isReady()) {
243 groupedSources
= reader
.getLibrary().getSourcesGrouped();
244 } catch (IOException e
) {
245 error(e
.getLocalizedMessage(), "IOException", e
);
248 JMenu sources
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_SOURCES
));
249 sources
.setMnemonic(KeyEvent
.VK_S
);
250 populateMenuSA(sources
, groupedSources
, true);
253 Map
<String
, List
<String
>> goupedAuthors
= new HashMap
<String
, List
<String
>>();
254 if (status
.isReady()) {
256 goupedAuthors
= reader
.getLibrary().getAuthorsGrouped();
257 } catch (IOException e
) {
258 error(e
.getLocalizedMessage(), "IOException", e
);
261 JMenu authors
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_AUTHORS
));
262 authors
.setMnemonic(KeyEvent
.VK_A
);
263 populateMenuSA(authors
, goupedAuthors
, false);
266 JMenu options
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_OPTIONS
));
267 options
.setMnemonic(KeyEvent
.VK_O
);
268 options
.add(createMenuItemConfig());
269 options
.add(createMenuItemUiConfig());
276 private void populateMenuSA(JMenu menu
,
277 Map
<String
, List
<String
>> groupedValues
, boolean type
) {
279 // "All" and "Listing" special items first
280 JMenuItem item
= new JMenuItem(
281 GuiReader
.trans(StringIdGui
.MENU_XXX_ALL_GROUPED
));
282 item
.addActionListener(getActionOpenList(type
, false));
284 item
= new JMenuItem(GuiReader
.trans(StringIdGui
.MENU_XXX_ALL_LISTING
));
285 item
.addActionListener(getActionOpenList(type
, true));
290 for (final String value
: groupedValues
.keySet()) {
291 List
<String
> list
= groupedValues
.get(value
);
292 if (type
&& list
.size() == 1 && list
.get(0).isEmpty()) {
293 // leaf item source/type
294 item
= new JMenuItem(
295 value
.isEmpty() ? GuiReader
296 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
)
298 item
.addActionListener(getActionOpen(value
, type
));
302 if (!type
&& groupedValues
.size() == 1) {
303 // only one group of authors
307 value
.isEmpty() ? GuiReader
308 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
)
312 for (String sub
: list
) {
313 // " " instead of "" for the visual height
314 String itemName
= sub
;
315 if (itemName
.isEmpty()) {
316 itemName
= type ?
" " : GuiReader
317 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
);
320 String actualValue
= value
;
322 if (!sub
.isEmpty()) {
323 actualValue
+= "/" + sub
;
329 item
= new JMenuItem(itemName
);
330 item
.addActionListener(getActionOpen(actualValue
, type
));
342 * Return an {@link ActionListener} that will set the given source (type) as
343 * the selected/displayed one.
346 * the type (source) to select, cannot be NULL
348 * @return the {@link ActionListener}
350 private ActionListener
getActionOpen(final String source
, final boolean type
) {
351 return new ActionListener() {
353 public void actionPerformed(ActionEvent e
) {
354 mainPanel
.removeBookPanes();
355 mainPanel
.addBookPane(source
, type
);
356 mainPanel
.refreshBooks();
361 private ActionListener
getActionOpenList(final boolean type
,
362 final boolean listMode
) {
363 return new ActionListener() {
365 public void actionPerformed(ActionEvent ae
) {
366 mainPanel
.removeBookPanes();
368 mainPanel
.addBookPane(type
, listMode
);
369 } catch (IOException e
) {
370 error(e
.getLocalizedMessage(), "IOException", e
);
372 mainPanel
.refreshBooks();
378 * Create the Fanfix Configuration menu item.
382 private JMenuItem
createMenuItemConfig() {
383 final String title
= GuiReader
.trans(StringIdGui
.TITLE_CONFIG
);
384 JMenuItem item
= new JMenuItem(title
);
385 item
.setMnemonic(KeyEvent
.VK_F
);
387 item
.addActionListener(new ActionListener() {
389 public void actionPerformed(ActionEvent e
) {
390 ConfigEditor
<Config
> ed
= new ConfigEditor
<Config
>(
391 Config
.class, Instance
.getConfig(), GuiReader
392 .trans(StringIdGui
.SUBTITLE_CONFIG
));
393 JFrame frame
= new JFrame(title
);
395 frame
.setSize(800, 600);
396 frame
.setVisible(true);
404 * Create the UI Configuration menu item.
408 private JMenuItem
createMenuItemUiConfig() {
409 final String title
= GuiReader
.trans(StringIdGui
.TITLE_CONFIG_UI
);
410 JMenuItem item
= new JMenuItem(title
);
411 item
.setMnemonic(KeyEvent
.VK_U
);
413 item
.addActionListener(new ActionListener() {
415 public void actionPerformed(ActionEvent e
) {
416 ConfigEditor
<UiConfig
> ed
= new ConfigEditor
<UiConfig
>(
417 UiConfig
.class, Instance
.getUiConfig(), GuiReader
418 .trans(StringIdGui
.SUBTITLE_CONFIG_UI
));
419 JFrame frame
= new JFrame(title
);
421 frame
.setSize(800, 600);
422 frame
.setVisible(true);
430 * Create the export menu item.
434 private JMenuItem
createMenuItemExport() {
435 final JFileChooser fc
= new JFileChooser();
436 fc
.setAcceptAllFileFilterUsed(false);
438 // Add the "ALL" filters first, then the others
439 final Map
<FileFilter
, OutputType
> otherFilters
= new HashMap
<FileFilter
, OutputType
>();
440 for (OutputType type
: OutputType
.values()) {
441 String ext
= type
.getDefaultExtension(false);
442 String desc
= type
.getDesc(false);
444 if (ext
== null || ext
.isEmpty()) {
445 fc
.addChoosableFileFilter(createAllFilter(desc
));
447 otherFilters
.put(new FileNameExtensionFilter(desc
, ext
), type
);
451 for (Entry
<FileFilter
, OutputType
> entry
: otherFilters
.entrySet()) {
452 fc
.addChoosableFileFilter(entry
.getKey());
456 JMenuItem export
= new JMenuItem(
457 GuiReader
.trans(StringIdGui
.MENU_FILE_EXPORT
), KeyEvent
.VK_S
);
458 export
.addActionListener(new ActionListener() {
460 public void actionPerformed(ActionEvent e
) {
461 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
462 if (selectedBook
!= null) {
463 fc
.showDialog(GuiReaderFrame
.this,
464 GuiReader
.trans(StringIdGui
.TITLE_SAVE
));
465 if (fc
.getSelectedFile() != null) {
466 final OutputType type
= otherFilters
.get(fc
468 final String path
= fc
.getSelectedFile()
470 + type
.getDefaultExtension(false);
471 final Progress pg
= new Progress();
472 mainPanel
.outOfUi(pg
, false, new Runnable() {
476 reader
.getLibrary().export(
477 selectedBook
.getInfo().getMeta()
478 .getLuid(), type
, path
, pg
);
479 } catch (IOException e
) {
480 Instance
.getTraceHandler().error(e
);
493 * Create a {@link FileFilter} that accepts all files and return the given
501 private FileFilter
createAllFilter(final String desc
) {
502 return new FileFilter() {
504 public String
getDescription() {
509 public boolean accept(File f
) {
516 * Create the refresh (delete cache) menu item.
520 private JMenuItem
createMenuItemClearCache() {
521 JMenuItem refresh
= new JMenuItem(
522 GuiReader
.trans(StringIdGui
.MENU_EDIT_CLEAR_CACHE
),
524 refresh
.addActionListener(new ActionListener() {
526 public void actionPerformed(ActionEvent e
) {
527 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
528 if (selectedBook
!= null) {
529 mainPanel
.outOfUi(null, false, new Runnable() {
532 reader
.clearLocalReaderCache(selectedBook
.getInfo()
533 .getMeta().getLuid());
534 selectedBook
.setCached(false);
535 GuiReaderCoverImager
.clearIcon(selectedBook
537 SwingUtilities
.invokeLater(new Runnable() {
540 selectedBook
.repaint();
553 * Create the "move to" menu item.
557 private JMenuItem
createMenuItemMoveTo() {
558 JMenu changeTo
= new JMenu(
559 GuiReader
.trans(StringIdGui
.MENU_FILE_MOVE_TO
));
560 changeTo
.setMnemonic(KeyEvent
.VK_M
);
562 Map
<String
, List
<String
>> groupedSources
= new HashMap
<String
, List
<String
>>();
564 groupedSources
= reader
.getLibrary().getSourcesGrouped();
565 } catch (IOException e
) {
566 error(e
.getLocalizedMessage(), "IOException", e
);
569 JMenuItem item
= new JMenuItem(
570 GuiReader
.trans(StringIdGui
.MENU_FILE_MOVE_TO_NEW_TYPE
));
571 item
.addActionListener(createMoveAction(ChangeAction
.SOURCE
, null));
573 changeTo
.addSeparator();
575 for (final String type
: groupedSources
.keySet()) {
576 List
<String
> list
= groupedSources
.get(type
);
577 if (list
.size() == 1 && list
.get(0).isEmpty()) {
578 item
= new JMenuItem(type
);
579 item
.addActionListener(createMoveAction(ChangeAction
.SOURCE
,
583 JMenu dir
= new JMenu(type
);
584 for (String sub
: list
) {
585 // " " instead of "" for the visual height
586 String itemName
= sub
.isEmpty() ?
" " : sub
;
587 String actualType
= type
;
588 if (!sub
.isEmpty()) {
589 actualType
+= "/" + sub
;
592 item
= new JMenuItem(itemName
);
593 item
.addActionListener(createMoveAction(
594 ChangeAction
.SOURCE
, actualType
));
605 * Create the "set author" menu item.
609 private JMenuItem
createMenuItemSetAuthor() {
610 JMenu changeTo
= new JMenu(
611 GuiReader
.trans(StringIdGui
.MENU_FILE_SET_AUTHOR
));
612 changeTo
.setMnemonic(KeyEvent
.VK_A
);
615 JMenuItem newItem
= new JMenuItem(
616 GuiReader
.trans(StringIdGui
.MENU_FILE_MOVE_TO_NEW_AUTHOR
));
617 changeTo
.add(newItem
);
618 changeTo
.addSeparator();
619 newItem
.addActionListener(createMoveAction(ChangeAction
.AUTHOR
, null));
622 Map
<String
, List
<String
>> groupedAuthors
;
625 groupedAuthors
= reader
.getLibrary().getAuthorsGrouped();
626 } catch (IOException e
) {
627 error(e
.getLocalizedMessage(), "IOException", e
);
628 groupedAuthors
= new HashMap
<String
, List
<String
>>();
632 if (groupedAuthors
.size() > 1) {
633 for (String key
: groupedAuthors
.keySet()) {
634 JMenu group
= new JMenu(key
);
635 for (String value
: groupedAuthors
.get(key
)) {
636 JMenuItem item
= new JMenuItem(
637 value
.isEmpty() ? GuiReader
638 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
)
640 item
.addActionListener(createMoveAction(
641 ChangeAction
.AUTHOR
, value
));
646 } else if (groupedAuthors
.size() == 1) {
647 for (String value
: groupedAuthors
.values().iterator().next()) {
648 JMenuItem item
= new JMenuItem(
649 value
.isEmpty() ? GuiReader
650 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
)
652 item
.addActionListener(createMoveAction(ChangeAction
.AUTHOR
,
662 * Create the "rename" menu item.
666 private JMenuItem
createMenuItemRename() {
667 JMenuItem changeTo
= new JMenuItem(
668 GuiReader
.trans(StringIdGui
.MENU_FILE_RENAME
));
669 changeTo
.setMnemonic(KeyEvent
.VK_R
);
670 changeTo
.addActionListener(createMoveAction(ChangeAction
.TITLE
, null));
674 private ActionListener
createMoveAction(final ChangeAction what
,
676 return new ActionListener() {
678 public void actionPerformed(ActionEvent e
) {
679 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
680 if (selectedBook
!= null) {
681 boolean refreshRequired
= false;
683 if (what
== ChangeAction
.SOURCE
) {
684 refreshRequired
= mainPanel
.getCurrentType();
685 } else if (what
== ChangeAction
.TITLE
) {
686 refreshRequired
= false;
687 } else if (what
== ChangeAction
.AUTHOR
) {
688 refreshRequired
= !mainPanel
.getCurrentType();
691 String changeTo
= type
;
693 MetaData meta
= selectedBook
.getInfo().getMeta();
695 if (what
== ChangeAction
.SOURCE
) {
696 init
= meta
.getSource();
697 } else if (what
== ChangeAction
.TITLE
) {
698 init
= meta
.getTitle();
699 } else if (what
== ChangeAction
.AUTHOR
) {
700 init
= meta
.getAuthor();
703 Object rep
= JOptionPane
.showInputDialog(
705 GuiReader
.trans(StringIdGui
.SUBTITLE_MOVE_TO
),
706 GuiReader
.trans(StringIdGui
.TITLE_MOVE_TO
),
707 JOptionPane
.QUESTION_MESSAGE
, null, null, init
);
713 changeTo
= rep
.toString();
716 final String fChangeTo
= changeTo
;
717 mainPanel
.outOfUi(null, refreshRequired
, new Runnable() {
720 String luid
= selectedBook
.getInfo().getMeta()
722 if (what
== ChangeAction
.SOURCE
) {
723 reader
.changeSource(luid
, fChangeTo
);
724 } else if (what
== ChangeAction
.TITLE
) {
725 reader
.changeTitle(luid
, fChangeTo
);
726 } else if (what
== ChangeAction
.AUTHOR
) {
727 reader
.changeAuthor(luid
, fChangeTo
);
730 mainPanel
.getSelectedBook().repaint();
731 mainPanel
.unsetSelectedBook();
733 SwingUtilities
.invokeLater(new Runnable() {
736 createMenu(reader
.getLibrary().getStatus());
747 * Create the re-download (then delete original) menu item.
751 private JMenuItem
createMenuItemRedownload() {
752 JMenuItem refresh
= new JMenuItem(
753 GuiReader
.trans(StringIdGui
.MENU_EDIT_REDOWNLOAD
),
755 refresh
.addActionListener(new ActionListener() {
757 public void actionPerformed(ActionEvent e
) {
758 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
759 if (selectedBook
!= null) {
760 final MetaData meta
= selectedBook
.getInfo().getMeta();
761 mainPanel
.imprt(meta
.getUrl(), new MetaDataRunnable() {
763 public void run(MetaData newMeta
) {
764 if (!newMeta
.getSource().equals(meta
.getSource())) {
765 reader
.changeSource(newMeta
.getLuid(),
769 }, GuiReader
.trans(StringIdGui
.PROGRESS_CHANGE_SOURCE
));
778 * Create the download to cache menu item.
782 private JMenuItem
createMenuItemDownloadToCache() {
783 JMenuItem refresh
= new JMenuItem(
784 GuiReader
.trans(StringIdGui
.MENU_EDIT_DOWNLOAD_TO_CACHE
),
786 refresh
.addActionListener(new ActionListener() {
788 public void actionPerformed(ActionEvent e
) {
789 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
790 if (selectedBook
!= null) {
791 mainPanel
.prefetchBook(selectedBook
);
801 * Create the delete menu item.
805 private JMenuItem
createMenuItemDelete() {
806 JMenuItem delete
= new JMenuItem(
807 GuiReader
.trans(StringIdGui
.MENU_EDIT_DELETE
), KeyEvent
.VK_D
);
808 delete
.addActionListener(new ActionListener() {
810 public void actionPerformed(ActionEvent e
) {
811 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
812 if (selectedBook
!= null
813 && selectedBook
.getInfo().getMeta() != null) {
815 final MetaData meta
= selectedBook
.getInfo().getMeta();
816 int rep
= JOptionPane
.showConfirmDialog(
818 GuiReader
.trans(StringIdGui
.SUBTITLE_DELETE
,
819 meta
.getLuid(), meta
.getTitle()),
820 GuiReader
.trans(StringIdGui
.TITLE_DELETE
),
821 JOptionPane
.OK_CANCEL_OPTION
);
823 if (rep
== JOptionPane
.OK_OPTION
) {
824 mainPanel
.outOfUi(null, true, new Runnable() {
827 reader
.delete(meta
.getLuid());
828 mainPanel
.unsetSelectedBook();
840 * Create the properties menu item.
844 private JMenuItem
createMenuItemProperties() {
845 JMenuItem delete
= new JMenuItem(
846 GuiReader
.trans(StringIdGui
.MENU_FILE_PROPERTIES
),
848 delete
.addActionListener(new ActionListener() {
850 public void actionPerformed(ActionEvent e
) {
851 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
852 if (selectedBook
!= null) {
853 mainPanel
.outOfUi(null, false, new Runnable() {
856 new GuiReaderPropertiesFrame(reader
.getLibrary(),
857 selectedBook
.getInfo().getMeta())
869 * Create the open menu item for a book, a source/type or an author.
873 public JMenuItem
createMenuItemOpenBook() {
874 JMenuItem open
= new JMenuItem(
875 GuiReader
.trans(StringIdGui
.MENU_FILE_OPEN
), KeyEvent
.VK_O
);
876 open
.addActionListener(new ActionListener() {
878 public void actionPerformed(ActionEvent e
) {
879 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
880 if (selectedBook
!= null) {
881 if (selectedBook
.getInfo().getMeta() == null) {
882 mainPanel
.removeBookPanes();
883 mainPanel
.addBookPane(selectedBook
.getInfo()
884 .getMainInfo(), mainPanel
.getCurrentType());
885 mainPanel
.refreshBooks();
887 mainPanel
.openBook(selectedBook
);
897 * Create the SetCover menu item for a book to change the linked source
902 private JMenuItem
createMenuItemSetCoverForSource() {
903 JMenuItem open
= new JMenuItem(
904 GuiReader
.trans(StringIdGui
.MENU_EDIT_SET_COVER_FOR_SOURCE
),
906 open
.addActionListener(new ActionListener() {
908 public void actionPerformed(ActionEvent ae
) {
909 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
910 if (selectedBook
!= null) {
911 BasicLibrary lib
= reader
.getLibrary();
912 String luid
= selectedBook
.getInfo().getMeta().getLuid();
913 String source
= selectedBook
.getInfo().getMeta()
917 lib
.setSourceCover(source
, luid
);
918 } catch (IOException e
) {
919 error(e
.getLocalizedMessage(), "IOException", e
);
922 GuiReaderBookInfo sourceInfo
= GuiReaderBookInfo
923 .fromSource(lib
, source
);
924 GuiReaderCoverImager
.clearIcon(sourceInfo
);
933 * Create the SetCover menu item for a book to change the linked source
938 private JMenuItem
createMenuItemSetCoverForAuthor() {
939 JMenuItem open
= new JMenuItem(
940 GuiReader
.trans(StringIdGui
.MENU_EDIT_SET_COVER_FOR_AUTHOR
),
942 open
.addActionListener(new ActionListener() {
944 public void actionPerformed(ActionEvent ae
) {
945 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
946 if (selectedBook
!= null) {
947 BasicLibrary lib
= reader
.getLibrary();
948 String luid
= selectedBook
.getInfo().getMeta().getLuid();
949 String author
= selectedBook
.getInfo().getMeta()
953 lib
.setAuthorCover(author
, luid
);
954 } catch (IOException e
) {
955 error(e
.getLocalizedMessage(), "IOException", e
);
958 GuiReaderBookInfo authorInfo
= GuiReaderBookInfo
959 .fromAuthor(lib
, author
);
960 GuiReaderCoverImager
.clearIcon(authorInfo
);
969 * Display an error message and log the linked {@link Exception}.
974 * the title of the error message
976 * the exception to log if any
978 public void error(final String message
, final String title
, Exception e
) {
979 Instance
.getTraceHandler().error(title
+ ": " + message
);
981 Instance
.getTraceHandler().error(e
);
984 SwingUtilities
.invokeLater(new Runnable() {
987 JOptionPane
.showMessageDialog(GuiReaderFrame
.this, message
,
988 title
, JOptionPane
.ERROR_MESSAGE
);
994 public GuiReader
getReader() {
999 * Return the title of the application.
1001 * @param libraryName
1002 * the name of the associated {@link BasicLibrary}, which can be
1007 static private String
getAppTitle(String libraryName
) {
1008 if (!libraryName
.isEmpty()) {
1009 return GuiReader
.trans(StringIdGui
.TITLE_LIBRARY_WITH_NAME
, Version
1010 .getCurrentVersion().toString(), libraryName
);
1013 return GuiReader
.trans(StringIdGui
.TITLE_LIBRARY
, Version
1014 .getCurrentVersion().toString());