From d3c84ac3317780016a5a6fff263ac8ff46220db9 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Thu, 16 Feb 2017 20:31:36 +0100 Subject: [PATCH] Fix CBZ importer, improve GUI - CBZ importer was not sorting the images, they were often reversed - The GUI is improved (~fixed book size, scroll, wrapping, better highlight colours) --- .../fanfix/reader/LocalReaderBook.java | 49 +++-- .../fanfix/reader/LocalReaderFrame.java | 10 +- src/be/nikiroo/fanfix/reader/WrapLayout.java | 201 ++++++++++++++++++ src/be/nikiroo/fanfix/supported/Cbz.java | 21 +- 4 files changed, 255 insertions(+), 26 deletions(-) create mode 100644 src/be/nikiroo/fanfix/reader/WrapLayout.java diff --git a/src/be/nikiroo/fanfix/reader/LocalReaderBook.java b/src/be/nikiroo/fanfix/reader/LocalReaderBook.java index 7fc8171c..ef6ba485 100644 --- a/src/be/nikiroo/fanfix/reader/LocalReaderBook.java +++ b/src/be/nikiroo/fanfix/reader/LocalReaderBook.java @@ -2,7 +2,9 @@ package be.nikiroo.fanfix.reader; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.image.BufferedImage; @@ -14,6 +16,7 @@ import java.util.List; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.JTextArea; import be.nikiroo.fanfix.data.MetaData; @@ -48,8 +51,8 @@ class LocalReaderBook extends JPanel { private static final long serialVersionUID = 1L; private JLabel icon; - private JLabel title; - private JLabel author; + private JTextArea title; + private JTextArea author; private boolean selected; private boolean hovered; private Date lastClick; @@ -69,8 +72,12 @@ class LocalReaderBook extends JPanel { icon = new JLabel(" [ no cover ] "); } - title = new JLabel(meta.getTitle()); - author = new JLabel("by " + meta.getAuthor()); + title = new JTextArea(meta.getTitle()); + title.setWrapStyleWord(true); + title.setLineWrap(true); + title.setEditable(false); + title.setBackground(new Color(0, true)); + author = new JTextArea("by " + meta.getAuthor()); this.setLayout(new BorderLayout()); this.add(icon, BorderLayout.CENTER); @@ -97,24 +104,12 @@ class LocalReaderBook extends JPanel { */ public void setSelected(boolean selected) { this.selected = selected; - fixColor(); + repaint(); } private void setHovered(boolean hovered) { this.hovered = hovered; - fixColor(); - } - - private void fixColor() { - if (selected && !hovered) { - setBackground(new Color(180, 180, 255)); - } else if (!selected && hovered) { - setBackground(new Color(230, 230, 255)); - } else if (selected && hovered) { - setBackground(new Color(200, 200, 255)); - } else { - setBackground(new Color(255, 255, 255)); - } + repaint(); } private void setupListeners() { @@ -160,4 +155,22 @@ class LocalReaderBook extends JPanel { public void addActionListener(BookActionListner listener) { listeners.add(listener); } + + @Override + public void paint(Graphics g) { + super.paint(g); + + Color color = new Color(255, 255, 255, 0); + if (selected && !hovered) { + color = new Color(80, 80, 100, 40); + } else if (!selected && hovered) { + color = new Color(230, 230, 255, 100); + } else if (selected && hovered) { + color = new Color(200, 200, 255, 100); + } + + Rectangle clip = g.getClipBounds(); + g.setColor(color); + g.fillRect(clip.x, clip.y, clip.width, clip.height); + } } diff --git a/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java b/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java index ed8a0390..dd9a8f2e 100644 --- a/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java +++ b/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java @@ -1,7 +1,7 @@ package be.nikiroo.fanfix.reader; +import java.awt.BorderLayout; import java.awt.Desktop; -import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; @@ -17,6 +17,7 @@ import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JScrollPane; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.Main; @@ -38,11 +39,12 @@ class LocalReaderFrame extends JFrame { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(800, 600); - setLayout(new FlowLayout()); + setLayout(new BorderLayout()); books = new ArrayList(); - bookPane = new JPanel(); - add(bookPane); + bookPane = new JPanel(new WrapLayout(WrapLayout.LEADING)); + + add(new JScrollPane(bookPane), BorderLayout.CENTER); refreshBooks(type); setJMenuBar(createMenu()); diff --git a/src/be/nikiroo/fanfix/reader/WrapLayout.java b/src/be/nikiroo/fanfix/reader/WrapLayout.java new file mode 100644 index 00000000..3c23a540 --- /dev/null +++ b/src/be/nikiroo/fanfix/reader/WrapLayout.java @@ -0,0 +1,201 @@ +package be.nikiroo.fanfix.reader; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; + +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +/** + * FlowLayout subclass that fully supports wrapping of components. + * + * @author https://tips4java.wordpress.com/2008/11/06/wrap-layout/ + */ +class WrapLayout extends FlowLayout { + private static final long serialVersionUID = 1L; + + /** + * Constructs a new WrapLayout with a left alignment and a + * default 5-unit horizontal and vertical gap. + */ + public WrapLayout() { + super(); + } + + /** + * Constructs a new FlowLayout with the specified alignment and + * a default 5-unit horizontal and vertical gap. The value of the alignment + * argument must be one of WrapLayout, WrapLayout, + * or WrapLayout. + * + * @param align + * the alignment value + */ + public WrapLayout(int align) { + super(align); + } + + /** + * Creates a new flow layout manager with the indicated alignment and the + * indicated horizontal and vertical gaps. + *

+ * The value of the alignment argument must be one of + * WrapLayout, WrapLayout, or + * WrapLayout. + * + * @param align + * the alignment value + * @param hgap + * the horizontal gap between components + * @param vgap + * the vertical gap between components + */ + public WrapLayout(int align, int hgap, int vgap) { + super(align, hgap, vgap); + } + + /** + * Returns the preferred dimensions for this layout given the visible + * components in the specified target container. + * + * @param target + * the component which needs to be laid out + * @return the preferred dimensions to lay out the subcomponents of the + * specified container + */ + @Override + public Dimension preferredLayoutSize(Container target) { + return layoutSize(target, true); + } + + /** + * Returns the minimum dimensions needed to layout the visible + * components contained in the specified target container. + * + * @param target + * the component which needs to be laid out + * @return the minimum dimensions to lay out the subcomponents of the + * specified container + */ + @Override + public Dimension minimumLayoutSize(Container target) { + Dimension minimum = layoutSize(target, false); + minimum.width -= (getHgap() + 1); + return minimum; + } + + /** + * Returns the minimum or preferred dimension needed to layout the target + * container. + * + * @param target + * target to get layout size for + * @param preferred + * should preferred size be calculated + * @return the dimension to layout the target container + */ + private Dimension layoutSize(Container target, boolean preferred) { + synchronized (target.getTreeLock()) { + // Each row must fit with the width allocated to the containter. + // When the container width = 0, the preferred width of the + // container + // has not yet been calculated so lets ask for the maximum. + + int targetWidth = target.getSize().width; + Container container = target; + + while (container.getSize().width == 0 + && container.getParent() != null) { + container = container.getParent(); + } + + targetWidth = container.getSize().width; + + if (targetWidth == 0) + targetWidth = Integer.MAX_VALUE; + + int hgap = getHgap(); + int vgap = getVgap(); + Insets insets = target.getInsets(); + int horizontalInsetsAndGap = insets.left + insets.right + + (hgap * 2); + int maxWidth = targetWidth - horizontalInsetsAndGap; + + // Fit components into the allowed width + + Dimension dim = new Dimension(0, 0); + int rowWidth = 0; + int rowHeight = 0; + + int nmembers = target.getComponentCount(); + + for (int i = 0; i < nmembers; i++) { + Component m = target.getComponent(i); + + if (m.isVisible()) { + Dimension d = preferred ? m.getPreferredSize() : m + .getMinimumSize(); + + // Can't add the component to current row. Start a new row. + + if (rowWidth + d.width > maxWidth) { + addRow(dim, rowWidth, rowHeight); + rowWidth = 0; + rowHeight = 0; + } + + // Add a horizontal gap for all components after the first + + if (rowWidth != 0) { + rowWidth += hgap; + } + + rowWidth += d.width; + rowHeight = Math.max(rowHeight, d.height); + } + } + + addRow(dim, rowWidth, rowHeight); + + dim.width += horizontalInsetsAndGap; + dim.height += insets.top + insets.bottom + vgap * 2; + + // When using a scroll pane or the DecoratedLookAndFeel we need to + // make sure the preferred size is less than the size of the + // target containter so shrinking the container size works + // correctly. Removing the horizontal gap is an easy way to do this. + + Container scrollPane = SwingUtilities.getAncestorOfClass( + JScrollPane.class, target); + + if (scrollPane != null && target.isValid()) { + dim.width -= (hgap + 1); + } + + return dim; + } + } + + /* + * A new row has been completed. Use the dimensions of this row to update + * the preferred size for the container. + * + * @param dim update the width and height when appropriate + * + * @param rowWidth the width of the row to add + * + * @param rowHeight the height of the row to add + */ + private void addRow(Dimension dim, int rowWidth, int rowHeight) { + dim.width = Math.max(dim.width, rowWidth); + + if (dim.height > 0) { + dim.height += getVgap(); + } + + dim.height += rowHeight; + } +} diff --git a/src/be/nikiroo/fanfix/supported/Cbz.java b/src/be/nikiroo/fanfix/supported/Cbz.java index f9eee08d..1080ad27 100644 --- a/src/be/nikiroo/fanfix/supported/Cbz.java +++ b/src/be/nikiroo/fanfix/supported/Cbz.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -60,6 +62,7 @@ class Cbz extends Epub { ZipInputStream zipIn = new ZipInputStream(getInput()); + List images = new ArrayList(); for (ZipEntry entry = zipIn.getNextEntry(); entry != null; entry = zipIn .getNextEntry()) { if (!entry.isDirectory() @@ -73,12 +76,10 @@ class Cbz extends Epub { } if (imageEntry) { + String uuid = meta.getUuid() + "_" + entry.getName(); + images.add(uuid); try { - String uuid = meta.getUuid() + "_" + entry.getName(); - Instance.getCache().addToCache(zipIn, uuid); - chap.getParagraphs().add( - new Paragraph(new File(uuid).toURI().toURL())); } catch (Exception e) { Instance.syserr(e); } @@ -86,6 +87,18 @@ class Cbz extends Epub { } } + // ZIP order is not sure + Collections.sort(images); + + for (String uuid : images) { + try { + chap.getParagraphs().add( + new Paragraph(new File(uuid).toURI().toURL())); + } catch (Exception e) { + Instance.syserr(e); + } + } + return story; } } -- 2.27.0