GUI: Update internal viewer:
authorNiki Roo <niki@nikiroo.be>
Sun, 24 Mar 2019 14:03:23 +0000 (15:03 +0100)
committerNiki Roo <niki@nikiroo.be>
Sun, 24 Mar 2019 14:03:23 +0000 (15:03 +0100)
- text viewer seems OK
- images viewer still need resize
- check why at least one CBZ story has an empty chapter 1

src/be/nikiroo/fanfix/reader/ui/GuiReader.java
src/be/nikiroo/fanfix/reader/ui/GuiReaderViewer.java [moved from src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewer.java with 55% similarity]
src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerPanel.java [new file with mode: 0644]
src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerTextOutput.java [moved from src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewerOutput.java with 94% similarity]

index 620df26075159b7560977bc65d8733733d692d9b..f97ffddd48a08cf8317d5adbdca682d754796d72 100644 (file)
@@ -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);
similarity index 55%
rename from src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewer.java
rename to src/be/nikiroo/fanfix/reader/ui/GuiReaderViewer.java
index 281f082a0b82aa3842d59d12abedaa948ca4e0f6..48dfa498472421904516009260c34e371cf1526a 100644 (file)
@@ -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.
+ * <p>
+ * 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.
+        * <p>
+        * 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("<HTML>&nbsp;&nbsp;<B>Chapter "
                                        + chap.getNumber() + "</B>: " + chap.getName() + "</HTML>");
 
-                       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 (file)
index 0000000..1ff4fcc
--- /dev/null
@@ -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.
+        * <p>
+        * Will always be text for a non-image document.
+        * <p>
+        * 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' <tt>enabled</tt> 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.");
+                       }
+               }
+       }
+}
similarity index 94%
rename from src/be/nikiroo/fanfix/reader/ui/GuiReaderTextViewerOutput.java
rename to src/be/nikiroo/fanfix/reader/ui/GuiReaderViewerTextOutput.java
index d247c1cfa01fc613dc92320f5a4248f8f338096a..c5f7943c17ed9eab4a03eb0d0a22f4c3b3eeb26e 100644 (file)
@@ -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();