From 32ba91e9d2443ac9d17d3db66eef4c570d02cdf1 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 24 Mar 2019 15:03:23 +0100 Subject: [PATCH] GUI: Update internal viewer: - text viewer seems OK - images viewer still need resize - check why at least one CBZ story has an empty chapter 1 --- .../nikiroo/fanfix/reader/ui/GuiReader.java | 4 +- ...erTextViewer.java => GuiReaderViewer.java} | 112 ++++++++---- .../reader/ui/GuiReaderViewerPanel.java | 164 ++++++++++++++++++ ...ut.java => GuiReaderViewerTextOutput.java} | 6 +- 4 files changed, 247 insertions(+), 39 deletions(-) rename src/be/nikiroo/fanfix/reader/ui/{GuiReaderTextViewer.java => GuiReaderViewer.java} (55%) create mode 100644 src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerPanel.java rename src/be/nikiroo/fanfix/reader/ui/{GuiReaderTextViewerOutput.java => GuiReaderViewerTextOutput.java} (94%) diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReader.java b/src/be/nikiroo/fanfix/reader/ui/GuiReader.java index 620df26..f97ffdd 100644 --- a/src/be/nikiroo/fanfix/reader/ui/GuiReader.java +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReader.java @@ -268,10 +268,10 @@ class GuiReader extends BasicReader { void read(String luid, boolean sync, Progress pg) throws IOException { File file = cacheLib.getFile(luid, pg); - GuiReaderTextViewer viewer = new GuiReaderTextViewer(cacheLib, + GuiReaderViewer viewer = new GuiReaderViewer(cacheLib, cacheLib.getStory(luid, null)); - // TODO: testing text viewer: + // TODO: testing internal story viewer: if (false) { if (sync) { sync(viewer); diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewer.java b/src/be/nikiroo/fanfix/reader/ui/GuiReaderViewer.java similarity index 55% rename from src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewer.java rename to src/be/nikiroo/fanfix/reader/ui/GuiReaderViewer.java index 281f082..48dfa49 100644 --- a/src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewer.java +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReaderViewer.java @@ -13,7 +13,6 @@ import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.JScrollPane; import javax.swing.SwingConstants; import be.nikiroo.fanfix.data.Chapter; @@ -21,19 +20,35 @@ import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.data.Story; import be.nikiroo.fanfix.library.BasicLibrary; -public class GuiReaderTextViewer extends JFrame { +/** + * An internal, Swing-based {@link Story} viewer. + *

+ * Works on both text and image document (see {@link MetaData#isImageDocument()} + * ). + * + * @author niki + */ +public class GuiReaderViewer extends JFrame { private static final long serialVersionUID = 1L; private Story story; private MetaData meta; private JLabel title; - private JLabel text; private JLabel chapterLabel; private GuiReaderPropertiesPane descPane; private int currentChapter = -42; // cover = -1 - private GuiReaderTextViewerOutput htmlOutput = new GuiReaderTextViewerOutput(); - - public GuiReaderTextViewer(BasicLibrary lib, Story story) { + private GuiReaderViewerPanel mainPanel; + private JButton[] navButtons; + + /** + * Create a new {@link Story} viewer. + * + * @param lib + * the {@link BasicLibrary} to load the cover from + * @param story + * the {@link Story} to display + */ + public GuiReaderViewer(BasicLibrary lib, Story story) { super(story.getMeta().getLuid() + ": " + story.getMeta().getTitle()); setSize(800, 600); @@ -47,6 +62,13 @@ public class GuiReaderTextViewer extends JFrame { setChapter(-1); } + /** + * Initialise the base panel with everything but the navigation buttons. + * + * @param lib + * the {@link BasicLibrary} to use to retrieve the cover image in + * the description panel + */ private void initGuiBase(BasicLibrary lib) { setLayout(new BorderLayout()); @@ -64,53 +86,65 @@ public class GuiReaderTextViewer extends JFrame { descPane = new GuiReaderPropertiesPane(lib, meta); contentPane.add(descPane, BorderLayout.NORTH); - text = new JLabel(); - text.setAlignmentY(TOP_ALIGNMENT); - - // TODO: why is it broken? - // text.setPreferredSize(new Dimension(500, 500)); - - JScrollPane scroll = new JScrollPane(text); - scroll.getVerticalScrollBar().setUnitIncrement(16); - contentPane.add(scroll, BorderLayout.CENTER); + mainPanel = new GuiReaderViewerPanel(story); + contentPane.add(mainPanel, BorderLayout.CENTER); } + /** + * Create the 4 navigation buttons in {@link GuiReaderViewer#navButtons} and + * initialise them. + */ private void initGuiNavButtons() { - JPanel navButtons = new JPanel(); - LayoutManager layout = new BoxLayout(navButtons, BoxLayout.X_AXIS); - navButtons.setLayout(layout); + JPanel navButtonsPane = new JPanel(); + LayoutManager layout = new BoxLayout(navButtonsPane, BoxLayout.X_AXIS); + navButtonsPane.setLayout(layout); - navButtons.add(createNavButton("<<", new ActionListener() { + navButtons = new JButton[4]; + + navButtons[0] = createNavButton("<<", new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setChapter(-1); } - })); - navButtons.add(createNavButton(" < ", new ActionListener() { + }); + navButtons[1] = createNavButton(" < ", new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setChapter(currentChapter - 1); } - })); - navButtons.add(createNavButton(" > ", new ActionListener() { + }); + navButtons[2] = createNavButton(" > ", new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setChapter(currentChapter + 1); } - })); - navButtons.add(createNavButton(">>", new ActionListener() { + }); + navButtons[3] = createNavButton(">>", new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setChapter(story.getChapters().size() - 1); } - })); + }); - add(navButtons, BorderLayout.SOUTH); + for (JButton navButton : navButtons) { + navButtonsPane.add(navButton); + } + + add(navButtonsPane, BorderLayout.SOUTH); chapterLabel = new JLabel(""); - navButtons.add(chapterLabel); + navButtonsPane.add(chapterLabel); } + /** + * Create a single navigation button. + * + * @param text + * the text to display + * @param action + * the action to take on click + * @return the button + */ private JButton createNavButton(String text, ActionListener action) { JButton navButton = new JButton(text); navButton.addActionListener(action); @@ -118,7 +152,20 @@ public class GuiReaderTextViewer extends JFrame { return navButton; } + /** + * Set the current chapter, 0-based. + *

+ * Chapter -1 is reserved for the description page. + * + * @param chapter + * the chapter number to set + */ private void setChapter(int chapter) { + navButtons[0].setEnabled(chapter >= 0); + navButtons[1].setEnabled(chapter >= 0); + navButtons[2].setEnabled(chapter + 1 < story.getChapters().size()); + navButtons[3].setEnabled(chapter + 1 < story.getChapters().size()); + if (chapter >= -1 && chapter < story.getChapters().size() && chapter != currentChapter) { currentChapter = chapter; @@ -126,7 +173,7 @@ public class GuiReaderTextViewer extends JFrame { Chapter chap; if (chapter == -1) { chap = meta.getResume(); - setCoverPage(); + descPane.setVisible(true); } else { chap = story.getChapters().get(chapter); descPane.setVisible(false); @@ -135,11 +182,8 @@ public class GuiReaderTextViewer extends JFrame { chapterLabel.setText("  Chapter " + chap.getNumber() + ": " + chap.getName() + ""); - text.setText(htmlOutput.convert(chap)); + System.out.println(chap); + mainPanel.setChapter(chap); } } - - private void setCoverPage() { - descPane.setVisible(true); - } } diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerPanel.java b/src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerPanel.java new file mode 100644 index 0000000..1ff4fcc --- /dev/null +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerPanel.java @@ -0,0 +1,164 @@ +package be.nikiroo.fanfix.reader.ui; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; + +import be.nikiroo.fanfix.Instance; +import be.nikiroo.fanfix.data.Chapter; +import be.nikiroo.fanfix.data.Story; +import be.nikiroo.utils.Image; +import be.nikiroo.utils.ui.ImageUtilsAwt; + +/** + * A {@link JPanel} that will show a {@link Story} chapter on screen. + * + * @author niki + */ +public class GuiReaderViewerPanel extends JPanel { + private static final long serialVersionUID = 1L; + + private boolean imageDocument; + private Chapter chap; + + private JLabel label; + private GuiReaderViewerTextOutput htmlOutput; + private JProgressBar imageProgress; + private int currentImage; + private JButton left; + private JButton right; + + /** + * Create a new viewer. + * + * @param story + * the {@link Story} to work on. + */ + public GuiReaderViewerPanel(Story story) { + super(new BorderLayout()); + + this.imageDocument = story.getMeta().isImageDocument(); + this.label = new JLabel(); + label.setAlignmentY(TOP_ALIGNMENT); + htmlOutput = new GuiReaderViewerTextOutput(); + + if (!imageDocument) { + // TODO: why is it broken? + // text.setPreferredSize(new Dimension(500, 500)); + + JScrollPane scroll = new JScrollPane(label); + scroll.getVerticalScrollBar().setUnitIncrement(16); + + add(scroll, BorderLayout.CENTER); + } else { + imageProgress = new JProgressBar(); + imageProgress.setStringPainted(true); + add(imageProgress, BorderLayout.SOUTH); + + JPanel main = new JPanel(new BorderLayout()); + main.add(label, BorderLayout.CENTER); + + left = new JButton(" < "); + left.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setImage(--currentImage); + } + }); + main.add(left, BorderLayout.WEST); + + right = new JButton(" > "); + right.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setImage(++currentImage); + } + }); + main.add(right, BorderLayout.EAST); + + add(main, BorderLayout.CENTER); + } + + setChapter(story.getMeta().getResume()); + } + + /** + * Load the given chapter. + *

+ * Will always be text for a non-image document. + *

+ * Will be an image and left/right controls for an image-document, except + * for chapter 0 which will be text (chapter 0 = resume). + * + * @param chap + * the chapter to load + */ + public void setChapter(Chapter chap) { + this.chap = chap; + + if (!imageDocument) { + label.setText(htmlOutput.convert(chap)); + } else { + left.setVisible(chap.getNumber() > 0); + right.setVisible(chap.getNumber() > 0); + imageProgress.setVisible(chap.getNumber() > 0); + + imageProgress.setMinimum(0); + imageProgress.setMaximum(chap.getParagraphs().size() - 1); + + if (chap.getNumber() == 0) { + label.setText(htmlOutput.convert(chap)); + } else { + setImage(0); + } + } + } + + /** + * Will set and display the current image, take care about the progression + * and update the left and right cursors' enabled property. + * + * @param i + * the image index to load + */ + private void setImage(int i) { + left.setEnabled(i > 0); + right.setEnabled(i + 1 < chap.getParagraphs().size()); + + if (i < 0 || i >= chap.getParagraphs().size()) { + return; + } + + imageProgress.setValue(i); + imageProgress.setString(String.format("Image %d / %d", i + 1, chap + .getParagraphs().size())); + + currentImage = i; + label.setText(""); + label.setIcon(null); + + Image img = chap.getParagraphs().get(i).getContentImage(); + if (img == null) { + label.setText("Error: cannot render image."); + } else { + try { + BufferedImage buffImg = ImageUtilsAwt.fromImage(img); + Icon icon = new ImageIcon(buffImg); + label.setIcon(icon); + } catch (Exception e) { + Instance.getTraceHandler().error( + new Exception("Failed to load image into label", e)); + label.setText("Error: cannot load image."); + } + } + } +} diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewerOutput.java b/src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerTextOutput.java similarity index 94% rename from src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewerOutput.java rename to src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerTextOutput.java index d247c1c..c5f7943 100644 --- a/src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewerOutput.java +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerTextOutput.java @@ -14,16 +14,16 @@ import be.nikiroo.fanfix.output.BasicOutput; * * @author niki */ -public class GuiReaderTextViewerOutput { +public class GuiReaderViewerTextOutput { private StringBuilder builder; private BasicOutput output; private Story fakeStory; /** - * Create a new {@link GuiReaderTextViewerOutput} that will convert a + * Create a new {@link GuiReaderViewerTextOutput} that will convert a * {@link Chapter} into HTML3 suited for Java Swing. */ - public GuiReaderTextViewerOutput() { + public GuiReaderViewerTextOutput() { builder = new StringBuilder(); fakeStory = new Story(); -- 2.27.0