Internal text viewer is now OK
authorNiki Roo <niki@nikiroo.be>
Sun, 3 May 2020 22:29:45 +0000 (00:29 +0200)
committerNiki Roo <niki@nikiroo.be>
Sun, 3 May 2020 22:29:45 +0000 (00:29 +0200)
src/be/nikiroo/fanfix_swing/Actions.java
src/be/nikiroo/fanfix_swing/gui/search/SearchAction.java
src/be/nikiroo/fanfix_swing/gui/viewer/TODEL_ViewerPanel.java [moved from src/be/nikiroo/fanfix_swing/gui/viewer/ViewerPanel.java with 97% similarity]
src/be/nikiroo/fanfix_swing/gui/viewer/Viewer.java [deleted file]
src/be/nikiroo/fanfix_swing/gui/viewer/ViewerImages.java
src/be/nikiroo/fanfix_swing/gui/viewer/ViewerNonImages.java [new file with mode: 0644]
src/be/nikiroo/fanfix_swing/gui/viewer/ViewerTextOutput.java

index aebe309f5c04a905c79565520565d96b37b48d09..d439f384f302b2e2f4ba54ceddcf5184d248c33e 100644 (file)
@@ -27,7 +27,7 @@ import be.nikiroo.fanfix_swing.gui.book.BookInfo;
 import be.nikiroo.fanfix_swing.gui.utils.CoverImager;
 import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
 import be.nikiroo.fanfix_swing.gui.viewer.ViewerImages;
-import be.nikiroo.fanfix_swing.gui.viewer.Viewer;
+import be.nikiroo.fanfix_swing.gui.viewer.ViewerNonImages;
 import be.nikiroo.utils.Progress;
 import be.nikiroo.utils.StringUtils;
 
@@ -141,8 +141,8 @@ public class Actions {
                        ViewerImages viewer = new ViewerImages(story);
                        viewer.setVisible(true);
                } else {
-                       Viewer viewer = new Viewer(Instance.getInstance().getLibrary(),
-                                       story);
+                       ViewerNonImages viewer = new ViewerNonImages(
+                                       Instance.getInstance().getLibrary(), story);
                        viewer.setVisible(true);
                }
 
index 301d8a43dec3b3ef2d74fb247e25aabfe20a6164..e57ff058d492ebb6edd1e14008a3db7edd99a4f6 100644 (file)
@@ -16,7 +16,7 @@ import be.nikiroo.fanfix.library.BasicLibrary;
 import be.nikiroo.fanfix_swing.gui.PropertiesPanel;
 import be.nikiroo.fanfix_swing.gui.book.BookInfo;
 import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
-import be.nikiroo.fanfix_swing.gui.viewer.ViewerPanel;
+import be.nikiroo.fanfix_swing.gui.viewer.TODEL_ViewerPanel;
 import be.nikiroo.utils.Progress;
 import be.nikiroo.utils.ui.ProgressBar;
 
