X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Freader%2FLocalReaderFrame.java;h=81ebbeff11a8732325e570388181c61402b6f57d;hb=9843a5e5c44825ac404f45ddccd6f63e554567a4;hp=d431d8e452ff821a375b07dd2a1ac19c4173344f;hpb=92fb0719f84f5b6734b51e528332546d78e9ccec;p=fanfix.git diff --git a/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java b/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java index d431d8e..81ebbef 100644 --- a/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java +++ b/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java @@ -6,26 +6,32 @@ import java.awt.Desktop; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; import be.nikiroo.fanfix.Instance; -import be.nikiroo.fanfix.Main; import be.nikiroo.fanfix.bundles.UiConfig; import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.reader.LocalReaderBook.BookActionListener; -import be.nikiroo.utils.WrapLayout; +import be.nikiroo.utils.Progress; +import be.nikiroo.utils.ui.ProgressBar; +import be.nikiroo.utils.ui.WrapLayout; class LocalReaderFrame extends JFrame { private static final long serialVersionUID = 1L; @@ -35,6 +41,9 @@ class LocalReaderFrame extends JFrame { private JPanel bookPane; private String type; private Color color; + private ProgressBar pgBar; + private JMenuBar bar; + private LocalReaderBook selectedBook; public LocalReaderFrame(LocalReader reader, String type) { super("Fanfix Library"); @@ -48,18 +57,7 @@ class LocalReaderFrame extends JFrame { books = new ArrayList(); bookPane = new JPanel(new WrapLayout(WrapLayout.LEADING, 5, 5)); - color = null; - String bg = Instance.getUiConfig().getString(UiConfig.BACKGROUND_COLOR); - if (bg.startsWith("#") && bg.length() == 7) { - try { - color = new Color(Integer.parseInt(bg.substring(1, 3), 16), - Integer.parseInt(bg.substring(3, 5), 16), - Integer.parseInt(bg.substring(5, 7), 16)); - } catch (NumberFormatException e) { - color = null; // no changes - e.printStackTrace(); - } - } + color = Instance.getUiConfig().getColor(UiConfig.BACKGROUND_COLOR); if (color != null) { setBackground(color); @@ -70,6 +68,9 @@ class LocalReaderFrame extends JFrame { scroll.getVerticalScrollBar().setUnitIncrement(16); add(scroll, BorderLayout.CENTER); + pgBar = new ProgressBar(); + add(pgBar, BorderLayout.SOUTH); + refreshBooks(type); setJMenuBar(createMenu()); @@ -82,28 +83,64 @@ class LocalReaderFrame extends JFrame { books.clear(); bookPane.removeAll(); for (MetaData meta : stories) { - LocalReaderBook book = new LocalReaderBook(meta); + LocalReaderBook book = new LocalReaderBook(meta, + reader.isCached(meta.getLuid())); if (color != null) { book.setBackground(color); } + book.addMouseListener(new MouseListener() { + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) + pop(e); + } + + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) + pop(e); + } + + public void mouseExited(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseClicked(MouseEvent e) { + } + + private void pop(MouseEvent e) { + JPopupMenu popup = new JPopupMenu(); + popup.add(createMenuItemExport()); + popup.add(createMenuItemRefresh()); + popup.addSeparator(); + popup.add(createMenuItemDelete()); + // popup.show(e.getComponent(), e.getX(), e.getY()); + } + }); + books.add(book); - final String luid = meta.getLuid(); book.addActionListener(new BookActionListener() { public void select(LocalReaderBook book) { + selectedBook = book; for (LocalReaderBook abook : books) { abook.setSelected(abook == book); } } - public void action(LocalReaderBook book) { - try { - File target = LocalReaderFrame.this.reader.getTarget( - luid, null); - Desktop.getDesktop().browse(target.toURI()); - } catch (IOException e) { - Instance.syserr(e); - } + public void popupRequested(LocalReaderBook book, MouseEvent e) { + JPopupMenu popup = new JPopupMenu(); + popup.add(createMenuItemOpenBook()); + popup.addSeparator(); + popup.add(createMenuItemExport()); + popup.add(createMenuItemRefresh()); + popup.addSeparator(); + popup.add(createMenuItemDelete()); + popup.show(e.getComponent(), e.getX(), e.getY()); + } + + public void action(final LocalReaderBook book) { + openBook(book); } }); @@ -115,41 +152,23 @@ class LocalReaderFrame extends JFrame { } private JMenuBar createMenu() { - JMenuBar bar = new JMenuBar(); + bar = new JMenuBar(); JMenu file = new JMenu("File"); + file.setMnemonic(KeyEvent.VK_F); - JMenuItem imprt = new JMenuItem("Import", KeyEvent.VK_I); + JMenuItem imprt = new JMenuItem("Import URL", KeyEvent.VK_U); imprt.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - String url = JOptionPane.showInputDialog(LocalReaderFrame.this, - "url of the story to import?\n" + "\n" - + "Note: it will currently make the UI \n" - + "unresponsive until it is downloaded...", - "Importing from URL", JOptionPane.QUESTION_MESSAGE); - if (url != null && !url.isEmpty()) { - if (Main.imprt(url, null) != 0) { - JOptionPane.showMessageDialog(LocalReaderFrame.this, - "Cannot import: " + url, "Imort error", - JOptionPane.ERROR_MESSAGE); - } else { - refreshBooks(type); - } - } + imprt(true); + } + }); + JMenuItem imprtF = new JMenuItem("Import File", KeyEvent.VK_F); + imprtF.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + imprt(false); } }); - JMenu types = new JMenu("Type"); - List tt = Instance.getLibrary().getTypes(); - tt.add(0, null); - for (final String type : tt) { - JMenuItem item = new JMenuItem(type == null ? "[all]" : type); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - refreshBooks(type); - } - }); - types.add(item); - } JMenuItem exit = new JMenuItem("Exit", KeyEvent.VK_X); exit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -158,13 +177,258 @@ class LocalReaderFrame extends JFrame { } }); + file.add(createMenuItemOpenBook()); + file.add(createMenuItemExport()); + file.addSeparator(); file.add(imprt); - file.add(types); + file.add(imprtF); file.addSeparator(); file.add(exit); bar.add(file); + JMenu edit = new JMenu("Edit"); + edit.setMnemonic(KeyEvent.VK_E); + + edit.add(createMenuItemRefresh()); + edit.addSeparator(); + edit.add(createMenuItemDelete()); + + bar.add(edit); + + JMenu view = new JMenu("View"); + view.setMnemonic(KeyEvent.VK_V); + + List tt = Instance.getLibrary().getTypes(); + tt.add(0, null); + for (final String type : tt) { + + JMenuItem item = new JMenuItem(type == null ? "All books" : type); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + refreshBooks(type); + } + }); + view.add(item); + + if (type == null) { + view.addSeparator(); + } + } + + bar.add(view); + return bar; } + + private JMenuItem createMenuItemExport() { + // TODO + final String notYet = "[TODO] not ready yet, but you can do it on command line, see: fanfix --help"; + + JMenuItem export = new JMenuItem("Save as...", KeyEvent.VK_E); + export.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JOptionPane.showMessageDialog(LocalReaderFrame.this, notYet); + } + }); + + return export; + } + + private JMenuItem createMenuItemRefresh() { + JMenuItem refresh = new JMenuItem("Refresh", KeyEvent.VK_R); + refresh.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (selectedBook != null) { + outOfUi(null, new Runnable() { + public void run() { + reader.refresh(selectedBook.getLuid()); + selectedBook.setCached(false); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + selectedBook.repaint(); + } + }); + } + }); + } + } + }); + + return refresh; + } + + private JMenuItem createMenuItemDelete() { + JMenuItem delete = new JMenuItem("Delete", KeyEvent.VK_D); + delete.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (selectedBook != null) { + outOfUi(null, new Runnable() { + public void run() { + reader.delete(selectedBook.getLuid()); + selectedBook = null; + SwingUtilities.invokeLater(new Runnable() { + public void run() { + refreshBooks(type); + } + }); + } + }); + } + } + }); + + return delete; + } + + private JMenuItem createMenuItemOpenBook() { + JMenuItem open = new JMenuItem("Open", KeyEvent.VK_O); + open.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (selectedBook != null) { + openBook(selectedBook); + } + } + }); + + return open; + } + + private void openBook(final LocalReaderBook book) { + final Progress pg = new Progress(); + outOfUi(pg, new Runnable() { + public void run() { + try { + File target = LocalReaderFrame.this.reader.getTarget( + book.getLuid(), pg); + book.setCached(true); + // TODO: allow custom programs, with + // Desktop/xdg-open fallback + try { + Desktop.getDesktop().browse(target.toURI()); + } catch (UnsupportedOperationException e) { + String browsers[] = new String[] { "xdg-open", + "epiphany", "konqueror", "firefox", "chrome", + "google-chrome", "mozilla" }; + + Runtime runtime = Runtime.getRuntime(); + for (String browser : browsers) { + try { + runtime.exec(new String[] { browser, + target.getAbsolutePath() }); + runtime = null; + break; + } catch (IOException ioe) { + // continue, try next browser + } + } + + if (runtime != null) { + throw new IOException( + "Cannot find a working GUI browser..."); + } + } + } catch (IOException e) { + Instance.syserr(e); + } + } + }); + } + + private void outOfUi(final Progress pg, final Runnable run) { + pgBar.setProgress(pg); + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + setAllEnabled(false); + pgBar.addActioListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + pgBar.setProgress(null); + setAllEnabled(true); + } + }); + } + }); + + new Thread(new Runnable() { + public void run() { + run.run(); + if (pg == null) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + setAllEnabled(true); + } + }); + } else if (!pg.isDone()) { + pg.setProgress(pg.getMax()); + } + } + }).start(); + } + + private void imprt(boolean askUrl) { + JFileChooser fc = new JFileChooser(); + + final String url; + if (askUrl) { + url = JOptionPane.showInputDialog(LocalReaderFrame.this, + "url of the story to import?", "Importing from URL", + JOptionPane.QUESTION_MESSAGE); + } else if (fc.showOpenDialog(this) != JFileChooser.CANCEL_OPTION) { + url = fc.getSelectedFile().getAbsolutePath(); + } else { + url = null; + } + + if (url != null && !url.isEmpty()) { + final Progress pg = new Progress("Importing " + url); + outOfUi(pg, new Runnable() { + public void run() { + Exception ex = null; + try { + Instance.getLibrary() + .imprt(BasicReader.getUrl(url), pg); + } catch (IOException e) { + ex = e; + } + + final Exception e = ex; + + final boolean ok = (e == null); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + if (!ok) { + JOptionPane.showMessageDialog( + LocalReaderFrame.this, + "Cannot import: " + url, + e.getMessage(), + JOptionPane.ERROR_MESSAGE); + + setAllEnabled(true); + } else { + refreshBooks(type); + } + } + }); + } + }); + } + } + + public void setAllEnabled(boolean enabled) { + for (LocalReaderBook book : books) { + book.setEnabled(enabled); + book.validate(); + book.repaint(); + } + + bar.setEnabled(enabled); + bookPane.setEnabled(enabled); + bookPane.validate(); + bookPane.repaint(); + + setEnabled(enabled); + validate(); + repaint(); + } }