gui: French translation
[fanfix.git] / src / be / nikiroo / fanfix / reader / ui / GuiReaderFrame.java
1 package be.nikiroo.fanfix.reader.ui;
2
3 import java.awt.BorderLayout;
4 import java.awt.Frame;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.awt.event.KeyEvent;
8 import java.awt.event.WindowEvent;
9 import java.io.File;
10 import java.io.IOException;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Map.Entry;
15
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;
26
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.utils.Progress;
40 import be.nikiroo.utils.Version;
41 import be.nikiroo.utils.ui.ConfigEditor;
42
43 /**
44 * A {@link Frame} that will show a {@link GuiReaderBook} item for each
45 * {@link Story} in the main cache ({@link Instance#getCache()}), and offer a
46 * way to copy them to the {@link GuiReader} cache (
47 * {@link BasicReader#getLibrary()}), read them, delete them...
48 *
49 * @author niki
50 */
51 class GuiReaderFrame extends JFrame implements FrameHelper {
52 private static final long serialVersionUID = 1L;
53 private GuiReader reader;
54 private GuiReaderMainPanel mainPanel;
55
56 /**
57 * The different modification actions you can use on {@link Story} items.
58 *
59 * @author niki
60 */
61 private enum ChangeAction {
62 /** Change the source/type, that is, move it to another source. */
63 SOURCE,
64 /** Change its name. */
65 TITLE,
66 /** Change its author. */
67 AUTHOR
68 }
69
70 /**
71 * Create a new {@link GuiReaderFrame}.
72 *
73 * @param reader
74 * the associated {@link GuiReader} to forward some commands and
75 * access its {@link LocalLibrary}
76 * @param type
77 * the type of {@link Story} to load, or NULL for all types
78 */
79 public GuiReaderFrame(GuiReader reader, String type) {
80 super(getAppTitle(reader.getLibrary().getLibraryName()));
81
82 this.reader = reader;
83
84 mainPanel = new GuiReaderMainPanel(this, type);
85
86 setSize(800, 600);
87 setLayout(new BorderLayout());
88 add(mainPanel, BorderLayout.CENTER);
89 }
90
91 @Override
92 public JPopupMenu createBookPopup() {
93 JPopupMenu popup = new JPopupMenu();
94 popup.add(createMenuItemOpenBook());
95 popup.addSeparator();
96 popup.add(createMenuItemExport());
97 popup.add(createMenuItemMoveTo(true));
98 popup.add(createMenuItemSetCoverForSource());
99 popup.add(createMenuItemSetCoverForAuthor());
100 popup.add(createMenuItemClearCache());
101 popup.add(createMenuItemRedownload());
102 popup.addSeparator();
103 popup.add(createMenuItemRename(true));
104 popup.add(createMenuItemSetAuthor(true));
105 popup.addSeparator();
106 popup.add(createMenuItemDelete());
107 popup.addSeparator();
108 popup.add(createMenuItemProperties());
109 return popup;
110 }
111
112 @Override
113 public JPopupMenu createSourceAuthorPopup() {
114 JPopupMenu popup = new JPopupMenu();
115 popup.add(createMenuItemOpenBook());
116 return popup;
117 }
118
119 @Override
120 public void createMenu(boolean libOk) {
121 invalidate();
122
123 JMenuBar bar = new JMenuBar();
124
125 JMenu file = new JMenu(GuiReader.trans(StringIdGui.MENU_FILE));
126 file.setMnemonic(KeyEvent.VK_F);
127
128 JMenuItem imprt = new JMenuItem(
129 GuiReader.trans(StringIdGui.MENU_FILE_IMPORT_URL),
130 KeyEvent.VK_U);
131 imprt.addActionListener(new ActionListener() {
132 @Override
133 public void actionPerformed(ActionEvent e) {
134 mainPanel.imprt(true);
135 }
136 });
137 JMenuItem imprtF = new JMenuItem(
138 GuiReader.trans(StringIdGui.MENU_FILE_IMPORT_FILE),
139 KeyEvent.VK_F);
140 imprtF.addActionListener(new ActionListener() {
141 @Override
142 public void actionPerformed(ActionEvent e) {
143 mainPanel.imprt(false);
144 }
145 });
146 JMenuItem exit = new JMenuItem(
147 GuiReader.trans(StringIdGui.MENU_FILE_EXIT), KeyEvent.VK_X);
148 exit.addActionListener(new ActionListener() {
149 @Override
150 public void actionPerformed(ActionEvent e) {
151 GuiReaderFrame.this.dispatchEvent(new WindowEvent(
152 GuiReaderFrame.this, WindowEvent.WINDOW_CLOSING));
153 }
154 });
155
156 file.add(createMenuItemOpenBook());
157 file.add(createMenuItemExport());
158 file.add(createMenuItemMoveTo(libOk));
159 file.addSeparator();
160 file.add(imprt);
161 file.add(imprtF);
162 file.addSeparator();
163 file.add(createMenuItemRename(libOk));
164 file.add(createMenuItemSetAuthor(libOk));
165 file.addSeparator();
166 file.add(createMenuItemProperties());
167 file.addSeparator();
168 file.add(exit);
169
170 bar.add(file);
171
172 JMenu edit = new JMenu(GuiReader.trans(StringIdGui.MENU_EDIT));
173 edit.setMnemonic(KeyEvent.VK_E);
174
175 edit.add(createMenuItemSetCoverForSource());
176 edit.add(createMenuItemSetCoverForAuthor());
177 edit.add(createMenuItemClearCache());
178 edit.add(createMenuItemRedownload());
179 edit.addSeparator();
180 edit.add(createMenuItemDelete());
181
182 bar.add(edit);
183
184 JMenu view = new JMenu(GuiReader.trans(StringIdGui.MENU_VIEW));
185 view.setMnemonic(KeyEvent.VK_V);
186 JMenuItem vauthors = new JMenuItem(
187 GuiReader.trans(StringIdGui.MENU_VIEW_AUTHOR));
188 vauthors.setMnemonic(KeyEvent.VK_A);
189 vauthors.addActionListener(new ActionListener() {
190 @Override
191 public void actionPerformed(ActionEvent e) {
192 mainPanel.setWords(false);
193 mainPanel.refreshBooks();
194 }
195 });
196 view.add(vauthors);
197 JMenuItem vwords = new JMenuItem(
198 GuiReader.trans(StringIdGui.MENU_VIEW_WCOUNT));
199 vwords.setMnemonic(KeyEvent.VK_W);
200 vwords.addActionListener(new ActionListener() {
201 @Override
202 public void actionPerformed(ActionEvent e) {
203 mainPanel.setWords(true);
204 mainPanel.refreshBooks();
205 }
206 });
207 view.add(vwords);
208 bar.add(view);
209
210 Map<String, List<String>> groupedSources = new HashMap<String, List<String>>();
211 if (libOk) {
212 groupedSources = reader.getLibrary().getSourcesGrouped();
213 }
214 JMenu sources = new JMenu(GuiReader.trans(StringIdGui.MENU_SOURCES));
215 sources.setMnemonic(KeyEvent.VK_S);
216 populateMenuSA(sources, groupedSources, true);
217 bar.add(sources);
218
219 Map<String, List<String>> goupedAuthors = new HashMap<String, List<String>>();
220 if (libOk) {
221 goupedAuthors = reader.getLibrary().getAuthorsGrouped();
222 }
223 JMenu authors = new JMenu(GuiReader.trans(StringIdGui.MENU_AUTHORS));
224 authors.setMnemonic(KeyEvent.VK_A);
225 populateMenuSA(authors, goupedAuthors, false);
226 bar.add(authors);
227
228 JMenu options = new JMenu(GuiReader.trans(StringIdGui.MENU_OPTIONS));
229 options.setMnemonic(KeyEvent.VK_O);
230 options.add(createMenuItemConfig());
231 options.add(createMenuItemUiConfig());
232 bar.add(options);
233
234 setJMenuBar(bar);
235 }
236
237 // "" = [unknown]
238 private void populateMenuSA(JMenu menu,
239 Map<String, List<String>> groupedValues, boolean type) {
240
241 // "All" and "Listing" special items first
242 JMenuItem item = new JMenuItem(GuiReader.trans(StringIdGui.MENU_XXX_ALL_GROUPED));
243 item.addActionListener(getActionOpenList(type, false));
244 menu.add(item);
245 item = new JMenuItem(GuiReader.trans(StringIdGui.MENU_XXX_ALL_LISTING));
246 item.addActionListener(getActionOpenList(type, true));
247 menu.add(item);
248
249 menu.addSeparator();
250
251 for (final String value : groupedValues.keySet()) {
252 List<String> list = groupedValues.get(value);
253 if (type && list.size() == 1 && list.get(0).isEmpty()) {
254 // leaf item source/type
255 item = new JMenuItem(value.isEmpty() ? GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN) : value);
256 item.addActionListener(getActionOpen(value, type));
257 menu.add(item);
258 } else {
259 JMenu dir;
260 if (!type && groupedValues.size() == 1) {
261 // only one group of authors
262 dir = menu;
263 } else {
264 dir = new JMenu(value.isEmpty() ? GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN) : value);
265 }
266
267 for (String sub : list) {
268 // " " instead of "" for the visual height
269 String itemName = sub;
270 if (itemName.isEmpty()) {
271 itemName = type ? " " : GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN);
272 }
273
274 String actualValue = value;
275 if (type) {
276 if (!sub.isEmpty()) {
277 actualValue += "/" + sub;
278 }
279 } else {
280 actualValue = sub;
281 }
282
283 item = new JMenuItem(itemName);
284 item.addActionListener(getActionOpen(actualValue, type));
285 dir.add(item);
286 }
287
288 if (menu != dir) {
289 menu.add(dir);
290 }
291 }
292 }
293 }
294
295 /**
296 * Return an {@link ActionListener} that will set the given source (type) as
297 * the selected/displayed one.
298 *
299 * @param type
300 * the type (source) to select, cannot be NULL
301 *
302 * @return the {@link ActionListener}
303 */
304 private ActionListener getActionOpen(final String source, final boolean type) {
305 return new ActionListener() {
306 @Override
307 public void actionPerformed(ActionEvent e) {
308 mainPanel.removeBookPanes();
309 mainPanel.addBookPane(source, type);
310 mainPanel.refreshBooks();
311 }
312 };
313 }
314
315 private ActionListener getActionOpenList(final boolean type,
316 final boolean listMode) {
317 return new ActionListener() {
318 @Override
319 public void actionPerformed(ActionEvent e) {
320 mainPanel.removeBookPanes();
321 mainPanel.addBookPane(type, listMode);
322 mainPanel.refreshBooks();
323 }
324 };
325 }
326
327 /**
328 * Create the Fanfix Configuration menu item.
329 *
330 * @return the item
331 */
332 private JMenuItem createMenuItemConfig() {
333 final String title = GuiReader.trans(StringIdGui.TITLE_CONFIG);
334 JMenuItem item = new JMenuItem(title);
335 item.setMnemonic(KeyEvent.VK_F);
336
337 item.addActionListener(new ActionListener() {
338 @Override
339 public void actionPerformed(ActionEvent e) {
340 ConfigEditor<Config> ed = new ConfigEditor<Config>(
341 Config.class, Instance.getConfig(),
342 GuiReader.trans(StringIdGui.SUBTITLE_CONFIG));
343 JFrame frame = new JFrame(title);
344 frame.add(ed);
345 frame.setSize(800, 600);
346 frame.setVisible(true);
347 }
348 });
349
350 return item;
351 }
352
353 /**
354 * Create the UI Configuration menu item.
355 *
356 * @return the item
357 */
358 private JMenuItem createMenuItemUiConfig() {
359 final String title = GuiReader.trans(StringIdGui.TITLE_CONFIG_UI);
360 JMenuItem item = new JMenuItem(title);
361 item.setMnemonic(KeyEvent.VK_U);
362
363 item.addActionListener(new ActionListener() {
364 @Override
365 public void actionPerformed(ActionEvent e) {
366 ConfigEditor<UiConfig> ed = new ConfigEditor<UiConfig>(
367 UiConfig.class, Instance.getUiConfig(),
368 GuiReader.trans(StringIdGui.SUBTITLE_CONFIG_UI));
369 JFrame frame = new JFrame(title);
370 frame.add(ed);
371 frame.setSize(800, 600);
372 frame.setVisible(true);
373 }
374 });
375
376 return item;
377 }
378
379 /**
380 * Create the export menu item.
381 *
382 * @return the item
383 */
384 private JMenuItem createMenuItemExport() {
385 final JFileChooser fc = new JFileChooser();
386 fc.setAcceptAllFileFilterUsed(false);
387
388 final Map<FileFilter, OutputType> filters = new HashMap<FileFilter, OutputType>();
389 for (OutputType type : OutputType.values()) {
390 String ext = type.getDefaultExtension(false);
391 String desc = type.getDesc(false);
392
393 if (ext == null || ext.isEmpty()) {
394 filters.put(createAllFilter(desc), type);
395 } else {
396 filters.put(new FileNameExtensionFilter(desc, ext), type);
397 }
398 }
399
400 // First the "ALL" filters, then, the extension filters
401 for (Entry<FileFilter, OutputType> entry : filters.entrySet()) {
402 if (!(entry.getKey() instanceof FileNameExtensionFilter)) {
403 fc.addChoosableFileFilter(entry.getKey());
404 }
405 }
406 for (Entry<FileFilter, OutputType> entry : filters.entrySet()) {
407 if (entry.getKey() instanceof FileNameExtensionFilter) {
408 fc.addChoosableFileFilter(entry.getKey());
409 }
410 }
411 //
412
413 JMenuItem export = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_EXPORT), KeyEvent.VK_S);
414 export.addActionListener(new ActionListener() {
415 @Override
416 public void actionPerformed(ActionEvent e) {
417 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
418 if (selectedBook != null) {
419 fc.showDialog(GuiReaderFrame.this, GuiReader.trans(StringIdGui.TITLE_SAVE));
420 if (fc.getSelectedFile() != null) {
421 final OutputType type = filters.get(fc.getFileFilter());
422 final String path = fc.getSelectedFile()
423 .getAbsolutePath()
424 + type.getDefaultExtension(false);
425 final Progress pg = new Progress();
426 mainPanel.outOfUi(pg, false, new Runnable() {
427 @Override
428 public void run() {
429 try {
430 reader.getLibrary().export(
431 selectedBook.getInfo().getMeta()
432 .getLuid(), type, path, pg);
433 } catch (IOException e) {
434 Instance.getTraceHandler().error(e);
435 }
436 }
437 });
438 }
439 }
440 }
441 });
442
443 return export;
444 }
445
446 /**
447 * Create a {@link FileFilter} that accepts all files and return the given
448 * description.
449 *
450 * @param desc
451 * the description
452 *
453 * @return the filter
454 */
455 private FileFilter createAllFilter(final String desc) {
456 return new FileFilter() {
457 @Override
458 public String getDescription() {
459 return desc;
460 }
461
462 @Override
463 public boolean accept(File f) {
464 return true;
465 }
466 };
467 }
468
469 /**
470 * Create the refresh (delete cache) menu item.
471 *
472 * @return the item
473 */
474 private JMenuItem createMenuItemClearCache() {
475 JMenuItem refresh = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_CLEAR_CACHE), KeyEvent.VK_C);
476 refresh.addActionListener(new ActionListener() {
477 @Override
478 public void actionPerformed(ActionEvent e) {
479 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
480 if (selectedBook != null) {
481 mainPanel.outOfUi(null, false, new Runnable() {
482 @Override
483 public void run() {
484 reader.clearLocalReaderCache(selectedBook.getInfo()
485 .getMeta().getLuid());
486 selectedBook.setCached(false);
487 GuiReaderCoverImager.clearIcon(selectedBook
488 .getInfo());
489 SwingUtilities.invokeLater(new Runnable() {
490 @Override
491 public void run() {
492 selectedBook.repaint();
493 }
494 });
495 }
496 });
497 }
498 }
499 });
500
501 return refresh;
502 }
503
504 /**
505 * Create the "move to" menu item.
506 *
507 * @param libOk
508 * the library can be queried
509 *
510 * @return the item
511 */
512 private JMenuItem createMenuItemMoveTo(boolean libOk) {
513 JMenu changeTo = new JMenu(GuiReader.trans(StringIdGui.MENU_FILE_MOVE_TO));
514 changeTo.setMnemonic(KeyEvent.VK_M);
515
516 Map<String, List<String>> groupedSources = new HashMap<String, List<String>>();
517 if (libOk) {
518 groupedSources = reader.getLibrary().getSourcesGrouped();
519 }
520
521 JMenuItem item = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_MOVE_TO_NEW_TYPE));
522 item.addActionListener(createMoveAction(ChangeAction.SOURCE, null));
523 changeTo.add(item);
524 changeTo.addSeparator();
525
526 for (final String type : groupedSources.keySet()) {
527 List<String> list = groupedSources.get(type);
528 if (list.size() == 1 && list.get(0).isEmpty()) {
529 item = new JMenuItem(type);
530 item.addActionListener(createMoveAction(ChangeAction.SOURCE,
531 type));
532 changeTo.add(item);
533 } else {
534 JMenu dir = new JMenu(type);
535 for (String sub : list) {
536 // " " instead of "" for the visual height
537 String itemName = sub.isEmpty() ? " " : sub;
538 String actualType = type;
539 if (!sub.isEmpty()) {
540 actualType += "/" + sub;
541 }
542
543 item = new JMenuItem(itemName);
544 item.addActionListener(createMoveAction(
545 ChangeAction.SOURCE, actualType));
546 dir.add(item);
547 }
548 changeTo.add(dir);
549 }
550 }
551
552 return changeTo;
553 }
554
555 /**
556 * Create the "set author" menu item.
557 *
558 * @param libOk
559 * the library can be queried
560 *
561 * @return the item
562 */
563 private JMenuItem createMenuItemSetAuthor(boolean libOk) {
564 JMenu changeTo = new JMenu(GuiReader.trans(StringIdGui.MENU_FILE_SET_AUTHOR));
565 changeTo.setMnemonic(KeyEvent.VK_A);
566
567 // New author
568 JMenuItem newItem = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_MOVE_TO_NEW_AUTHOR));
569 changeTo.add(newItem);
570 changeTo.addSeparator();
571 newItem.addActionListener(createMoveAction(ChangeAction.AUTHOR, null));
572
573 // Existing authors
574 if (libOk) {
575 Map<String, List<String>> groupedAuthors = reader.getLibrary()
576 .getAuthorsGrouped();
577
578 if (groupedAuthors.size() > 1) {
579 for (String key : groupedAuthors.keySet()) {
580 JMenu group = new JMenu(key);
581 for (String value : groupedAuthors.get(key)) {
582 JMenuItem item = new JMenuItem(
583 value.isEmpty() ? GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN) : value);
584 item.addActionListener(createMoveAction(
585 ChangeAction.AUTHOR, value));
586 group.add(item);
587 }
588 changeTo.add(group);
589 }
590 } else if (groupedAuthors.size() == 1) {
591 for (String value : groupedAuthors.values().iterator().next()) {
592 JMenuItem item = new JMenuItem(
593 value.isEmpty() ? GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN) : value);
594 item.addActionListener(createMoveAction(
595 ChangeAction.AUTHOR, value));
596 changeTo.add(item);
597 }
598 }
599 }
600
601 return changeTo;
602 }
603
604 /**
605 * Create the "rename" menu item.
606 *
607 * @param libOk
608 * the library can be queried
609 *
610 * @return the item
611 */
612 private JMenuItem createMenuItemRename(
613 @SuppressWarnings("unused") boolean libOk) {
614 JMenuItem changeTo = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_RENAME));
615 changeTo.setMnemonic(KeyEvent.VK_R);
616 changeTo.addActionListener(createMoveAction(ChangeAction.TITLE, null));
617 return changeTo;
618 }
619
620 private ActionListener createMoveAction(final ChangeAction what,
621 final String type) {
622 return new ActionListener() {
623 @Override
624 public void actionPerformed(ActionEvent e) {
625 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
626 if (selectedBook != null) {
627 boolean refreshRequired = false;
628
629 if (what == ChangeAction.SOURCE) {
630 refreshRequired = mainPanel.getCurrentType();
631 } else if (what == ChangeAction.TITLE) {
632 refreshRequired = false;
633 } else if (what == ChangeAction.AUTHOR) {
634 refreshRequired = !mainPanel.getCurrentType();
635 }
636
637 String changeTo = type;
638 if (type == null) {
639 MetaData meta = selectedBook.getInfo().getMeta();
640 String init = "";
641 if (what == ChangeAction.SOURCE) {
642 init = meta.getSource();
643 } else if (what == ChangeAction.TITLE) {
644 init = meta.getTitle();
645 } else if (what == ChangeAction.AUTHOR) {
646 init = meta.getAuthor();
647 }
648
649 Object rep = JOptionPane.showInputDialog(
650 GuiReaderFrame.this, GuiReader.trans(StringIdGui.SUBTITLE_MOVE_TO),
651 GuiReader.trans(StringIdGui.TITLE_MOVE_TO), JOptionPane.QUESTION_MESSAGE,
652 null, null, init);
653
654 if (rep == null) {
655 return;
656 }
657
658 changeTo = rep.toString();
659 }
660
661 final String fChangeTo = changeTo;
662 mainPanel.outOfUi(null, refreshRequired, new Runnable() {
663 @Override
664 public void run() {
665 String luid = selectedBook.getInfo().getMeta()
666 .getLuid();
667 if (what == ChangeAction.SOURCE) {
668 reader.changeSource(luid, fChangeTo);
669 } else if (what == ChangeAction.TITLE) {
670 reader.changeTitle(luid, fChangeTo);
671 } else if (what == ChangeAction.AUTHOR) {
672 reader.changeAuthor(luid, fChangeTo);
673 }
674
675 mainPanel.getSelectedBook().repaint();
676 mainPanel.unsetSelectedBook();
677
678 SwingUtilities.invokeLater(new Runnable() {
679 @Override
680 public void run() {
681 createMenu(true);
682 }
683 });
684 }
685 });
686 }
687 }
688 };
689 }
690
691 /**
692 * Create the re-download (then delete original) menu item.
693 *
694 * @return the item
695 */
696 private JMenuItem createMenuItemRedownload() {
697 JMenuItem refresh = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_REDOWNLOAD), KeyEvent.VK_R);
698 refresh.addActionListener(new ActionListener() {
699 @Override
700 public void actionPerformed(ActionEvent e) {
701 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
702 if (selectedBook != null) {
703 final MetaData meta = selectedBook.getInfo().getMeta();
704 mainPanel.imprt(meta.getUrl(), new StoryRunnable() {
705 @Override
706 public void run(Story story) {
707 reader.delete(meta.getLuid());
708 mainPanel.unsetSelectedBook();
709 MetaData newMeta = story.getMeta();
710 if (!newMeta.getSource().equals(meta.getSource())) {
711 reader.changeSource(newMeta.getLuid(),
712 meta.getSource());
713 }
714 }
715 }, GuiReader.trans(StringIdGui.PROGRESS_REDOWNLOAD_REMOVE_OLD_COPY));
716 }
717 }
718 });
719
720 return refresh;
721 }
722
723 /**
724 * Create the delete menu item.
725 *
726 * @return the item
727 */
728 private JMenuItem createMenuItemDelete() {
729 JMenuItem delete = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_DELETE), KeyEvent.VK_D);
730 delete.addActionListener(new ActionListener() {
731 @Override
732 public void actionPerformed(ActionEvent e) {
733 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
734 if (selectedBook != null
735 && selectedBook.getInfo().getMeta() != null) {
736
737 final MetaData meta = selectedBook.getInfo().getMeta();
738 int rep = JOptionPane.showConfirmDialog(
739 GuiReaderFrame.this,
740 GuiReader.trans(StringIdGui.SUBTITLE_DELETE, meta.getLuid(),
741 meta.getTitle()), GuiReader.trans(StringIdGui.TITLE_DELETE),
742 JOptionPane.OK_CANCEL_OPTION);
743
744 if (rep == JOptionPane.OK_OPTION) {
745 mainPanel.outOfUi(null, true, new Runnable() {
746 @Override
747 public void run() {
748 reader.delete(meta.getLuid());
749 mainPanel.unsetSelectedBook();
750 }
751 });
752 }
753 }
754 }
755 });
756
757 return delete;
758 }
759
760 /**
761 * Create the properties menu item.
762 *
763 * @return the item
764 */
765 private JMenuItem createMenuItemProperties() {
766 JMenuItem delete = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_PROPERTIES), KeyEvent.VK_P);
767 delete.addActionListener(new ActionListener() {
768 @Override
769 public void actionPerformed(ActionEvent e) {
770 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
771 if (selectedBook != null) {
772 mainPanel.outOfUi(null, false, new Runnable() {
773 @Override
774 public void run() {
775 new GuiReaderPropertiesFrame(reader.getLibrary(),
776 selectedBook.getInfo().getMeta())
777 .setVisible(true);
778 }
779 });
780 }
781 }
782 });
783
784 return delete;
785 }
786
787 /**
788 * Create the open menu item for a book, a source/type or an author.
789 *
790 * @return the item
791 */
792 public JMenuItem createMenuItemOpenBook() {
793 JMenuItem open = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_OPEN), KeyEvent.VK_O);
794 open.addActionListener(new ActionListener() {
795 @Override
796 public void actionPerformed(ActionEvent e) {
797 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
798 if (selectedBook != null) {
799 if (selectedBook.getInfo().getMeta() == null) {
800 mainPanel.removeBookPanes();
801 mainPanel.addBookPane(selectedBook.getInfo()
802 .getMainInfo(), mainPanel.getCurrentType());
803 mainPanel.refreshBooks();
804 } else {
805 mainPanel.openBook(selectedBook);
806 }
807 }
808 }
809 });
810
811 return open;
812 }
813
814 /**
815 * Create the SetCover menu item for a book to change the linked source
816 * cover.
817 *
818 * @return the item
819 */
820 private JMenuItem createMenuItemSetCoverForSource() {
821 JMenuItem open = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_SET_COVER_FOR_SOURCE), KeyEvent.VK_C);
822 open.addActionListener(new ActionListener() {
823 @Override
824 public void actionPerformed(ActionEvent e) {
825 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
826 if (selectedBook != null) {
827 BasicLibrary lib = reader.getLibrary();
828 String luid = selectedBook.getInfo().getMeta().getLuid();
829 String source = selectedBook.getInfo().getMeta()
830 .getSource();
831
832 lib.setSourceCover(source, luid);
833
834 GuiReaderBookInfo sourceInfo = GuiReaderBookInfo
835 .fromSource(lib, source);
836 GuiReaderCoverImager.clearIcon(sourceInfo);
837 }
838 }
839 });
840
841 return open;
842 }
843
844 /**
845 * Create the SetCover menu item for a book to change the linked source
846 * cover.
847 *
848 * @return the item
849 */
850 private JMenuItem createMenuItemSetCoverForAuthor() {
851 JMenuItem open = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_SET_COVER_FOR_AUTHOR), KeyEvent.VK_A);
852 open.addActionListener(new ActionListener() {
853 @Override
854 public void actionPerformed(ActionEvent e) {
855 final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
856 if (selectedBook != null) {
857 BasicLibrary lib = reader.getLibrary();
858 String luid = selectedBook.getInfo().getMeta().getLuid();
859 String author = selectedBook.getInfo().getMeta()
860 .getAuthor();
861
862 lib.setAuthorCover(author, luid);
863
864 GuiReaderBookInfo authorInfo = GuiReaderBookInfo
865 .fromAuthor(lib, author);
866 GuiReaderCoverImager.clearIcon(authorInfo);
867 }
868 }
869 });
870
871 return open;
872 }
873
874 /**
875 * Display an error message and log the linked {@link Exception}.
876 *
877 * @param message
878 * the message
879 * @param title
880 * the title of the error message
881 * @param e
882 * the exception to log if any
883 */
884 public void error(final String message, final String title, Exception e) {
885 Instance.getTraceHandler().error(title + ": " + message);
886 if (e != null) {
887 Instance.getTraceHandler().error(e);
888 }
889
890 SwingUtilities.invokeLater(new Runnable() {
891 @Override
892 public void run() {
893 JOptionPane.showMessageDialog(GuiReaderFrame.this, message,
894 title, JOptionPane.ERROR_MESSAGE);
895 }
896 });
897 }
898
899 @Override
900 public GuiReader getReader() {
901 return reader;
902 }
903
904 /**
905 * Return the title of the application.
906 *
907 * @param libraryName
908 * the name of the associated {@link BasicLibrary}, which can be
909 * EMPTY
910 *
911 * @return the title
912 */
913 static private String getAppTitle(String libraryName) {
914 if (!libraryName.isEmpty()) {
915 return GuiReader.trans(StringIdGui.TITLE_LIBRARY_WITH_NAME, Version
916 .getCurrentVersion().toString(), libraryName);
917 }
918
919 return GuiReader.trans(StringIdGui.TITLE_LIBRARY, Version.getCurrentVersion()
920 .toString());
921 }
922 }