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
.LocalLibrary
;
35 import be
.nikiroo
.fanfix
.output
.BasicOutput
.OutputType
;
36 import be
.nikiroo
.fanfix
.reader
.BasicReader
;
37 import be
.nikiroo
.fanfix
.reader
.ui
.GuiReaderMainPanel
.FrameHelper
;
38 import be
.nikiroo
.fanfix
.reader
.ui
.GuiReaderMainPanel
.StoryRunnable
;
39 import be
.nikiroo
.fanfix
.searchable
.BasicSearchable
;
40 import be
.nikiroo
.fanfix
.supported
.SupportType
;
41 import be
.nikiroo
.utils
.Progress
;
42 import be
.nikiroo
.utils
.Version
;
43 import be
.nikiroo
.utils
.ui
.ConfigEditor
;
46 * A {@link Frame} that will show a {@link GuiReaderBook} item for each
47 * {@link Story} in the main cache ({@link Instance#getCache()}), and offer a
48 * way to copy them to the {@link GuiReader} cache (
49 * {@link BasicReader#getLibrary()}), read them, delete them...
53 class GuiReaderFrame
extends JFrame
implements FrameHelper
{
54 private static final long serialVersionUID
= 1L;
55 private GuiReader reader
;
56 private GuiReaderMainPanel mainPanel
;
59 * The different modification actions you can use on {@link Story} items.
63 private enum ChangeAction
{
64 /** Change the source/type, that is, move it to another source. */
66 /** Change its name. */
68 /** Change its author. */
73 * Create a new {@link GuiReaderFrame}.
76 * the associated {@link GuiReader} to forward some commands and
77 * access its {@link LocalLibrary}
79 * the type of {@link Story} to load, or NULL for all types
81 public GuiReaderFrame(GuiReader reader
, String type
) {
82 super(getAppTitle(reader
.getLibrary().getLibraryName()));
86 mainPanel
= new GuiReaderMainPanel(this, type
);
89 setLayout(new BorderLayout());
90 add(mainPanel
, BorderLayout
.CENTER
);
94 public JPopupMenu
createBookPopup() {
95 JPopupMenu popup
= new JPopupMenu();
96 popup
.add(createMenuItemOpenBook());
98 popup
.add(createMenuItemExport());
99 popup
.add(createMenuItemMoveTo(true));
100 popup
.add(createMenuItemSetCoverForSource());
101 popup
.add(createMenuItemSetCoverForAuthor());
102 popup
.add(createMenuItemClearCache());
103 popup
.add(createMenuItemRedownload());
104 popup
.addSeparator();
105 popup
.add(createMenuItemRename(true));
106 popup
.add(createMenuItemSetAuthor(true));
107 popup
.addSeparator();
108 popup
.add(createMenuItemDelete());
109 popup
.addSeparator();
110 popup
.add(createMenuItemProperties());
115 public JPopupMenu
createSourceAuthorPopup() {
116 JPopupMenu popup
= new JPopupMenu();
117 popup
.add(createMenuItemOpenBook());
122 public void createMenu(boolean libOk
) {
125 JMenuBar bar
= new JMenuBar();
127 JMenu file
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_FILE
));
128 file
.setMnemonic(KeyEvent
.VK_F
);
130 JMenuItem imprt
= new JMenuItem(
131 GuiReader
.trans(StringIdGui
.MENU_FILE_IMPORT_URL
),
133 imprt
.addActionListener(new ActionListener() {
135 public void actionPerformed(ActionEvent e
) {
136 mainPanel
.imprt(true);
139 JMenuItem imprtF
= new JMenuItem(
140 GuiReader
.trans(StringIdGui
.MENU_FILE_IMPORT_FILE
),
142 imprtF
.addActionListener(new ActionListener() {
144 public void actionPerformed(ActionEvent e
) {
145 mainPanel
.imprt(false);
148 JMenuItem exit
= new JMenuItem(
149 GuiReader
.trans(StringIdGui
.MENU_FILE_EXIT
), KeyEvent
.VK_X
);
150 exit
.addActionListener(new ActionListener() {
152 public void actionPerformed(ActionEvent e
) {
153 GuiReaderFrame
.this.dispatchEvent(new WindowEvent(
154 GuiReaderFrame
.this, WindowEvent
.WINDOW_CLOSING
));
158 file
.add(createMenuItemOpenBook());
159 file
.add(createMenuItemExport());
160 file
.add(createMenuItemMoveTo(libOk
));
165 file
.add(createMenuItemRename(libOk
));
166 file
.add(createMenuItemSetAuthor(libOk
));
168 file
.add(createMenuItemProperties());
174 JMenu edit
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_EDIT
));
175 edit
.setMnemonic(KeyEvent
.VK_E
);
177 edit
.add(createMenuItemSetCoverForSource());
178 edit
.add(createMenuItemSetCoverForAuthor());
179 edit
.add(createMenuItemClearCache());
180 edit
.add(createMenuItemRedownload());
182 edit
.add(createMenuItemDelete());
186 JMenu search
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_SEARCH
));
187 search
.setMnemonic(KeyEvent
.VK_H
);
188 for (SupportType type
: SupportType
.values()) {
189 BasicSearchable searchable
= BasicSearchable
.getSearchable(type
);
190 if (searchable
!= null) {
191 JMenuItem searchItem
= new JMenuItem(type
.getSourceName());
192 searchItem
.addActionListener(new ActionListener() {
194 public void actionPerformed(ActionEvent e
) {
195 // TODO: open a search window
198 search
.add(searchItem
);
203 JMenu view
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_VIEW
));
204 view
.setMnemonic(KeyEvent
.VK_V
);
205 JMenuItem vauthors
= new JMenuItem(
206 GuiReader
.trans(StringIdGui
.MENU_VIEW_AUTHOR
));
207 vauthors
.setMnemonic(KeyEvent
.VK_A
);
208 vauthors
.addActionListener(new ActionListener() {
210 public void actionPerformed(ActionEvent e
) {
211 mainPanel
.setWords(false);
212 mainPanel
.refreshBooks();
216 JMenuItem vwords
= new JMenuItem(
217 GuiReader
.trans(StringIdGui
.MENU_VIEW_WCOUNT
));
218 vwords
.setMnemonic(KeyEvent
.VK_W
);
219 vwords
.addActionListener(new ActionListener() {
221 public void actionPerformed(ActionEvent e
) {
222 mainPanel
.setWords(true);
223 mainPanel
.refreshBooks();
229 Map
<String
, List
<String
>> groupedSources
= new HashMap
<String
, List
<String
>>();
231 groupedSources
= reader
.getLibrary().getSourcesGrouped();
233 JMenu sources
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_SOURCES
));
234 sources
.setMnemonic(KeyEvent
.VK_S
);
235 populateMenuSA(sources
, groupedSources
, true);
238 Map
<String
, List
<String
>> goupedAuthors
= new HashMap
<String
, List
<String
>>();
240 goupedAuthors
= reader
.getLibrary().getAuthorsGrouped();
242 JMenu authors
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_AUTHORS
));
243 authors
.setMnemonic(KeyEvent
.VK_A
);
244 populateMenuSA(authors
, goupedAuthors
, false);
247 JMenu options
= new JMenu(GuiReader
.trans(StringIdGui
.MENU_OPTIONS
));
248 options
.setMnemonic(KeyEvent
.VK_O
);
249 options
.add(createMenuItemConfig());
250 options
.add(createMenuItemUiConfig());
257 private void populateMenuSA(JMenu menu
,
258 Map
<String
, List
<String
>> groupedValues
, boolean type
) {
260 // "All" and "Listing" special items first
261 JMenuItem item
= new JMenuItem(
262 GuiReader
.trans(StringIdGui
.MENU_XXX_ALL_GROUPED
));
263 item
.addActionListener(getActionOpenList(type
, false));
265 item
= new JMenuItem(GuiReader
.trans(StringIdGui
.MENU_XXX_ALL_LISTING
));
266 item
.addActionListener(getActionOpenList(type
, true));
271 for (final String value
: groupedValues
.keySet()) {
272 List
<String
> list
= groupedValues
.get(value
);
273 if (type
&& list
.size() == 1 && list
.get(0).isEmpty()) {
274 // leaf item source/type
275 item
= new JMenuItem(
276 value
.isEmpty() ? GuiReader
277 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
)
279 item
.addActionListener(getActionOpen(value
, type
));
283 if (!type
&& groupedValues
.size() == 1) {
284 // only one group of authors
288 value
.isEmpty() ? GuiReader
289 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
)
293 for (String sub
: list
) {
294 // " " instead of "" for the visual height
295 String itemName
= sub
;
296 if (itemName
.isEmpty()) {
297 itemName
= type ?
" " : GuiReader
298 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
);
301 String actualValue
= value
;
303 if (!sub
.isEmpty()) {
304 actualValue
+= "/" + sub
;
310 item
= new JMenuItem(itemName
);
311 item
.addActionListener(getActionOpen(actualValue
, type
));
323 * Return an {@link ActionListener} that will set the given source (type) as
324 * the selected/displayed one.
327 * the type (source) to select, cannot be NULL
329 * @return the {@link ActionListener}
331 private ActionListener
getActionOpen(final String source
, final boolean type
) {
332 return new ActionListener() {
334 public void actionPerformed(ActionEvent e
) {
335 mainPanel
.removeBookPanes();
336 mainPanel
.addBookPane(source
, type
);
337 mainPanel
.refreshBooks();
342 private ActionListener
getActionOpenList(final boolean type
,
343 final boolean listMode
) {
344 return new ActionListener() {
346 public void actionPerformed(ActionEvent e
) {
347 mainPanel
.removeBookPanes();
348 mainPanel
.addBookPane(type
, listMode
);
349 mainPanel
.refreshBooks();
355 * Create the Fanfix Configuration menu item.
359 private JMenuItem
createMenuItemConfig() {
360 final String title
= GuiReader
.trans(StringIdGui
.TITLE_CONFIG
);
361 JMenuItem item
= new JMenuItem(title
);
362 item
.setMnemonic(KeyEvent
.VK_F
);
364 item
.addActionListener(new ActionListener() {
366 public void actionPerformed(ActionEvent e
) {
367 ConfigEditor
<Config
> ed
= new ConfigEditor
<Config
>(
368 Config
.class, Instance
.getConfig(), GuiReader
369 .trans(StringIdGui
.SUBTITLE_CONFIG
));
370 JFrame frame
= new JFrame(title
);
372 frame
.setSize(800, 600);
373 frame
.setVisible(true);
381 * Create the UI Configuration menu item.
385 private JMenuItem
createMenuItemUiConfig() {
386 final String title
= GuiReader
.trans(StringIdGui
.TITLE_CONFIG_UI
);
387 JMenuItem item
= new JMenuItem(title
);
388 item
.setMnemonic(KeyEvent
.VK_U
);
390 item
.addActionListener(new ActionListener() {
392 public void actionPerformed(ActionEvent e
) {
393 ConfigEditor
<UiConfig
> ed
= new ConfigEditor
<UiConfig
>(
394 UiConfig
.class, Instance
.getUiConfig(), GuiReader
395 .trans(StringIdGui
.SUBTITLE_CONFIG_UI
));
396 JFrame frame
= new JFrame(title
);
398 frame
.setSize(800, 600);
399 frame
.setVisible(true);
407 * Create the export menu item.
411 private JMenuItem
createMenuItemExport() {
412 final JFileChooser fc
= new JFileChooser();
413 fc
.setAcceptAllFileFilterUsed(false);
415 // Add the "ALL" filters first, then the others
416 final Map
<FileFilter
, OutputType
> otherFilters
= new HashMap
<FileFilter
, OutputType
>();
417 for (OutputType type
: OutputType
.values()) {
418 String ext
= type
.getDefaultExtension(false);
419 String desc
= type
.getDesc(false);
421 if (ext
== null || ext
.isEmpty()) {
422 fc
.addChoosableFileFilter(createAllFilter(desc
));
424 otherFilters
.put(new FileNameExtensionFilter(desc
, ext
), type
);
428 for (Entry
<FileFilter
, OutputType
> entry
: otherFilters
.entrySet()) {
429 fc
.addChoosableFileFilter(entry
.getKey());
433 JMenuItem export
= new JMenuItem(
434 GuiReader
.trans(StringIdGui
.MENU_FILE_EXPORT
), KeyEvent
.VK_S
);
435 export
.addActionListener(new ActionListener() {
437 public void actionPerformed(ActionEvent e
) {
438 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
439 if (selectedBook
!= null) {
440 fc
.showDialog(GuiReaderFrame
.this,
441 GuiReader
.trans(StringIdGui
.TITLE_SAVE
));
442 if (fc
.getSelectedFile() != null) {
443 final OutputType type
= otherFilters
.get(fc
.getFileFilter());
444 final String path
= fc
.getSelectedFile()
446 + type
.getDefaultExtension(false);
447 final Progress pg
= new Progress();
448 mainPanel
.outOfUi(pg
, false, new Runnable() {
452 reader
.getLibrary().export(
453 selectedBook
.getInfo().getMeta()
454 .getLuid(), type
, path
, pg
);
455 } catch (IOException e
) {
456 Instance
.getTraceHandler().error(e
);
469 * Create a {@link FileFilter} that accepts all files and return the given
477 private FileFilter
createAllFilter(final String desc
) {
478 return new FileFilter() {
480 public String
getDescription() {
485 public boolean accept(File f
) {
492 * Create the refresh (delete cache) menu item.
496 private JMenuItem
createMenuItemClearCache() {
497 JMenuItem refresh
= new JMenuItem(
498 GuiReader
.trans(StringIdGui
.MENU_EDIT_CLEAR_CACHE
),
500 refresh
.addActionListener(new ActionListener() {
502 public void actionPerformed(ActionEvent e
) {
503 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
504 if (selectedBook
!= null) {
505 mainPanel
.outOfUi(null, false, new Runnable() {
508 reader
.clearLocalReaderCache(selectedBook
.getInfo()
509 .getMeta().getLuid());
510 selectedBook
.setCached(false);
511 GuiReaderCoverImager
.clearIcon(selectedBook
513 SwingUtilities
.invokeLater(new Runnable() {
516 selectedBook
.repaint();
529 * Create the "move to" menu item.
532 * the library can be queried
536 private JMenuItem
createMenuItemMoveTo(boolean libOk
) {
537 JMenu changeTo
= new JMenu(
538 GuiReader
.trans(StringIdGui
.MENU_FILE_MOVE_TO
));
539 changeTo
.setMnemonic(KeyEvent
.VK_M
);
541 Map
<String
, List
<String
>> groupedSources
= new HashMap
<String
, List
<String
>>();
543 groupedSources
= reader
.getLibrary().getSourcesGrouped();
546 JMenuItem item
= new JMenuItem(
547 GuiReader
.trans(StringIdGui
.MENU_FILE_MOVE_TO_NEW_TYPE
));
548 item
.addActionListener(createMoveAction(ChangeAction
.SOURCE
, null));
550 changeTo
.addSeparator();
552 for (final String type
: groupedSources
.keySet()) {
553 List
<String
> list
= groupedSources
.get(type
);
554 if (list
.size() == 1 && list
.get(0).isEmpty()) {
555 item
= new JMenuItem(type
);
556 item
.addActionListener(createMoveAction(ChangeAction
.SOURCE
,
560 JMenu dir
= new JMenu(type
);
561 for (String sub
: list
) {
562 // " " instead of "" for the visual height
563 String itemName
= sub
.isEmpty() ?
" " : sub
;
564 String actualType
= type
;
565 if (!sub
.isEmpty()) {
566 actualType
+= "/" + sub
;
569 item
= new JMenuItem(itemName
);
570 item
.addActionListener(createMoveAction(
571 ChangeAction
.SOURCE
, actualType
));
582 * Create the "set author" menu item.
585 * the library can be queried
589 private JMenuItem
createMenuItemSetAuthor(boolean libOk
) {
590 JMenu changeTo
= new JMenu(
591 GuiReader
.trans(StringIdGui
.MENU_FILE_SET_AUTHOR
));
592 changeTo
.setMnemonic(KeyEvent
.VK_A
);
595 JMenuItem newItem
= new JMenuItem(
596 GuiReader
.trans(StringIdGui
.MENU_FILE_MOVE_TO_NEW_AUTHOR
));
597 changeTo
.add(newItem
);
598 changeTo
.addSeparator();
599 newItem
.addActionListener(createMoveAction(ChangeAction
.AUTHOR
, null));
603 Map
<String
, List
<String
>> groupedAuthors
= reader
.getLibrary()
604 .getAuthorsGrouped();
606 if (groupedAuthors
.size() > 1) {
607 for (String key
: groupedAuthors
.keySet()) {
608 JMenu group
= new JMenu(key
);
609 for (String value
: groupedAuthors
.get(key
)) {
610 JMenuItem item
= new JMenuItem(
611 value
.isEmpty() ? GuiReader
612 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
)
614 item
.addActionListener(createMoveAction(
615 ChangeAction
.AUTHOR
, value
));
620 } else if (groupedAuthors
.size() == 1) {
621 for (String value
: groupedAuthors
.values().iterator().next()) {
622 JMenuItem item
= new JMenuItem(
623 value
.isEmpty() ? GuiReader
624 .trans(StringIdGui
.MENU_AUTHORS_UNKNOWN
)
626 item
.addActionListener(createMoveAction(
627 ChangeAction
.AUTHOR
, value
));
637 * Create the "rename" menu item.
640 * the library can be queried
644 private JMenuItem
createMenuItemRename(
645 @SuppressWarnings("unused") boolean libOk
) {
646 JMenuItem changeTo
= new JMenuItem(
647 GuiReader
.trans(StringIdGui
.MENU_FILE_RENAME
));
648 changeTo
.setMnemonic(KeyEvent
.VK_R
);
649 changeTo
.addActionListener(createMoveAction(ChangeAction
.TITLE
, null));
653 private ActionListener
createMoveAction(final ChangeAction what
,
655 return new ActionListener() {
657 public void actionPerformed(ActionEvent e
) {
658 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
659 if (selectedBook
!= null) {
660 boolean refreshRequired
= false;
662 if (what
== ChangeAction
.SOURCE
) {
663 refreshRequired
= mainPanel
.getCurrentType();
664 } else if (what
== ChangeAction
.TITLE
) {
665 refreshRequired
= false;
666 } else if (what
== ChangeAction
.AUTHOR
) {
667 refreshRequired
= !mainPanel
.getCurrentType();
670 String changeTo
= type
;
672 MetaData meta
= selectedBook
.getInfo().getMeta();
674 if (what
== ChangeAction
.SOURCE
) {
675 init
= meta
.getSource();
676 } else if (what
== ChangeAction
.TITLE
) {
677 init
= meta
.getTitle();
678 } else if (what
== ChangeAction
.AUTHOR
) {
679 init
= meta
.getAuthor();
682 Object rep
= JOptionPane
.showInputDialog(
684 GuiReader
.trans(StringIdGui
.SUBTITLE_MOVE_TO
),
685 GuiReader
.trans(StringIdGui
.TITLE_MOVE_TO
),
686 JOptionPane
.QUESTION_MESSAGE
, null, null, init
);
692 changeTo
= rep
.toString();
695 final String fChangeTo
= changeTo
;
696 mainPanel
.outOfUi(null, refreshRequired
, new Runnable() {
699 String luid
= selectedBook
.getInfo().getMeta()
701 if (what
== ChangeAction
.SOURCE
) {
702 reader
.changeSource(luid
, fChangeTo
);
703 } else if (what
== ChangeAction
.TITLE
) {
704 reader
.changeTitle(luid
, fChangeTo
);
705 } else if (what
== ChangeAction
.AUTHOR
) {
706 reader
.changeAuthor(luid
, fChangeTo
);
709 mainPanel
.getSelectedBook().repaint();
710 mainPanel
.unsetSelectedBook();
712 SwingUtilities
.invokeLater(new Runnable() {
726 * Create the re-download (then delete original) menu item.
730 private JMenuItem
createMenuItemRedownload() {
731 JMenuItem refresh
= new JMenuItem(
732 GuiReader
.trans(StringIdGui
.MENU_EDIT_REDOWNLOAD
),
734 refresh
.addActionListener(new ActionListener() {
736 public void actionPerformed(ActionEvent e
) {
737 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
738 if (selectedBook
!= null) {
739 final MetaData meta
= selectedBook
.getInfo().getMeta();
742 new StoryRunnable() {
744 public void run(Story story
) {
745 MetaData newMeta
= story
.getMeta();
746 if (!newMeta
.getSource().equals(
748 reader
.changeSource(newMeta
.getLuid(),
754 .trans(StringIdGui
.PROGRESS_CHANGE_SOURCE
));
763 * Create the delete menu item.
767 private JMenuItem
createMenuItemDelete() {
768 JMenuItem delete
= new JMenuItem(
769 GuiReader
.trans(StringIdGui
.MENU_EDIT_DELETE
), KeyEvent
.VK_D
);
770 delete
.addActionListener(new ActionListener() {
772 public void actionPerformed(ActionEvent e
) {
773 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
774 if (selectedBook
!= null
775 && selectedBook
.getInfo().getMeta() != null) {
777 final MetaData meta
= selectedBook
.getInfo().getMeta();
778 int rep
= JOptionPane
.showConfirmDialog(
780 GuiReader
.trans(StringIdGui
.SUBTITLE_DELETE
,
781 meta
.getLuid(), meta
.getTitle()),
782 GuiReader
.trans(StringIdGui
.TITLE_DELETE
),
783 JOptionPane
.OK_CANCEL_OPTION
);
785 if (rep
== JOptionPane
.OK_OPTION
) {
786 mainPanel
.outOfUi(null, true, new Runnable() {
789 reader
.delete(meta
.getLuid());
790 mainPanel
.unsetSelectedBook();
802 * Create the properties menu item.
806 private JMenuItem
createMenuItemProperties() {
807 JMenuItem delete
= new JMenuItem(
808 GuiReader
.trans(StringIdGui
.MENU_FILE_PROPERTIES
),
810 delete
.addActionListener(new ActionListener() {
812 public void actionPerformed(ActionEvent e
) {
813 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
814 if (selectedBook
!= null) {
815 mainPanel
.outOfUi(null, false, new Runnable() {
818 new GuiReaderPropertiesFrame(reader
.getLibrary(),
819 selectedBook
.getInfo().getMeta())
831 * Create the open menu item for a book, a source/type or an author.
835 public JMenuItem
createMenuItemOpenBook() {
836 JMenuItem open
= new JMenuItem(
837 GuiReader
.trans(StringIdGui
.MENU_FILE_OPEN
), KeyEvent
.VK_O
);
838 open
.addActionListener(new ActionListener() {
840 public void actionPerformed(ActionEvent e
) {
841 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
842 if (selectedBook
!= null) {
843 if (selectedBook
.getInfo().getMeta() == null) {
844 mainPanel
.removeBookPanes();
845 mainPanel
.addBookPane(selectedBook
.getInfo()
846 .getMainInfo(), mainPanel
.getCurrentType());
847 mainPanel
.refreshBooks();
849 mainPanel
.openBook(selectedBook
);
859 * Create the SetCover menu item for a book to change the linked source
864 private JMenuItem
createMenuItemSetCoverForSource() {
865 JMenuItem open
= new JMenuItem(
866 GuiReader
.trans(StringIdGui
.MENU_EDIT_SET_COVER_FOR_SOURCE
),
868 open
.addActionListener(new ActionListener() {
870 public void actionPerformed(ActionEvent e
) {
871 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
872 if (selectedBook
!= null) {
873 BasicLibrary lib
= reader
.getLibrary();
874 String luid
= selectedBook
.getInfo().getMeta().getLuid();
875 String source
= selectedBook
.getInfo().getMeta()
878 lib
.setSourceCover(source
, luid
);
880 GuiReaderBookInfo sourceInfo
= GuiReaderBookInfo
881 .fromSource(lib
, source
);
882 GuiReaderCoverImager
.clearIcon(sourceInfo
);
891 * Create the SetCover menu item for a book to change the linked source
896 private JMenuItem
createMenuItemSetCoverForAuthor() {
897 JMenuItem open
= new JMenuItem(
898 GuiReader
.trans(StringIdGui
.MENU_EDIT_SET_COVER_FOR_AUTHOR
),
900 open
.addActionListener(new ActionListener() {
902 public void actionPerformed(ActionEvent e
) {
903 final GuiReaderBook selectedBook
= mainPanel
.getSelectedBook();
904 if (selectedBook
!= null) {
905 BasicLibrary lib
= reader
.getLibrary();
906 String luid
= selectedBook
.getInfo().getMeta().getLuid();
907 String author
= selectedBook
.getInfo().getMeta()
910 lib
.setAuthorCover(author
, luid
);
912 GuiReaderBookInfo authorInfo
= GuiReaderBookInfo
913 .fromAuthor(lib
, author
);
914 GuiReaderCoverImager
.clearIcon(authorInfo
);
923 * Display an error message and log the linked {@link Exception}.
928 * the title of the error message
930 * the exception to log if any
932 public void error(final String message
, final String title
, Exception e
) {
933 Instance
.getTraceHandler().error(title
+ ": " + message
);
935 Instance
.getTraceHandler().error(e
);
938 SwingUtilities
.invokeLater(new Runnable() {
941 JOptionPane
.showMessageDialog(GuiReaderFrame
.this, message
,
942 title
, JOptionPane
.ERROR_MESSAGE
);
948 public GuiReader
getReader() {
953 * Return the title of the application.
956 * the name of the associated {@link BasicLibrary}, which can be
961 static private String
getAppTitle(String libraryName
) {
962 if (!libraryName
.isEmpty()) {
963 return GuiReader
.trans(StringIdGui
.TITLE_LIBRARY_WITH_NAME
, Version
964 .getCurrentVersion().toString(), libraryName
);
967 return GuiReader
.trans(StringIdGui
.TITLE_LIBRARY
, Version
968 .getCurrentVersion().toString());