From b38998aad5e9e14083321ea21b325fcb1ee4e1ba Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Mon, 4 May 2020 00:29:45 +0200 Subject: [PATCH] Internal text viewer is now OK --- src/be/nikiroo/fanfix_swing/Actions.java | 6 +- .../fanfix_swing/gui/search/SearchAction.java | 4 +- ...iewerPanel.java => TODEL_ViewerPanel.java} | 8 +- .../fanfix_swing/gui/viewer/Viewer.java | 171 --------------- .../fanfix_swing/gui/viewer/ViewerImages.java | 2 - .../gui/viewer/ViewerNonImages.java | 198 ++++++++++++++++++ .../gui/viewer/ViewerTextOutput.java | 35 ++-- 7 files changed, 229 insertions(+), 195 deletions(-) rename src/be/nikiroo/fanfix_swing/gui/viewer/{ViewerPanel.java => TODEL_ViewerPanel.java} (97%) delete mode 100644 src/be/nikiroo/fanfix_swing/gui/viewer/Viewer.java create mode 100644 src/be/nikiroo/fanfix_swing/gui/viewer/ViewerNonImages.java diff --git a/src/be/nikiroo/fanfix_swing/Actions.java b/src/be/nikiroo/fanfix_swing/Actions.java index aebe309f..d439f384 100644 --- a/src/be/nikiroo/fanfix_swing/Actions.java +++ b/src/be/nikiroo/fanfix_swing/Actions.java @@ -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); } diff --git a/src/be/nikiroo/fanfix_swing/gui/search/SearchAction.java b/src/be/nikiroo/fanfix_swing/gui/search/SearchAction.java index 301d8a43..e57ff058 100644 --- a/src/be/nikiroo/fanfix_swing/gui/search/SearchAction.java +++ b/src/be/nikiroo/fanfix_swing/gui/search/SearchAction.java @@ -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); diff --git a/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerPanel.java b/src/be/nikiroo/fanfix_swing/gui/viewer/TODEL_ViewerPanel.java 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 3832fa23..2286215c 100644 --- a/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerPanel.java +++ b/src/be/nikiroo/fanfix_swing/gui/viewer/TODEL_ViewerPanel.java @@ -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 index 10a7c77d..00000000 --- a/src/be/nikiroo/fanfix_swing/gui/viewer/Viewer.java +++ /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. - *

- * 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 "" + chapterDisplay + ""; - } - }; - - 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. - *

- * 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); - } -} diff --git a/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerImages.java b/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerImages.java index 4f85cf72..752b5045 100644 --- a/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerImages.java +++ b/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerImages.java @@ -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 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 index 00000000..26008dc3 --- /dev/null +++ b/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerNonImages.java @@ -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. + *

+ * 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. + *

+ * 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() { + @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) { + } + } + }); + } +} diff --git a/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerTextOutput.java b/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerTextOutput.java index 16d863ef..07028809 100644 --- a/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerTextOutput.java +++ b/src/be/nikiroo/fanfix_swing/gui/viewer/ViewerTextOutput.java @@ -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(""); - - builder.append("

"); - builder.append("Chapter "); - builder.append(chap.getNumber()); - builder.append(": "); - builder.append(chap.getName()); - builder.append("

"); + builder.append(""); + + if (chapterName) { + builder.append("

"); + builder.append("Chapter "); + builder.append(chap.getNumber()); + if (chap.getName() != null + && !chap.getName().trim().isEmpty()) { + builder.append(": "); + builder.append(chap.getName()); + } + builder.append("

"); + } builder.append("
"); } @@ -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)); -- 2.27.0