Add more warnings source to 1.6) and fix warnings
[nikiroo-utils.git] / src / be / nikiroo / fanfix / reader / GuiReaderFrame.java
CommitLineData
a6395bef
NR
1package be.nikiroo.fanfix.reader;
2
d3c84ac3 3import java.awt.BorderLayout;
b4dc6ab5 4import java.awt.Color;
4d205683 5import java.awt.Frame;
5130ce84
NR
6import java.awt.Toolkit;
7import java.awt.datatransfer.DataFlavor;
a6395bef
NR
8import java.awt.event.ActionEvent;
9import java.awt.event.ActionListener;
333f0e7b 10import java.awt.event.KeyEvent;
9843a5e5 11import java.awt.event.MouseEvent;
333f0e7b
NR
12import java.awt.event.WindowEvent;
13import java.io.File;
a6395bef 14import java.io.IOException;
4d205683 15import java.net.URL;
70c9b112 16import java.util.ArrayList;
4d205683 17import java.util.HashMap;
a6395bef 18import java.util.List;
4d205683
NR
19import java.util.Map;
20import java.util.Map.Entry;
a6395bef 21
4310bae9 22import javax.swing.BoxLayout;
10d558d2 23import javax.swing.JFileChooser;
a6395bef 24import javax.swing.JFrame;
333f0e7b
NR
25import javax.swing.JMenu;
26import javax.swing.JMenuBar;
27import javax.swing.JMenuItem;
28import javax.swing.JOptionPane;
29import javax.swing.JPanel;
9843a5e5 30import javax.swing.JPopupMenu;
d3c84ac3 31import javax.swing.JScrollPane;
3b2b638f 32import javax.swing.SwingUtilities;
4d205683
NR
33import javax.swing.filechooser.FileFilter;
34import javax.swing.filechooser.FileNameExtensionFilter;
a6395bef
NR
35
36import be.nikiroo.fanfix.Instance;
e8eeea0a 37import be.nikiroo.fanfix.bundles.Config;
b4dc6ab5 38import be.nikiroo.fanfix.bundles.UiConfig;
a6395bef 39import be.nikiroo.fanfix.data.MetaData;
4d205683 40import be.nikiroo.fanfix.data.Story;
e42573a0 41import be.nikiroo.fanfix.library.LocalLibrary;
4d205683 42import be.nikiroo.fanfix.output.BasicOutput.OutputType;
5dd985cf 43import be.nikiroo.fanfix.reader.GuiReaderBook.BookActionListener;
3b2b638f 44import be.nikiroo.utils.Progress;
39c3c689 45import be.nikiroo.utils.Version;
e8eeea0a 46import be.nikiroo.utils.ui.ConfigEditor;
3b2b638f 47import be.nikiroo.utils.ui.ProgressBar;
a6395bef 48
4d205683 49/**
5dd985cf 50 * A {@link Frame} that will show a {@link GuiReaderBook} item for each
4d205683 51 * {@link Story} in the main cache ({@link Instance#getCache()}), and offer a
5dd985cf
NR
52 * way to copy them to the {@link GuiReader} cache (
53 * {@link BasicReader#getLibrary()}), read them, delete them...
4d205683
NR
54 *
55 * @author niki
56 */
5dd985cf 57class GuiReaderFrame extends JFrame {
a6395bef 58 private static final long serialVersionUID = 1L;
5dd985cf
NR
59 private GuiReader reader;
60 private Map<GuiReaderGroup, String> booksByType;
61 private Map<GuiReaderGroup, String> booksByAuthor;
4310bae9 62 private JPanel pane;
b4dc6ab5 63 private Color color;
3b2b638f
NR
64 private ProgressBar pgBar;
65 private JMenuBar bar;
5dd985cf 66 private GuiReaderBook selectedBook;
793f1071 67 private boolean words; // words or authors (secondary info on books)
a6395bef 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
83 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
84 setSize(800, 600);
d3c84ac3 85 setLayout(new BorderLayout());
a6395bef 86
4310bae9
NR
87 pane = new JPanel();
88 pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
b4dc6ab5 89
3b2b638f 90 color = Instance.getUiConfig().getColor(UiConfig.BACKGROUND_COLOR);
b4dc6ab5
NR
91 if (color != null) {
92 setBackground(color);
4310bae9 93 pane.setBackground(color);
b4dc6ab5 94 }
d3c84ac3 95
4310bae9 96 JScrollPane scroll = new JScrollPane(pane);
b4dc6ab5
NR
97 scroll.getVerticalScrollBar().setUnitIncrement(16);
98 add(scroll, BorderLayout.CENTER);
a6395bef 99
3b2b638f
NR
100 pgBar = new ProgressBar();
101 add(pgBar, BorderLayout.SOUTH);
102
754a5bc2 103 pgBar.addActionListener(new ActionListener() {
211f7ddb 104 @Override
754a5bc2
NR
105 public void actionPerformed(ActionEvent e) {
106 invalidate();
107 pgBar.setProgress(null);
108 validate();
109 setEnabled(true);
110 }
111 });
112
113 pgBar.addUpdateListener(new ActionListener() {
211f7ddb 114 @Override
754a5bc2 115 public void actionPerformed(ActionEvent e) {
80791ae8
NR
116 invalidate();
117 validate();
754a5bc2
NR
118 repaint();
119 }
120 });
121
5dd985cf
NR
122 booksByType = new HashMap<GuiReaderGroup, String>();
123 booksByAuthor = new HashMap<GuiReaderGroup, String>();
4310bae9 124
4f661b2b
NR
125 pane.setVisible(false);
126 final Progress pg = new Progress();
127 final String typeF = type;
128 outOfUi(pg, new Runnable() {
211f7ddb 129 @Override
4f661b2b 130 public void run() {
e42573a0 131 GuiReaderFrame.this.reader.getLibrary().refresh(false, pg);
4f661b2b
NR
132 invalidate();
133 setJMenuBar(createMenu());
134 addBookPane(typeF, true);
135 refreshBooks();
136 validate();
137 pane.setVisible(true);
138 }
139 });
4310bae9 140
333f0e7b
NR
141 setVisible(true);
142 }
143
4d205683 144 /**
5dd985cf
NR
145 * Add a new {@link GuiReaderGroup} on the frame to display the books of the
146 * selected type or author.
4d205683 147 *
4310bae9 148 * @param value
70c9b112
NR
149 * the author or the type, or NULL to get all the
150 * authors-or-types
4d205683 151 * @param type
4310bae9 152 * TRUE for type, FALSE for author
4d205683 153 */
4310bae9
NR
154 private void addBookPane(String value, boolean type) {
155 if (value == null) {
156 if (type) {
e42573a0 157 for (String tt : reader.getLibrary().getSources()) {
4310bae9
NR
158 if (tt != null) {
159 addBookPane(tt, type);
160 }
161 }
162 } else {
e42573a0 163 for (String tt : reader.getLibrary().getAuthors()) {
4310bae9
NR
164 if (tt != null) {
165 addBookPane(tt, type);
166 }
167 }
b4dc6ab5
NR
168 }
169
4310bae9
NR
170 return;
171 }
4d205683 172
5dd985cf 173 GuiReaderGroup bookPane = new GuiReaderGroup(reader, value, color);
4310bae9
NR
174 if (type) {
175 booksByType.put(bookPane, value);
176 } else {
177 booksByAuthor.put(bookPane, value);
178 }
333f0e7b 179
4310bae9
NR
180 this.invalidate();
181 pane.invalidate();
182 pane.add(bookPane);
183 pane.validate();
184 this.validate();
9843a5e5 185
4310bae9 186 bookPane.setActionListener(new BookActionListener() {
211f7ddb 187 @Override
5dd985cf 188 public void select(GuiReaderBook book) {
4310bae9
NR
189 selectedBook = book;
190 }
191
211f7ddb 192 @Override
5dd985cf 193 public void popupRequested(GuiReaderBook book, MouseEvent e) {
4310bae9
NR
194 JPopupMenu popup = new JPopupMenu();
195 popup.add(createMenuItemOpenBook());
196 popup.addSeparator();
197 popup.add(createMenuItemExport());
70c9b112 198 popup.add(createMenuItemMove());
4310bae9
NR
199 popup.add(createMenuItemClearCache());
200 popup.add(createMenuItemRedownload());
201 popup.addSeparator();
202 popup.add(createMenuItemDelete());
203 popup.show(e.getComponent(), e.getX(), e.getY());
204 }
205
211f7ddb 206 @Override
5dd985cf 207 public void action(final GuiReaderBook book) {
4310bae9
NR
208 openBook(book);
209 }
210 });
211 }
a6395bef 212
4310bae9
NR
213 private void removeBookPanes() {
214 booksByType.clear();
215 booksByAuthor.clear();
216 pane.invalidate();
217 this.invalidate();
218 pane.removeAll();
219 pane.validate();
220 this.validate();
221 }
222
223 /**
5dd985cf 224 * Refresh the list of {@link GuiReaderBook}s from disk.
4310bae9 225 *
4310bae9
NR
226 */
227 private void refreshBooks() {
5dd985cf 228 for (GuiReaderGroup group : booksByType.keySet()) {
e42573a0 229 List<MetaData> stories = reader.getLibrary().getListBySource(
4310bae9 230 booksByType.get(group));
793f1071 231 group.refreshBooks(stories, words);
4310bae9
NR
232 }
233
5dd985cf 234 for (GuiReaderGroup group : booksByAuthor.keySet()) {
e42573a0 235 List<MetaData> stories = reader.getLibrary().getListByAuthor(
4310bae9 236 booksByAuthor.get(group));
793f1071 237 group.refreshBooks(stories, words);
a6395bef
NR
238 }
239
4310bae9
NR
240 pane.repaint();
241 this.repaint();
333f0e7b
NR
242 }
243
4d205683
NR
244 /**
245 * Create the main menu bar.
246 *
247 * @return the bar
248 */
333f0e7b 249 private JMenuBar createMenu() {
3b2b638f 250 bar = new JMenuBar();
333f0e7b
NR
251
252 JMenu file = new JMenu("File");
10d558d2 253 file.setMnemonic(KeyEvent.VK_F);
333f0e7b 254
22848428 255 JMenuItem imprt = new JMenuItem("Import URL...", KeyEvent.VK_U);
333f0e7b 256 imprt.addActionListener(new ActionListener() {
211f7ddb 257 @Override
333f0e7b 258 public void actionPerformed(ActionEvent e) {
10d558d2
NR
259 imprt(true);
260 }
261 });
22848428 262 JMenuItem imprtF = new JMenuItem("Import File...", KeyEvent.VK_F);
10d558d2 263 imprtF.addActionListener(new ActionListener() {
211f7ddb 264 @Override
10d558d2
NR
265 public void actionPerformed(ActionEvent e) {
266 imprt(false);
267 }
268 });
269 JMenuItem exit = new JMenuItem("Exit", KeyEvent.VK_X);
270 exit.addActionListener(new ActionListener() {
211f7ddb 271 @Override
10d558d2 272 public void actionPerformed(ActionEvent e) {
5dd985cf
NR
273 GuiReaderFrame.this.dispatchEvent(new WindowEvent(
274 GuiReaderFrame.this, WindowEvent.WINDOW_CLOSING));
10d558d2
NR
275 }
276 });
3b2b638f 277
9843a5e5
NR
278 file.add(createMenuItemOpenBook());
279 file.add(createMenuItemExport());
70c9b112 280 file.add(createMenuItemMove());
9843a5e5 281 file.addSeparator();
10d558d2
NR
282 file.add(imprt);
283 file.add(imprtF);
284 file.addSeparator();
285 file.add(exit);
3b2b638f 286
10d558d2
NR
287 bar.add(file);
288
289 JMenu edit = new JMenu("Edit");
290 edit.setMnemonic(KeyEvent.VK_E);
291
22848428
NR
292 edit.add(createMenuItemClearCache());
293 edit.add(createMenuItemRedownload());
9843a5e5
NR
294 edit.addSeparator();
295 edit.add(createMenuItemDelete());
296
297 bar.add(edit);
298
793f1071
NR
299 JMenu view = new JMenu("View");
300 view.setMnemonic(KeyEvent.VK_V);
301 JMenuItem vauthors = new JMenuItem("Author");
302 vauthors.setMnemonic(KeyEvent.VK_A);
303 vauthors.addActionListener(new ActionListener() {
211f7ddb 304 @Override
793f1071
NR
305 public void actionPerformed(ActionEvent e) {
306 words = false;
307 refreshBooks();
308 }
309 });
310 view.add(vauthors);
311 JMenuItem vwords = new JMenuItem("Word count");
312 vwords.setMnemonic(KeyEvent.VK_W);
313 vwords.addActionListener(new ActionListener() {
211f7ddb 314 @Override
793f1071
NR
315 public void actionPerformed(ActionEvent e) {
316 words = true;
317 refreshBooks();
318 }
319 });
320 view.add(vwords);
321 bar.add(view);
322
4310bae9
NR
323 JMenu sources = new JMenu("Sources");
324 sources.setMnemonic(KeyEvent.VK_S);
9843a5e5 325
e42573a0 326 List<String> tt = reader.getLibrary().getSources();
9843a5e5
NR
327 tt.add(0, null);
328 for (final String type : tt) {
4310bae9 329 JMenuItem item = new JMenuItem(type == null ? "All" : type);
9843a5e5 330 item.addActionListener(new ActionListener() {
211f7ddb 331 @Override
9843a5e5 332 public void actionPerformed(ActionEvent e) {
4310bae9
NR
333 removeBookPanes();
334 addBookPane(type, true);
335 refreshBooks();
9843a5e5
NR
336 }
337 });
4310bae9 338 sources.add(item);
9843a5e5
NR
339
340 if (type == null) {
4310bae9 341 sources.addSeparator();
9843a5e5
NR
342 }
343 }
10d558d2 344
4310bae9
NR
345 bar.add(sources);
346
347 JMenu authors = new JMenu("Authors");
348 authors.setMnemonic(KeyEvent.VK_A);
349
e42573a0 350 List<String> aa = reader.getLibrary().getAuthors();
4310bae9
NR
351 aa.add(0, null);
352 for (final String author : aa) {
353 JMenuItem item = new JMenuItem(author == null ? "All"
354 : author.isEmpty() ? "[unknown]" : author);
355 item.addActionListener(new ActionListener() {
211f7ddb 356 @Override
4310bae9
NR
357 public void actionPerformed(ActionEvent e) {
358 removeBookPanes();
359 addBookPane(author, false);
360 refreshBooks();
361 }
362 });
363 authors.add(item);
364
365 if (author == null || author.isEmpty()) {
366 authors.addSeparator();
367 }
368 }
369
370 bar.add(authors);
9843a5e5 371
e8eeea0a
NR
372 JMenu options = new JMenu("Options");
373 options.setMnemonic(KeyEvent.VK_O);
374 options.add(createMenuItemConfig());
375 options.add(createMenuItemUiConfig());
376 bar.add(options);
377
9843a5e5
NR
378 return bar;
379 }
380
e8eeea0a
NR
381 /**
382 * Create the Fanfix Configuration menu item.
383 *
384 * @return the item
385 */
386 private JMenuItem createMenuItemConfig() {
387 final String title = "Fanfix Configuration";
388 JMenuItem item = new JMenuItem(title);
389 item.setMnemonic(KeyEvent.VK_F);
390
391 item.addActionListener(new ActionListener() {
211f7ddb 392 @Override
e8eeea0a
NR
393 public void actionPerformed(ActionEvent e) {
394 ConfigEditor<Config> ed = new ConfigEditor<Config>(
395 Config.class, Instance.getConfig(),
396 "This is where you configure the options of the program.");
397 JFrame frame = new JFrame(title);
398 frame.add(ed);
399 frame.setSize(800, 600);
400 frame.setVisible(true);
401 }
402 });
403
404 return item;
405 }
406
407 /**
408 * Create the UI Configuration menu item.
409 *
410 * @return the item
411 */
412 private JMenuItem createMenuItemUiConfig() {
413 final String title = "UI Configuration";
414 JMenuItem item = new JMenuItem(title);
415 item.setMnemonic(KeyEvent.VK_U);
416
417 item.addActionListener(new ActionListener() {
211f7ddb 418 @Override
e8eeea0a
NR
419 public void actionPerformed(ActionEvent e) {
420 ConfigEditor<UiConfig> ed = new ConfigEditor<UiConfig>(
421 UiConfig.class, Instance.getUiConfig(),
422 "This is where you configure the graphical appearence of the program.");
423 JFrame frame = new JFrame(title);
424 frame.add(ed);
425 frame.setSize(800, 600);
426 frame.setVisible(true);
427 }
428 });
429
430 return item;
431 }
432
4d205683
NR
433 /**
434 * Create the export menu item.
435 *
436 * @return the item
437 */
9843a5e5 438 private JMenuItem createMenuItemExport() {
4d205683
NR
439 final JFileChooser fc = new JFileChooser();
440 fc.setAcceptAllFileFilterUsed(false);
441
442 final Map<FileFilter, OutputType> filters = new HashMap<FileFilter, OutputType>();
443 for (OutputType type : OutputType.values()) {
444 String ext = type.getDefaultExtension(false);
445 String desc = type.getDesc(false);
b2612f9d 446
4d205683
NR
447 if (ext == null || ext.isEmpty()) {
448 filters.put(createAllFilter(desc), type);
449 } else {
450 filters.put(new FileNameExtensionFilter(desc, ext), type);
451 }
452 }
453
454 // First the "ALL" filters, then, the extension filters
455 for (Entry<FileFilter, OutputType> entry : filters.entrySet()) {
456 if (!(entry.getKey() instanceof FileNameExtensionFilter)) {
457 fc.addChoosableFileFilter(entry.getKey());
458 }
459 }
460 for (Entry<FileFilter, OutputType> entry : filters.entrySet()) {
461 if (entry.getKey() instanceof FileNameExtensionFilter) {
462 fc.addChoosableFileFilter(entry.getKey());
463 }
464 }
465 //
9843a5e5 466
4d205683 467 JMenuItem export = new JMenuItem("Save as...", KeyEvent.VK_S);
10d558d2 468 export.addActionListener(new ActionListener() {
211f7ddb 469 @Override
10d558d2 470 public void actionPerformed(ActionEvent e) {
4d205683 471 if (selectedBook != null) {
5dd985cf 472 fc.showDialog(GuiReaderFrame.this, "Save");
b2612f9d
NR
473 if (fc.getSelectedFile() != null) {
474 final OutputType type = filters.get(fc.getFileFilter());
475 final String path = fc.getSelectedFile()
476 .getAbsolutePath()
477 + type.getDefaultExtension(false);
478 final Progress pg = new Progress();
479 outOfUi(pg, new Runnable() {
211f7ddb 480 @Override
b2612f9d
NR
481 public void run() {
482 try {
e42573a0 483 reader.getLibrary().export(
b2612f9d
NR
484 selectedBook.getMeta().getLuid(),
485 type, path, pg);
486 } catch (IOException e) {
487 Instance.syserr(e);
488 }
4d205683 489 }
b2612f9d
NR
490 });
491 }
4d205683 492 }
10d558d2
NR
493 }
494 });
495
9843a5e5
NR
496 return export;
497 }
498
edd46289
NR
499 /**
500 * Create a {@link FileFilter} that accepts all files and return the given
501 * description.
502 *
503 * @param desc
504 * the description
505 *
506 * @return the filter
507 */
4d205683
NR
508 private FileFilter createAllFilter(final String desc) {
509 return new FileFilter() {
510 @Override
511 public String getDescription() {
512 return desc;
513 }
514
515 @Override
516 public boolean accept(File f) {
517 return true;
518 }
519 };
520 }
521
522 /**
523 * Create the refresh (delete cache) menu item.
524 *
525 * @return the item
526 */
22848428 527 private JMenuItem createMenuItemClearCache() {
4d205683 528 JMenuItem refresh = new JMenuItem("Clear cache", KeyEvent.VK_C);
10d558d2 529 refresh.addActionListener(new ActionListener() {
211f7ddb 530 @Override
10d558d2
NR
531 public void actionPerformed(ActionEvent e) {
532 if (selectedBook != null) {
533 outOfUi(null, new Runnable() {
211f7ddb 534 @Override
10d558d2 535 public void run() {
754a5bc2
NR
536 reader.clearLocalReaderCache(selectedBook.getMeta()
537 .getLuid());
10d558d2 538 selectedBook.setCached(false);
3b2b638f 539 SwingUtilities.invokeLater(new Runnable() {
211f7ddb 540 @Override
3b2b638f 541 public void run() {
10d558d2 542 selectedBook.repaint();
3b2b638f
NR
543 }
544 });
545 }
546 });
333f0e7b
NR
547 }
548 }
549 });
10d558d2 550
9843a5e5
NR
551 return refresh;
552 }
553
70c9b112
NR
554 /**
555 * Create the delete menu item.
556 *
557 * @return the item
558 */
559 private JMenuItem createMenuItemMove() {
560 JMenu moveTo = new JMenu("Move to...");
561 moveTo.setMnemonic(KeyEvent.VK_M);
562
563 List<String> types = new ArrayList<String>();
564 types.add(null);
e42573a0 565 types.addAll(reader.getLibrary().getSources());
70c9b112
NR
566
567 for (String type : types) {
568 JMenuItem item = new JMenuItem(type == null ? "New type..." : type);
569
570 moveTo.add(item);
571 if (type == null) {
572 moveTo.addSeparator();
573 }
574
575 final String ftype = type;
576 item.addActionListener(new ActionListener() {
211f7ddb 577 @Override
70c9b112
NR
578 public void actionPerformed(ActionEvent e) {
579 if (selectedBook != null) {
580 String type = ftype;
581 if (type == null) {
582 Object rep = JOptionPane.showInputDialog(
5dd985cf 583 GuiReaderFrame.this, "Move to:",
70c9b112
NR
584 "Moving story",
585 JOptionPane.QUESTION_MESSAGE, null, null,
586 selectedBook.getMeta().getSource());
211f7ddb 587
70c9b112
NR
588 if (rep == null) {
589 return;
70c9b112 590 }
211f7ddb
NR
591
592 type = rep.toString();
70c9b112
NR
593 }
594
595 final String ftype = type;
596 outOfUi(null, new Runnable() {
211f7ddb 597 @Override
70c9b112
NR
598 public void run() {
599 reader.changeType(selectedBook.getMeta()
600 .getLuid(), ftype);
601
602 selectedBook = null;
603
604 SwingUtilities.invokeLater(new Runnable() {
211f7ddb 605 @Override
70c9b112
NR
606 public void run() {
607 setJMenuBar(createMenu());
608 }
609 });
610 }
611 });
612 }
613 }
614 });
615 }
616
617 return moveTo;
618 }
619
22848428
NR
620 /**
621 * Create the redownload (then delete original) menu item.
622 *
623 * @return the item
624 */
625 private JMenuItem createMenuItemRedownload() {
626 JMenuItem refresh = new JMenuItem("Redownload", KeyEvent.VK_R);
627 refresh.addActionListener(new ActionListener() {
211f7ddb 628 @Override
22848428
NR
629 public void actionPerformed(ActionEvent e) {
630 if (selectedBook != null) {
754a5bc2
NR
631 final MetaData meta = selectedBook.getMeta();
632 imprt(meta.getUrl(), new Runnable() {
211f7ddb 633 @Override
22848428 634 public void run() {
754a5bc2 635 reader.delete(meta.getLuid());
5dd985cf 636 GuiReaderFrame.this.selectedBook = null;
22848428 637 }
754a5bc2 638 }, "Removing old copy");
22848428
NR
639 }
640 }
641 });
642
643 return refresh;
644 }
645
4d205683
NR
646 /**
647 * Create the delete menu item.
648 *
649 * @return the item
650 */
9843a5e5 651 private JMenuItem createMenuItemDelete() {
10d558d2
NR
652 JMenuItem delete = new JMenuItem("Delete", KeyEvent.VK_D);
653 delete.addActionListener(new ActionListener() {
211f7ddb 654 @Override
10d558d2
NR
655 public void actionPerformed(ActionEvent e) {
656 if (selectedBook != null) {
657 outOfUi(null, new Runnable() {
211f7ddb 658 @Override
10d558d2 659 public void run() {
22848428 660 reader.delete(selectedBook.getMeta().getLuid());
10d558d2 661 selectedBook = null;
10d558d2
NR
662 }
663 });
664 }
665 }
666 });
667
9843a5e5
NR
668 return delete;
669 }
10d558d2 670
4d205683
NR
671 /**
672 * Create the open menu item.
673 *
674 * @return the item
675 */
9843a5e5
NR
676 private JMenuItem createMenuItemOpenBook() {
677 JMenuItem open = new JMenuItem("Open", KeyEvent.VK_O);
678 open.addActionListener(new ActionListener() {
211f7ddb 679 @Override
9843a5e5
NR
680 public void actionPerformed(ActionEvent e) {
681 if (selectedBook != null) {
682 openBook(selectedBook);
683 }
684 }
685 });
10d558d2 686
9843a5e5
NR
687 return open;
688 }
10d558d2 689
4d205683 690 /**
5dd985cf 691 * Open a {@link GuiReaderBook} item.
4d205683
NR
692 *
693 * @param book
5dd985cf 694 * the {@link GuiReaderBook} to open
4d205683 695 */
5dd985cf 696 private void openBook(final GuiReaderBook book) {
9843a5e5
NR
697 final Progress pg = new Progress();
698 outOfUi(pg, new Runnable() {
211f7ddb 699 @Override
9843a5e5
NR
700 public void run() {
701 try {
bc2ea776 702 reader.read(book.getMeta().getLuid(), pg);
edd46289 703 SwingUtilities.invokeLater(new Runnable() {
211f7ddb 704 @Override
edd46289
NR
705 public void run() {
706 book.setCached(true);
9843a5e5 707 }
edd46289 708 });
9843a5e5 709 } catch (IOException e) {
edd46289 710 // TODO: error message?
9843a5e5 711 Instance.syserr(e);
333f0e7b 712 }
10d558d2 713 }
9843a5e5 714 });
a6395bef 715 }
3b2b638f 716
4d205683
NR
717 /**
718 * Process the given action out of the Swing UI thread and link the given
719 * {@link ProgressBar} to the action.
720 * <p>
721 * The code will make sure that the {@link ProgressBar} (if not NULL) is set
722 * to done when the action is done.
723 *
5dd985cf 724 * @param progress
4d205683
NR
725 * the {@link ProgressBar} or NULL
726 * @param run
727 * the action to run
728 */
754a5bc2
NR
729 private void outOfUi(Progress progress, final Runnable run) {
730 final Progress pg = new Progress();
d5a7153c 731 final Progress reload = new Progress("Reload books");
754a5bc2
NR
732 if (progress == null) {
733 progress = new Progress();
734 }
3b2b638f 735
754a5bc2
NR
736 pg.addProgress(progress, 90);
737 pg.addProgress(reload, 10);
738
739 invalidate();
740 pgBar.setProgress(pg);
741 validate();
a4143cd7 742 setEnabled(false);
3b2b638f
NR
743
744 new Thread(new Runnable() {
211f7ddb 745 @Override
3b2b638f
NR
746 public void run() {
747 run.run();
754a5bc2 748 refreshBooks();
5ce869b8 749 reload.done();
754a5bc2
NR
750 if (!pg.isDone()) {
751 // will trigger pgBar ActionListener:
5ce869b8 752 pg.done();
3b2b638f
NR
753 }
754 }
754a5bc2 755 }, "outOfUi thread").start();
3b2b638f
NR
756 }
757
4d205683 758 /**
68e2c6d2 759 * Import a {@link Story} into the main {@link LocalLibrary}.
22848428
NR
760 * <p>
761 * Should be called inside the UI thread.
4d205683
NR
762 *
763 * @param askUrl
764 * TRUE for an {@link URL}, false for a {@link File}
765 */
10d558d2
NR
766 private void imprt(boolean askUrl) {
767 JFileChooser fc = new JFileChooser();
768
5130ce84 769 Object url;
10d558d2 770 if (askUrl) {
5130ce84
NR
771 String clipboard = "";
772 try {
773 clipboard = ("" + Toolkit.getDefaultToolkit()
774 .getSystemClipboard().getData(DataFlavor.stringFlavor))
775 .trim();
776 } catch (Exception e) {
777 // No data will be handled
778 }
779
780 if (clipboard == null || !clipboard.startsWith("http")) {
781 clipboard = "";
782 }
783
5dd985cf 784 url = JOptionPane.showInputDialog(GuiReaderFrame.this,
10d558d2 785 "url of the story to import?", "Importing from URL",
5130ce84 786 JOptionPane.QUESTION_MESSAGE, null, null, clipboard);
10d558d2
NR
787 } else if (fc.showOpenDialog(this) != JFileChooser.CANCEL_OPTION) {
788 url = fc.getSelectedFile().getAbsolutePath();
789 } else {
790 url = null;
791 }
792
5130ce84 793 if (url != null && !url.toString().isEmpty()) {
754a5bc2 794 imprt(url.toString(), null, null);
22848428
NR
795 }
796 }
10d558d2 797
22848428 798 /**
68e2c6d2 799 * Actually import the {@link Story} into the main {@link LocalLibrary}.
22848428
NR
800 * <p>
801 * Should be called inside the UI thread.
802 *
803 * @param url
804 * the {@link Story} to import by {@link URL}
805 * @param onSuccess
806 * Action to execute on success
807 */
754a5bc2
NR
808 private void imprt(final String url, final Runnable onSuccess,
809 String onSuccessPgName) {
810 final Progress pg = new Progress();
811 final Progress pgImprt = new Progress();
812 final Progress pgOnSuccess = new Progress(onSuccessPgName);
813 pg.addProgress(pgImprt, 95);
814 pg.addProgress(pgOnSuccess, 5);
815
22848428 816 outOfUi(pg, new Runnable() {
211f7ddb 817 @Override
22848428
NR
818 public void run() {
819 Exception ex = null;
820 try {
e42573a0 821 reader.getLibrary().imprt(BasicReader.getUrl(url), pgImprt);
22848428
NR
822 } catch (IOException e) {
823 ex = e;
824 }
10d558d2 825
22848428
NR
826 final Exception e = ex;
827
828 final boolean ok = (e == null);
754a5bc2
NR
829
830 pgOnSuccess.setProgress(0);
831 if (!ok) {
832 Instance.syserr(e);
833 SwingUtilities.invokeLater(new Runnable() {
211f7ddb 834 @Override
754a5bc2 835 public void run() {
5dd985cf
NR
836 JOptionPane.showMessageDialog(GuiReaderFrame.this,
837 "Cannot import: " + url, e.getMessage(),
22848428 838 JOptionPane.ERROR_MESSAGE);
10d558d2 839 }
754a5bc2
NR
840 });
841 } else {
842 if (onSuccess != null) {
843 onSuccess.run();
22848428 844 }
754a5bc2 845 }
5ce869b8 846 pgOnSuccess.done();
22848428
NR
847 }
848 });
10d558d2
NR
849 }
850
4d205683
NR
851 /**
852 * Enables or disables this component, depending on the value of the
853 * parameter <code>b</code>. An enabled component can respond to user input
854 * and generate events. Components are enabled initially by default.
855 * <p>
856 * Disabling this component will also affect its children.
857 *
858 * @param b
859 * If <code>true</code>, this component is enabled; otherwise
860 * this component is disabled
861 */
862 @Override
863 public void setEnabled(boolean b) {
4f661b2b
NR
864 if (bar != null) {
865 bar.setEnabled(b);
866 }
867
5dd985cf 868 for (GuiReaderGroup group : booksByType.keySet()) {
4310bae9
NR
869 group.setEnabled(b);
870 }
5dd985cf 871 for (GuiReaderGroup group : booksByAuthor.keySet()) {
4310bae9
NR
872 group.setEnabled(b);
873 }
4d205683 874 super.setEnabled(b);
3b2b638f
NR
875 repaint();
876 }
a6395bef 877}