gui: French translation
[fanfix.git] / src / be / nikiroo / fanfix / reader / ui / GuiReaderViewerPanel.java
CommitLineData
32ba91e9
NR
1package be.nikiroo.fanfix.reader.ui;
2
3import java.awt.BorderLayout;
908bbb35
NR
4import java.awt.EventQueue;
5import java.awt.Graphics2D;
32ba91e9
NR
6import java.awt.event.ActionEvent;
7import java.awt.event.ActionListener;
8import java.awt.image.BufferedImage;
9
10import javax.swing.Icon;
11import javax.swing.ImageIcon;
12import javax.swing.JButton;
908bbb35 13import javax.swing.JEditorPane;
32ba91e9
NR
14import javax.swing.JLabel;
15import javax.swing.JPanel;
16import javax.swing.JProgressBar;
17import javax.swing.JScrollPane;
908bbb35 18import javax.swing.SwingConstants;
32ba91e9
NR
19
20import be.nikiroo.fanfix.Instance;
5bc9573b 21import be.nikiroo.fanfix.bundles.StringIdGui;
32ba91e9
NR
22import be.nikiroo.fanfix.data.Chapter;
23import be.nikiroo.fanfix.data.Story;
24import be.nikiroo.utils.Image;
25import be.nikiroo.utils.ui.ImageUtilsAwt;
26
27/**
28 * A {@link JPanel} that will show a {@link Story} chapter on screen.
29 *
30 * @author niki
31 */
32public class GuiReaderViewerPanel extends JPanel {
33 private static final long serialVersionUID = 1L;
34
35 private boolean imageDocument;
36 private Chapter chap;
908bbb35 37 private JScrollPane scroll;
32ba91e9 38 private GuiReaderViewerTextOutput htmlOutput;
908bbb35
NR
39
40 // text only:
41 private JEditorPane text;
42
43 // image only:
44 private JLabel image;
32ba91e9
NR
45 private JProgressBar imageProgress;
46 private int currentImage;
47 private JButton left;
48 private JButton right;
49
50 /**
51 * Create a new viewer.
52 *
53 * @param story
54 * the {@link Story} to work on.
55 */
56 public GuiReaderViewerPanel(Story story) {
57 super(new BorderLayout());
58
59 this.imageDocument = story.getMeta().isImageDocument();
908bbb35
NR
60
61 this.text = new JEditorPane("text/html", "");
62 text.setAlignmentY(TOP_ALIGNMENT);
32ba91e9
NR
63 htmlOutput = new GuiReaderViewerTextOutput();
64
908bbb35
NR
65 image = new JLabel();
66 image.setHorizontalAlignment(SwingConstants.CENTER);
32ba91e9 67
908bbb35
NR
68 scroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
69 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
70 scroll.getVerticalScrollBar().setUnitIncrement(16);
32ba91e9 71
908bbb35 72 if (!imageDocument) {
32ba91e9
NR
73 add(scroll, BorderLayout.CENTER);
74 } else {
75 imageProgress = new JProgressBar();
76 imageProgress.setStringPainted(true);
77 add(imageProgress, BorderLayout.SOUTH);
78
79 JPanel main = new JPanel(new BorderLayout());
908bbb35 80 main.add(scroll, BorderLayout.CENTER);
32ba91e9 81
908bbb35 82 left = new JButton("<HTML>&nbsp; &nbsp; &lt; &nbsp; &nbsp;</HTML>");
32ba91e9
NR
83 left.addActionListener(new ActionListener() {
84 @Override
85 public void actionPerformed(ActionEvent e) {
86 setImage(--currentImage);
87 }
88 });
89 main.add(left, BorderLayout.WEST);
90
908bbb35 91 right = new JButton("<HTML>&nbsp; &nbsp; &gt; &nbsp; &nbsp;</HTML>");
32ba91e9
NR
92 right.addActionListener(new ActionListener() {
93 @Override
94 public void actionPerformed(ActionEvent e) {
95 setImage(++currentImage);
96 }
97 });
98 main.add(right, BorderLayout.EAST);
99
100 add(main, BorderLayout.CENTER);
908bbb35 101 main.invalidate();
32ba91e9
NR
102 }
103
104 setChapter(story.getMeta().getResume());
105 }
106
107 /**
108 * Load the given chapter.
109 * <p>
110 * Will always be text for a non-image document.
111 * <p>
112 * Will be an image and left/right controls for an image-document, except
113 * for chapter 0 which will be text (chapter 0 = resume).
114 *
115 * @param chap
116 * the chapter to load
117 */
118 public void setChapter(Chapter chap) {
119 this.chap = chap;
120
121 if (!imageDocument) {
908bbb35 122 setText(chap);
32ba91e9
NR
123 } else {
124 left.setVisible(chap.getNumber() > 0);
125 right.setVisible(chap.getNumber() > 0);
126 imageProgress.setVisible(chap.getNumber() > 0);
127
128 imageProgress.setMinimum(0);
129 imageProgress.setMaximum(chap.getParagraphs().size() - 1);
130
131 if (chap.getNumber() == 0) {
908bbb35 132 setText(chap);
32ba91e9
NR
133 } else {
134 setImage(0);
135 }
136 }
137 }
138
908bbb35
NR
139 /**
140 * Will set and display the current chapter text.
141 *
142 * @param chap
143 * the chapter to display
144 */
145 private void setText(final Chapter chap) {
146 new Thread(new Runnable() {
147 @Override
148 public void run() {
149 final String content = htmlOutput.convert(chap);
150 // Wait until size computations are correct
151 while (!scroll.isValid()) {
152 try {
153 Thread.sleep(1);
154 } catch (InterruptedException e) {
155 }
156 }
157
158 setText(content);
159 }
160 }).start();
161 }
162
163 /**
164 * Actually set the text in the UI.
165 * <p>
166 * Do <b>NOT</b> use this method from the UI thread.
167 *
168 * @param content
169 * the text
170 */
171 private void setText(final String content) {
172 EventQueue.invokeLater(new Runnable() {
173 @Override
174 public void run() {
175 text.setText(content);
176 text.setCaretPosition(0);
177 scroll.setViewportView(text);
178 }
179 });
180 }
181
32ba91e9
NR
182 /**
183 * Will set and display the current image, take care about the progression
184 * and update the left and right cursors' <tt>enabled</tt> property.
185 *
186 * @param i
187 * the image index to load
188 */
189 private void setImage(int i) {
190 left.setEnabled(i > 0);
191 right.setEnabled(i + 1 < chap.getParagraphs().size());
192
193 if (i < 0 || i >= chap.getParagraphs().size()) {
194 return;
195 }
196
197 imageProgress.setValue(i);
5bc9573b
NR
198 imageProgress.setString(GuiReader.trans(StringIdGui.IMAGE_PROGRESSION,
199 i + 1, chap.getParagraphs().size()));
32ba91e9
NR
200
201 currentImage = i;
32ba91e9 202
908bbb35
NR
203 final Image img = chap.getParagraphs().get(i).getContentImage();
204
eea1c0a8
NR
205 // prepare the viewport to get the right sizes later on
206 image.setIcon(null);
207 scroll.setViewportView(image);
208
908bbb35
NR
209 new Thread(new Runnable() {
210 @Override
211 public void run() {
212 // Wait until size computations are correct
213 while (!scroll.isValid()) {
214 try {
215 Thread.sleep(1);
216 } catch (InterruptedException e) {
217 }
218 }
219
220 if (img == null) {
221 setText("Error: cannot render image.");
222 } else {
223 setImage(img);
224 }
225 }
226 }).start();
227 }
228
229 /**
230 * Actually set the image in the UI.
231 * <p>
232 * Do <b>NOT</b> use this method from the UI thread.
233 *
234 * @param img
235 * the image to set
236 */
237 private void setImage(Image img) {
238 try {
239 int scrollWidth = scroll.getWidth()
240 - scroll.getVerticalScrollBar().getWidth();
241
242 BufferedImage buffImg = ImageUtilsAwt.fromImage(img);
243
244 int iw = buffImg.getWidth();
245 int ih = buffImg.getHeight();
246 double ratio = ((double) ih) / iw;
247
248 int w = scrollWidth;
249 int h = (int) (ratio * scrollWidth);
250
251 BufferedImage resizedImage = new BufferedImage(w, h,
252 BufferedImage.TYPE_4BYTE_ABGR);
253
254 Graphics2D g = resizedImage.createGraphics();
32ba91e9 255 try {
908bbb35
NR
256 g.drawImage(buffImg, 0, 0, w, h, null);
257 } finally {
258 g.dispose();
32ba91e9 259 }
908bbb35
NR
260
261 final Icon icon = new ImageIcon(resizedImage);
262 EventQueue.invokeLater(new Runnable() {
263 @Override
264 public void run() {
265 image.setIcon(icon);
266 scroll.setViewportView(image);
267 }
268 });
269 } catch (Exception e) {
270 Instance.getTraceHandler().error(
271 new Exception("Failed to load image into label", e));
272 EventQueue.invokeLater(new Runnable() {
273 @Override
274 public void run() {
275 text.setText("Error: cannot load image.");
276 }
277 });
32ba91e9
NR
278 }
279 }
280}