package be.nikiroo.fanfix.reader.ui;
import java.awt.BorderLayout;
+import java.awt.EventQueue;
+import java.awt.Graphics2D;
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.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
+import javax.swing.SwingConstants;
import be.nikiroo.fanfix.Instance;
import be.nikiroo.fanfix.data.Chapter;
private boolean imageDocument;
private Chapter chap;
-
- private JLabel label;
+ private JScrollPane scroll;
private GuiReaderViewerTextOutput htmlOutput;
+
+ // text only:
+ private JEditorPane text;
+
+ // image only:
+ private JLabel image;
private JProgressBar imageProgress;
private int currentImage;
private JButton left;
super(new BorderLayout());
this.imageDocument = story.getMeta().isImageDocument();
- this.label = new JLabel();
- label.setAlignmentY(TOP_ALIGNMENT);
+
+ this.text = new JEditorPane("text/html", "");
+ text.setAlignmentY(TOP_ALIGNMENT);
htmlOutput = new GuiReaderViewerTextOutput();
- if (!imageDocument) {
- // TODO: why is it broken?
- // text.setPreferredSize(new Dimension(500, 500));
+ image = new JLabel();
+ image.setHorizontalAlignment(SwingConstants.CENTER);
- JScrollPane scroll = new JScrollPane(label);
- scroll.getVerticalScrollBar().setUnitIncrement(16);
+ scroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ scroll.getVerticalScrollBar().setUnitIncrement(16);
+ if (!imageDocument) {
add(scroll, BorderLayout.CENTER);
} else {
imageProgress = new JProgressBar();
add(imageProgress, BorderLayout.SOUTH);
JPanel main = new JPanel(new BorderLayout());
- main.add(label, BorderLayout.CENTER);
+ main.add(scroll, BorderLayout.CENTER);
- left = new JButton(" < ");
+ left = new JButton("<HTML> < </HTML>");
left.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
});
main.add(left, BorderLayout.WEST);
- right = new JButton(" > ");
+ right = new JButton("<HTML> > </HTML>");
right.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
main.add(right, BorderLayout.EAST);
add(main, BorderLayout.CENTER);
+ main.invalidate();
}
setChapter(story.getMeta().getResume());
this.chap = chap;
if (!imageDocument) {
- label.setText(htmlOutput.convert(chap));
+ setText(chap);
} else {
left.setVisible(chap.getNumber() > 0);
right.setVisible(chap.getNumber() > 0);
imageProgress.setMaximum(chap.getParagraphs().size() - 1);
if (chap.getNumber() == 0) {
- label.setText(htmlOutput.convert(chap));
+ setText(chap);
} else {
setImage(0);
}
}
}
+ /**
+ * Will set and display the current chapter text.
+ *
+ * @param chap
+ * the chapter to display
+ */
+ private void setText(final Chapter chap) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ final String content = htmlOutput.convert(chap);
+ // Wait until size computations are correct
+ while (!scroll.isValid()) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ setText(content);
+ }
+ }).start();
+ }
+
+ /**
+ * Actually set the text in the UI.
+ * <p>
+ * Do <b>NOT</b> use this method from the UI thread.
+ *
+ * @param content
+ * the text
+ */
+ private void setText(final String content) {
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ text.setText(content);
+ text.setCaretPosition(0);
+ scroll.setViewportView(text);
+ }
+ });
+ }
+
/**
* Will set and display the current image, take care about the progression
* and update the left and right cursors' <tt>enabled</tt> property.
.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 {
+ final Image img = chap.getParagraphs().get(i).getContentImage();
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Wait until size computations are correct
+ while (!scroll.isValid()) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ if (img == null) {
+ setText("Error: cannot render image.");
+ } else {
+ setImage(img);
+ }
+ }
+ }).start();
+ }
+
+ /**
+ * Actually set the image in the UI.
+ * <p>
+ * Do <b>NOT</b> use this method from the UI thread.
+ *
+ * @param img
+ * the image to set
+ */
+ private void setImage(Image img) {
+ try {
+ int scrollWidth = scroll.getWidth()
+ - scroll.getVerticalScrollBar().getWidth();
+
+ BufferedImage buffImg = ImageUtilsAwt.fromImage(img);
+
+ int iw = buffImg.getWidth();
+ int ih = buffImg.getHeight();
+ double ratio = ((double) ih) / iw;
+
+ int w = scrollWidth;
+ int h = (int) (ratio * scrollWidth);
+
+ BufferedImage resizedImage = new BufferedImage(w, h,
+ BufferedImage.TYPE_4BYTE_ABGR);
+
+ Graphics2D g = resizedImage.createGraphics();
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.");
+ g.drawImage(buffImg, 0, 0, w, h, null);
+ } finally {
+ g.dispose();
}
+
+ final Icon icon = new ImageIcon(resizedImage);
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ image.setIcon(icon);
+ scroll.setViewportView(image);
+ }
+ });
+ } catch (Exception e) {
+ Instance.getTraceHandler().error(
+ new Exception("Failed to load image into label", e));
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ text.setText("Error: cannot load image.");
+ }
+ });
}
}
}