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