X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Freader%2FGuiReaderFrame.java;h=99091d376ed03de370002f75fceb4538c52a9f26;hb=925298fd058a953144058f8b70d939c2a3e7ea5b;hp=59663fe3e8369d41162e0fc276aacb86b3dce43d;hpb=bc2ea776b67cabcbdcbbc6d8a4e2df1aafa9101a;p=nikiroo-utils.git diff --git a/src/be/nikiroo/fanfix/reader/GuiReaderFrame.java b/src/be/nikiroo/fanfix/reader/GuiReaderFrame.java index 59663fe..99091d3 100644 --- a/src/be/nikiroo/fanfix/reader/GuiReaderFrame.java +++ b/src/be/nikiroo/fanfix/reader/GuiReaderFrame.java @@ -13,6 +13,7 @@ import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.net.URL; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -22,6 +23,7 @@ import java.util.Map.Entry; import javax.swing.BoxLayout; import javax.swing.JFileChooser; import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; @@ -29,6 +31,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; +import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; @@ -38,6 +41,8 @@ import be.nikiroo.fanfix.bundles.Config; import be.nikiroo.fanfix.bundles.UiConfig; import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.data.Story; +import be.nikiroo.fanfix.library.BasicLibrary; +import be.nikiroo.fanfix.library.BasicLibrary.Status; import be.nikiroo.fanfix.library.LocalLibrary; import be.nikiroo.fanfix.output.BasicOutput.OutputType; import be.nikiroo.fanfix.reader.GuiReaderBook.BookActionListener; @@ -66,6 +71,21 @@ class GuiReaderFrame extends JFrame { private GuiReaderBook selectedBook; private boolean words; // words or authors (secondary info on books) + /** + * A {@link Runnable} with a {@link Story} parameter. + * + * @author niki + */ + private interface StoryRunnable { + /** + * Run the action. + * + * @param story + * the story + */ + public void run(Story story); + } + /** * Create a new {@link GuiReaderFrame}. * @@ -97,10 +117,17 @@ class GuiReaderFrame extends JFrame { scroll.getVerticalScrollBar().setUnitIncrement(16); add(scroll, BorderLayout.CENTER); + String message = reader.getLibrary().getLibraryName(); + if (!message.isEmpty()) { + JLabel name = new JLabel(message, SwingConstants.CENTER); + add(name, BorderLayout.NORTH); + } + pgBar = new ProgressBar(); add(pgBar, BorderLayout.SOUTH); pgBar.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { invalidate(); pgBar.setProgress(null); @@ -110,6 +137,7 @@ class GuiReaderFrame extends JFrame { }); pgBar.addUpdateListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { invalidate(); validate(); @@ -124,20 +152,94 @@ class GuiReaderFrame extends JFrame { final Progress pg = new Progress(); final String typeF = type; outOfUi(pg, new Runnable() { + @Override public void run() { - GuiReaderFrame.this.reader.getLibrary().refresh(false, pg); - invalidate(); - setJMenuBar(createMenu()); - addBookPane(typeF, true); - refreshBooks(); - validate(); - pane.setVisible(true); + BasicLibrary lib = GuiReaderFrame.this.reader.getLibrary(); + Status status = lib.getStatus(); + + if (status == Status.READY) { + lib.refresh(pg); + invalidate(); + setJMenuBar(createMenu(true)); + addBookPane(typeF, true); + refreshBooks(); + validate(); + pane.setVisible(true); + } else { + invalidate(); + setJMenuBar(createMenu(false)); + validate(); + + String err = lib.getLibraryName() + "\n"; + switch (status) { + case INVALID: + err += "Library not valid"; + break; + + case UNAUTORIZED: + err += "You are not allowed to access this library"; + break; + + case UNAVAILABLE: + err += "Library currently unavilable"; + break; + + default: + err += "An error occured when contacting the library"; + break; + } + + error(err, "Library error", null); + } } }); setVisible(true); } + private void addSourcePanes() { + // Sources -> i18n + GuiReaderGroup bookPane = new GuiReaderGroup(reader, "Sources", color); + + List sources = new ArrayList(); + for (String source : reader.getLibrary().getSources()) { + MetaData mSource = new MetaData(); + mSource.setLuid(null); + mSource.setTitle(source); + mSource.setSource(source); + sources.add(mSource); + } + + bookPane.refreshBooks(sources, false); + + this.invalidate(); + pane.invalidate(); + pane.add(bookPane); + pane.validate(); + this.validate(); + + bookPane.setActionListener(new BookActionListener() { + @Override + public void select(GuiReaderBook book) { + selectedBook = book; + } + + @Override + public void popupRequested(GuiReaderBook book, MouseEvent e) { + JPopupMenu popup = new JPopupMenu(); + popup.add(createMenuItemOpenBook()); + popup.show(e.getComponent(), e.getX(), e.getY()); + } + + @Override + public void action(final GuiReaderBook book) { + removeBookPanes(); + addBookPane(book.getMeta().getSource(), true); + refreshBooks(); + } + }); + } + /** * Add a new {@link GuiReaderGroup} on the frame to display the books of the * selected type or author. @@ -151,9 +253,14 @@ class GuiReaderFrame extends JFrame { private void addBookPane(String value, boolean type) { if (value == null) { if (type) { - for (String tt : reader.getLibrary().getSources()) { - if (tt != null) { - addBookPane(tt, type); + if (Instance.getUiConfig().getBoolean(UiConfig.SOURCE_PAGE, + false)) { + addSourcePanes(); + } else { + for (String tt : reader.getLibrary().getSources()) { + if (tt != null) { + addBookPane(tt, type); + } } } } else { @@ -181,16 +288,19 @@ class GuiReaderFrame extends JFrame { this.validate(); bookPane.setActionListener(new BookActionListener() { + @Override public void select(GuiReaderBook book) { selectedBook = book; } + @Override public void popupRequested(GuiReaderBook book, MouseEvent e) { JPopupMenu popup = new JPopupMenu(); popup.add(createMenuItemOpenBook()); popup.addSeparator(); popup.add(createMenuItemExport()); - popup.add(createMenuItemMove()); + popup.add(createMenuItemMove(true)); + popup.add(createMenuItemSetCover()); popup.add(createMenuItemClearCache()); popup.add(createMenuItemRedownload()); popup.addSeparator(); @@ -198,6 +308,7 @@ class GuiReaderFrame extends JFrame { popup.show(e.getComponent(), e.getX(), e.getY()); } + @Override public void action(final GuiReaderBook book) { openBook(book); } @@ -238,9 +349,12 @@ class GuiReaderFrame extends JFrame { /** * Create the main menu bar. * + * @param libOk + * the library can be queried + * * @return the bar */ - private JMenuBar createMenu() { + private JMenuBar createMenu(boolean libOk) { bar = new JMenuBar(); JMenu file = new JMenu("File"); @@ -248,18 +362,21 @@ class GuiReaderFrame extends JFrame { JMenuItem imprt = new JMenuItem("Import URL...", KeyEvent.VK_U); imprt.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { imprt(true); } }); JMenuItem imprtF = new JMenuItem("Import File...", KeyEvent.VK_F); imprtF.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { imprt(false); } }); JMenuItem exit = new JMenuItem("Exit", KeyEvent.VK_X); exit.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { GuiReaderFrame.this.dispatchEvent(new WindowEvent( GuiReaderFrame.this, WindowEvent.WINDOW_CLOSING)); @@ -268,7 +385,7 @@ class GuiReaderFrame extends JFrame { file.add(createMenuItemOpenBook()); file.add(createMenuItemExport()); - file.add(createMenuItemMove()); + file.add(createMenuItemMove(libOk)); file.addSeparator(); file.add(imprt); file.add(imprtF); @@ -292,6 +409,7 @@ class GuiReaderFrame extends JFrame { JMenuItem vauthors = new JMenuItem("Author"); vauthors.setMnemonic(KeyEvent.VK_A); vauthors.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { words = false; refreshBooks(); @@ -301,6 +419,7 @@ class GuiReaderFrame extends JFrame { JMenuItem vwords = new JMenuItem("Word count"); vwords.setMnemonic(KeyEvent.VK_W); vwords.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { words = true; refreshBooks(); @@ -312,11 +431,16 @@ class GuiReaderFrame extends JFrame { JMenu sources = new JMenu("Sources"); sources.setMnemonic(KeyEvent.VK_S); - List tt = reader.getLibrary().getSources(); + List tt = new ArrayList(); + if (libOk) { + tt.addAll(reader.getLibrary().getSources()); + } tt.add(0, null); + for (final String type : tt) { JMenuItem item = new JMenuItem(type == null ? "All" : type); item.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { removeBookPanes(); addBookPane(type, true); @@ -335,12 +459,16 @@ class GuiReaderFrame extends JFrame { JMenu authors = new JMenu("Authors"); authors.setMnemonic(KeyEvent.VK_A); - List aa = reader.getLibrary().getAuthors(); + List aa = new ArrayList(); + if (libOk) { + aa.addAll(reader.getLibrary().getAuthors()); + } aa.add(0, null); for (final String author : aa) { JMenuItem item = new JMenuItem(author == null ? "All" : author.isEmpty() ? "[unknown]" : author); item.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { removeBookPanes(); addBookPane(author, false); @@ -376,6 +504,7 @@ class GuiReaderFrame extends JFrame { item.setMnemonic(KeyEvent.VK_F); item.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { ConfigEditor ed = new ConfigEditor( Config.class, Instance.getConfig(), @@ -401,6 +530,7 @@ class GuiReaderFrame extends JFrame { item.setMnemonic(KeyEvent.VK_U); item.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { ConfigEditor ed = new ConfigEditor( UiConfig.class, Instance.getUiConfig(), @@ -451,6 +581,7 @@ class GuiReaderFrame extends JFrame { JMenuItem export = new JMenuItem("Save as...", KeyEvent.VK_S); export.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { if (selectedBook != null) { fc.showDialog(GuiReaderFrame.this, "Save"); @@ -461,13 +592,14 @@ class GuiReaderFrame extends JFrame { + type.getDefaultExtension(false); final Progress pg = new Progress(); outOfUi(pg, new Runnable() { + @Override public void run() { try { reader.getLibrary().export( selectedBook.getMeta().getLuid(), type, path, pg); } catch (IOException e) { - Instance.syserr(e); + Instance.getTraceHandler().error(e); } } }); @@ -510,14 +642,18 @@ class GuiReaderFrame extends JFrame { private JMenuItem createMenuItemClearCache() { JMenuItem refresh = new JMenuItem("Clear cache", KeyEvent.VK_C); refresh.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { if (selectedBook != null) { outOfUi(null, new Runnable() { + @Override public void run() { reader.clearLocalReaderCache(selectedBook.getMeta() .getLuid()); selectedBook.setCached(false); + GuiReaderBook.clearIcon(selectedBook.getMeta()); SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { selectedBook.repaint(); } @@ -534,15 +670,20 @@ class GuiReaderFrame extends JFrame { /** * Create the delete menu item. * + * @param libOk + * the library can be queried + * * @return the item */ - private JMenuItem createMenuItemMove() { + private JMenuItem createMenuItemMove(boolean libOk) { JMenu moveTo = new JMenu("Move to..."); moveTo.setMnemonic(KeyEvent.VK_M); List types = new ArrayList(); types.add(null); - types.addAll(reader.getLibrary().getSources()); + if (libOk) { + types.addAll(reader.getLibrary().getSources()); + } for (String type : types) { JMenuItem item = new JMenuItem(type == null ? "New type..." : type); @@ -554,6 +695,7 @@ class GuiReaderFrame extends JFrame { final String ftype = type; item.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { if (selectedBook != null) { String type = ftype; @@ -563,15 +705,17 @@ class GuiReaderFrame extends JFrame { "Moving story", JOptionPane.QUESTION_MESSAGE, null, null, selectedBook.getMeta().getSource()); + if (rep == null) { return; - } else { - type = rep.toString(); } + + type = rep.toString(); } final String ftype = type; outOfUi(null, new Runnable() { + @Override public void run() { reader.changeType(selectedBook.getMeta() .getLuid(), ftype); @@ -579,8 +723,9 @@ class GuiReaderFrame extends JFrame { selectedBook = null; SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - setJMenuBar(createMenu()); + setJMenuBar(createMenu(true)); } }); } @@ -601,13 +746,20 @@ class GuiReaderFrame extends JFrame { private JMenuItem createMenuItemRedownload() { JMenuItem refresh = new JMenuItem("Redownload", KeyEvent.VK_R); refresh.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { if (selectedBook != null) { final MetaData meta = selectedBook.getMeta(); - imprt(meta.getUrl(), new Runnable() { - public void run() { + imprt(meta.getUrl(), new StoryRunnable() { + @Override + public void run(Story story) { reader.delete(meta.getLuid()); GuiReaderFrame.this.selectedBook = null; + MetaData newMeta = story.getMeta(); + if (!newMeta.getSource().equals(meta.getSource())) { + reader.changeType(newMeta.getLuid(), + meta.getSource()); + } } }, "Removing old copy"); } @@ -625,9 +777,11 @@ class GuiReaderFrame extends JFrame { private JMenuItem createMenuItemDelete() { JMenuItem delete = new JMenuItem("Delete", KeyEvent.VK_D); delete.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { if (selectedBook != null) { outOfUi(null, new Runnable() { + @Override public void run() { reader.delete(selectedBook.getMeta().getLuid()); selectedBook = null; @@ -641,16 +795,48 @@ class GuiReaderFrame extends JFrame { } /** - * Create the open menu item. + * Create the open menu item for a book or a source (no LUID). * * @return the item */ private JMenuItem createMenuItemOpenBook() { JMenuItem open = new JMenuItem("Open", KeyEvent.VK_O); open.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { if (selectedBook != null) { - openBook(selectedBook); + if (selectedBook.getMeta().getLuid() == null) { + removeBookPanes(); + addBookPane(selectedBook.getMeta().getSource(), true); + refreshBooks(); + } else { + openBook(selectedBook); + } + } + } + }); + + return open; + } + + /** + * Create the SetCover menu item for a book to change the linked source + * cover. + * + * @return the item + */ + private JMenuItem createMenuItemSetCover() { + JMenuItem open = new JMenuItem("Set as cover for source", KeyEvent.VK_C); + open.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (selectedBook != null) { + reader.getLibrary().setSourceCover( + selectedBook.getMeta().getSource(), + selectedBook.getMeta().getLuid()); + MetaData source = selectedBook.getMeta().clone(); + source.setLuid(null); + GuiReaderBook.clearIcon(source); } } }); @@ -667,17 +853,19 @@ class GuiReaderFrame extends JFrame { private void openBook(final GuiReaderBook book) { final Progress pg = new Progress(); outOfUi(pg, new Runnable() { + @Override public void run() { try { reader.read(book.getMeta().getLuid(), pg); SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { book.setCached(true); } }); } catch (IOException e) { // TODO: error message? - Instance.syserr(e); + Instance.getTraceHandler().error(e); } } }); @@ -711,13 +899,17 @@ class GuiReaderFrame extends JFrame { setEnabled(false); new Thread(new Runnable() { + @Override public void run() { - run.run(); - refreshBooks(); - reload.done(); - if (!pg.isDone()) { - // will trigger pgBar ActionListener: - pg.done(); + try { + run.run(); + refreshBooks(); + } finally { + reload.done(); + if (!pg.isDone()) { + // will trigger pgBar ActionListener: + pg.done(); + } } } }, "outOfUi thread").start(); @@ -773,7 +965,7 @@ class GuiReaderFrame extends JFrame { * @param onSuccess * Action to execute on success */ - private void imprt(final String url, final Runnable onSuccess, + private void imprt(final String url, final StoryRunnable onSuccess, String onSuccessPgName) { final Progress pg = new Progress(); final Progress pgImprt = new Progress(); @@ -782,10 +974,13 @@ class GuiReaderFrame extends JFrame { pg.addProgress(pgOnSuccess, 5); outOfUi(pg, new Runnable() { + @Override public void run() { Exception ex = null; + Story story = null; try { - reader.getLibrary().imprt(BasicReader.getUrl(url), pgImprt); + story = reader.getLibrary().imprt(BasicReader.getUrl(url), + pgImprt); } catch (IOException e) { ex = e; } @@ -796,17 +991,16 @@ class GuiReaderFrame extends JFrame { pgOnSuccess.setProgress(0); if (!ok) { - Instance.syserr(e); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - JOptionPane.showMessageDialog(GuiReaderFrame.this, - "Cannot import: " + url, e.getMessage(), - JOptionPane.ERROR_MESSAGE); - } - }); + if (e instanceof UnknownHostException) { + error("URL not supported: " + url, "Cannot import URL", + null); + } else { + error("Failed to import " + url + ": \n" + + e.getMessage(), "Cannot import URL", e); + } } else { if (onSuccess != null) { - onSuccess.run(); + onSuccess.run(story); } } pgOnSuccess.done(); @@ -840,4 +1034,29 @@ class GuiReaderFrame extends JFrame { super.setEnabled(b); repaint(); } + + /** + * Display an error message and log the linked {@link Exception}. + * + * @param message + * the message + * @param title + * the title of the error message + * @param e + * the exception to log if any + */ + private void error(final String message, final String title, Exception e) { + Instance.getTraceHandler().error(title + ": " + message); + if (e != null) { + Instance.getTraceHandler().error(e); + } + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(GuiReaderFrame.this, message, + title, JOptionPane.ERROR_MESSAGE); + } + }); + } }