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