@@ -37,7 +37,7 @@ public class SearchAction extends JFrame {
                JPanel props = new PropertiesPanel(lib, info.getMeta(), false);
 
                main.add(props, BorderLayout.NORTH);
-               main.add(new ViewerPanel(info.getMeta(), info.getMeta()
+               main.add(new TODEL_ViewerPanel(info.getMeta(), info.getMeta()
                                .isImageDocument()), BorderLayout.CENTER);
                main.add(createImportButton(lib), BorderLayout.SOUTH);
 
similarity index 97%
rename from src/be/nikiroo/fanfix_swing/gui/viewer/ViewerPanel.java
rename to src/be/nikiroo/fanfix_swing/gui/viewer/TODEL_ViewerPanel.java
index 3832fa23864f1bc2efcfbe7cc2bae71bcb5a3fff..2286215c59c0a83c3db1dd18c1219ad34b27687a 100644 (file)
@@ -30,7 +30,7 @@ import be.nikiroo.utils.ui.ImageUtilsAwt;
  * 
  * @author niki
  */
-public class ViewerPanel extends JPanel {
+public class TODEL_ViewerPanel extends JPanel {
        private static final long serialVersionUID = 1L;
 
        private boolean imageDocument;
@@ -54,7 +54,7 @@ public class ViewerPanel extends JPanel {
         * @param story
         *            the {@link Story} to work on
         */
-       public ViewerPanel(Story story) {
+       public TODEL_ViewerPanel(Story story) {
                this(story.getMeta(), story.getMeta().isImageDocument());
        }
 
@@ -66,7 +66,7 @@ public class ViewerPanel extends JPanel {
         * @param isImageDocument
         *            TRUE if it is an image document, FALSE if not
         */
-       public ViewerPanel(MetaData meta, boolean isImageDocument) {
+       public TODEL_ViewerPanel(MetaData meta, boolean isImageDocument) {
                super(new BorderLayout());
 
                this.imageDocument = isImageDocument;
@@ -164,7 +164,7 @@ public class ViewerPanel extends JPanel {
                new Thread(new Runnable() {
                        @Override
                        public void run() {
-                               final String content = htmlOutput.convert(chap);
+                               final String content = htmlOutput.convert(chap, true);
                                // Wait until size computations are correct
                                while (!scroll.isValid()) {
                                        try {
diff --git a/src/be/nikiroo/fanfix_swing/gui/viewer/Viewer.java b/src/be/nikiroo/fanfix_swing/gui/viewer/Viewer.java
deleted file mode 100644 (file)
index 10a7c77..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-package be.nikiroo.fanfix_swing.gui.viewer;
-
-import java.awt.BorderLayout;
-import java.awt.Font;
-import java.awt.LayoutManager;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.BorderFactory;
-import javax.swing.BoxLayout;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.SwingConstants;
-
-import be.nikiroo.fanfix.Instance;
-import be.nikiroo.fanfix.bundles.StringIdGui;
-import be.nikiroo.fanfix.data.Chapter;
-import be.nikiroo.fanfix.data.MetaData;
-import be.nikiroo.fanfix.data.Story;
-import be.nikiroo.fanfix.library.BasicLibrary;
-import be.nikiroo.fanfix_swing.gui.PropertiesPanel;
-import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
-
-/**
- * An internal, Swing-based {@link Story} viewer.
- * <p>
- * Works on both text and image document (see {@link MetaData#isImageDocument()}
- * ).
- * 
- * @author niki
- */
-public class Viewer extends JFrame {
-       private static final long serialVersionUID = 1L;
-
-       private Story story;
-       private MetaData meta;
-       private JLabel title;
-       private PropertiesPanel descPane;
-       private ViewerPanel mainPanel;
-       private NavBar navbar;
-
-       /**
-        * Create a new {@link Story} viewer.
-        * 
-        * @param lib
-        *            the {@link BasicLibrary} to load the cover from
-        * @param story
-        *            the {@link Story} to display
-        */
-       public Viewer(BasicLibrary lib, Story story) {
-               setTitle(Instance
-                               .getInstance()
-                               .getTransGui()
-                               .getString(StringIdGui.TITLE_STORY, story.getMeta().getLuid(),
-                                               story.getMeta().getTitle()));
-
-               setSize(800, 600);
-
-               this.story = story;
-               this.meta = story.getMeta();
-
-               initGuiBase(lib);
-               initGuiNavButtons();
-
-               setChapter(-1);
-               
-               UiHelper.setFrameIcon(this);
-       }
-
-       /**
-        * 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());
-
-               title = new JLabel();
-               title.setFont(new Font(Font.SERIF, Font.BOLD,
-                               title.getFont().getSize() * 3));
-               title.setText(meta.getTitle());
-               title.setHorizontalAlignment(SwingConstants.CENTER);
-               title.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
-               add(title, BorderLayout.NORTH);
-
-               JPanel contentPane = new JPanel(new BorderLayout());
-               add(contentPane, BorderLayout.CENTER);
-
-               descPane = new PropertiesPanel(lib, meta, false);
-               contentPane.add(descPane, BorderLayout.NORTH);
-
-               mainPanel = new ViewerPanel(story);
-               contentPane.add(mainPanel, BorderLayout.CENTER);
-       }
-
-       /**
-        * Create the 4 navigation buttons in {@link Viewer#navButtons} and
-        * initialise them.
-        */
-       private void initGuiNavButtons() {
-               navbar = new NavBar(-1, story.getChapters().size() - 1) {
-                       private static final long serialVersionUID = 1L;
-
-                       @Override
-                       public String getExtraLabel() {
-                               int chapter = getIndex();
-                               Chapter chap;
-                               if (chapter < 0) {
-                                       chap = meta.getResume();
-                                       descPane.setVisible(true);
-                               } else {
-                                       chap = story.getChapters().get(chapter);
-                                       descPane.setVisible(false);
-                               }
-
-                               String chapterDisplay = Instance
-                                               .getInstance()
-                                               .getTransGui()
-                                               .getString(StringIdGui.CHAPTER_HTML_UNNAMED,
-                                                               chap.getNumber(), story.getChapters().size());
-                               if (chap.getName() != null && !chap.getName().trim().isEmpty()) {
-                                       chapterDisplay = Instance
-                                                       .getInstance()
-                                                       .getTransGui()
-                                                       .getString(StringIdGui.CHAPTER_HTML_NAMED,
-                                                                       chap.getNumber(),
-                                                                       story.getChapters().size(), chap.getName());
-                               }
-
-                               return "<HTML>" + chapterDisplay + "</HTML>";
-                       }
-               };
-
-               navbar.addActionListener(new ActionListener() {
-                       @Override
-                       public void actionPerformed(ActionEvent e) {
-                               setChapter(navbar.getIndex());
-                       }
-               });
-
-               JPanel navButtonsPane = new JPanel();
-               LayoutManager layout = new BoxLayout(navButtonsPane, BoxLayout.X_AXIS);
-               navButtonsPane.setLayout(layout);
-
-               add(navbar, BorderLayout.SOUTH);
-       }
-
-       /**
-        * 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) {
-               Chapter chap;
-               if (chapter < 0) {
-                       chap = meta.getResume();
-                       descPane.setVisible(true);
-               } else {
-                       chap = story.getChapters().get(chapter);
-                       descPane.setVisible(false);
-               }
-
-               mainPanel.setChapter(chap);
-       }
-}
index 4f85cf727e907dae22e2dcac2150899c8c60031c..752b50453b5e9740a5f9a1801e5e0b0b66a5d18b 100644 (file)
@@ -27,7 +27,6 @@ import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
-import javax.swing.JTextField;
 import javax.swing.JToolBar;
 import javax.swing.SwingWorker;
 
@@ -116,7 +115,6 @@ public class ViewerImages extends JFrame {
        private NavBar navbar;
        private JLabel area;
        private JScrollPane scroll;
-       private JTextField page;
        private DefaultComboBoxModel<ZoomLevel> zoomBoxModel;
 
        private DelayWorker worker;
diff --git a/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerNonImages.java b/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerNonImages.java
new file mode 100644 (file)
index 0000000..26008dc
--- /dev/null
@@ -0,0 +1,198 @@
+package be.nikiroo.fanfix_swing.gui.viewer;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JEditorPane;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.JToolBar;
+import javax.swing.SwingWorker;
+
+import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.bundles.StringIdGui;
+import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.fanfix.library.BasicLibrary;
+import be.nikiroo.fanfix_swing.gui.PropertiesPanel;
+import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
+import be.nikiroo.utils.ui.DelayWorker;
+import be.nikiroo.utils.ui.UIUtils;
+
+/**
+ * An internal, Swing-based {@link Story} viewer.
+ * <p>
+ * Works on both text and image document (see {@link MetaData#isImageDocument()}
+ * ).
+ * 
+ * @author niki
+ */
+public class ViewerNonImages extends JFrame {
+       private static final long serialVersionUID = 1L;
+
+       private Story story;
+       private ViewerTextOutput html;
+
+       private NavBar navbar;
+       private JLabel title;
+       private JScrollPane scroll;
+       private JPanel mainPane;
+       private JEditorPane area;
+       private JPanel descPane;
+
+       private DelayWorker worker;
+
+       /**
+        * Create a new {@link Story} viewer.
+        * 
+        * @param lib
+        *            the {@link BasicLibrary} to use to retrieve the cover image in
+        *            the description panel
+        * @param story
+        *            the {@link Story} to display
+        * 
+        */
+       public ViewerNonImages(BasicLibrary lib, Story story) {
+               this.story = story;
+               this.setTitle(Instance.getInstance().getTransGui().getString(
+                               StringIdGui.TITLE_STORY, story.getMeta().getLuid(),
+                               story.getMeta().getTitle()));
+
+               this.setSize(800, 600);
+
+               html = new ViewerTextOutput();
+               worker = new DelayWorker(100);
+               worker.start();
+
+               initGui(lib);
+               setChapter(0);
+
+               UiHelper.setFrameIcon(this);
+       }
+
+       /**
+        * Initialise the base panel.
+        * 
+        * @param lib
+        *            the {@link BasicLibrary} to use to retrieve the cover image in
+        *            the description panel
+        */
+       private void initGui(BasicLibrary lib) {
+               this.setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
+
+               title = new JLabel();
+               title.setFont(
+                               new Font(Font.SERIF, Font.BOLD, title.getFont().getSize() * 2));
+               title.setText(story.getMeta().getTitle());
+               title.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+               title.setToolTipText(story.getMeta().getTitle());
+
+               JToolBar toolbarTitle = createToolBar();
+               toolbarTitle.add(title);
+
+               area = new JEditorPane("text/html", "");
+               area.setEditable(false);
+               area.setAlignmentY(TOP_ALIGNMENT);
+               area.setOpaque(true);
+               area.setFocusable(true);
+               area.setBackground(new JTextField().getBackground());
+               area.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+               scroll = UIUtils.scroll(area, false);
+
+               JLabel descLabel = new JLabel("Description");
+               descLabel.setFont(new Font(Font.SERIF, Font.BOLD,
+                               (int) Math.round(descLabel.getFont().getSize() * 1.5)));
+               descLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+               descLabel.setHorizontalAlignment(JLabel.CENTER);
+               descLabel.setOpaque(true);
+               Color bg = descLabel.getBackground();
+               descLabel.setBackground(descLabel.getForeground());
+               descLabel.setForeground(bg);
+
+               descPane = new JPanel(new BorderLayout());
+               PropertiesPanel desc = new PropertiesPanel(lib, story.getMeta(), false);
+               desc.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+               descPane.add(desc, BorderLayout.CENTER);
+               descPane.add(descLabel, BorderLayout.SOUTH);
+
+               area.setSize(scroll.getViewport().getSize());
+               area.requestFocus();
+
+               this.add(toolbarTitle);
+               this.add(descPane);
+               this.add(scroll);
+
+               listen();
+       }
+
+       private void listen() {
+               navbar.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               setChapter(navbar.getIndex());
+                       }
+               });
+       }
+
+       private JToolBar createToolBar() {
+               JToolBar toolbar = new JToolBar();
+               navbar = new NavBar(0, story.getChapters().size());
+               toolbar.add(navbar);
+               return toolbar;
+       }
+
+       /**
+        * Set the current chapter, 0-based.
+        * <p>
+        * Chapter 0 will also toggle the description page on top.
+        * 
+        * @param chapter
+        *            the chapter number to set
+        */
+       private void setChapter(final int chapter) {
+               worker.delay("update chapter", new SwingWorker<String, Void>() {
+                       @Override
+                       protected String doInBackground() throws Exception {
+                               if (chapter <= 0) {
+                                       return html.convert(story.getMeta().getResume(), false);
+                               }
+
+                               return html.convert(story.getChapters().get(chapter - 1), true);
+                       }
+
+                       @Override
+                       protected void done() {
+                               try {
+                                       String text = get();
+                                       if (chapter <= 0) {
+                                               descPane.setVisible(true);
+                                       } else {
+                                               descPane.setVisible(false);
+                                       }
+
+                                       area.setText(text);
+                                       area.setSize(scroll.getViewport().getSize());
+                                       area.setCaretPosition(0);
+                                       area.scrollRectToVisible(new Rectangle());
+
+                                       // So we can use the keyboard navigation even after a
+                                       // toolbar click
+                                       area.requestFocus();
+                               } catch (InterruptedException e) {
+                               } catch (ExecutionException e) {
+                               }
+                       }
+               });
+       }
+}
index 16d863ef97660ab297074a1752885ddd34ba9c58..070288090b4e87cbf9038e0c95c326ee0079fd2e 100644 (file)
@@ -15,14 +15,15 @@ import be.nikiroo.fanfix.output.BasicOutput;
  * 
  * @author niki
  */
-public class ViewerTextOutput {
+class ViewerTextOutput {
        private StringBuilder builder;
        private BasicOutput output;
        private Story fakeStory;
+       private boolean chapterName;
 
        /**
-        * Create a new {@link ViewerTextOutput} that will convert a
-        * {@link Chapter} into HTML3 suited for Java Swing.
+        * Create a new {@link ViewerTextOutput} that will convert a {@link Chapter}
+        * into HTML3 suited for Java Swing.
         */
        public ViewerTextOutput() {
                builder = new StringBuilder();
@@ -33,14 +34,19 @@ public class ViewerTextOutput {
 
                        @Override
                        protected void writeChapterHeader(Chapter chap) throws IOException {
-                               builder.append("<HTML>");
-
-                               builder.append("<H1>");
-                               builder.append("Chapter ");
-                               builder.append(chap.getNumber());
-                               builder.append(": ");
-                               builder.append(chap.getName());
-                               builder.append("</H1>");
+                               builder.append("<HTML style='line-height: normal;'>");
+
+                               if (chapterName) {
+                                       builder.append("<H1>");
+                                       builder.append("Chapter ");
+                                       builder.append(chap.getNumber());
+                                       if (chap.getName() != null
+                                                       && !chap.getName().trim().isEmpty()) {
+                                               builder.append(": ");
+                                               builder.append(chap.getName());
+                                       }
+                                       builder.append("</H1>");
+                               }
 
                                builder.append("<DIV align='justify'>");
                        }
@@ -111,11 +117,14 @@ public class ViewerTextOutput {
         * Convert the chapter into HTML3 code.
         * 
         * @param chap
-        *            the {@link Chapter} to convert.
+        *            the {@link Chapter} to convert
+        * @param chapterName
+        *            display the chapter name
         * 
         * @return HTML3 code tested with Java Swing
         */
-       public String convert(Chapter chap) {
+       public String convert(Chapter chap, boolean chapterName) {
+               this.chapterName = chapterName;
                builder.setLength(0);
                try {
                        fakeStory.setChapters(Arrays.asList(chap));