tui: fix meta/story use
[fanfix.git] / src / be / nikiroo / fanfix / reader / tui / TuiReaderStoryWindow.java
CommitLineData
16a81ef7 1package be.nikiroo.fanfix.reader.tui;
c1873e56 2
e8796963
NR
3import java.text.ParseException;
4import java.text.SimpleDateFormat;
edfd3577 5import java.util.ArrayList;
6a26aa76 6import java.util.Arrays;
e8796963 7import java.util.Date;
edfd3577
NR
8import java.util.List;
9
0861d62a 10import jexer.TAction;
0861d62a 11import jexer.TButton;
0861d62a 12import jexer.TLabel;
6a26aa76 13import jexer.TTable;
f63c4267 14import jexer.TText;
0861d62a 15import jexer.TWindow;
cf9c5ed1 16import jexer.event.TCommandEvent;
c1873e56 17import jexer.event.TResizeEvent;
4f66bfa8 18import jexer.event.TResizeEvent.Type;
c1873e56
NR
19import be.nikiroo.fanfix.data.Chapter;
20import be.nikiroo.fanfix.data.MetaData;
21import be.nikiroo.fanfix.data.Paragraph;
9293188f 22import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
c1873e56 23import be.nikiroo.fanfix.data.Story;
e8796963 24import be.nikiroo.utils.StringUtils;
c1873e56 25
6a26aa76
NR
26/**
27 * This window will contain the {@link Story} in a readable format, with a
28 * chapter browser.
29 *
30 * @author niki
31 */
5dd985cf 32class TuiReaderStoryWindow extends TWindow {
c1873e56 33 private Story story;
6a26aa76 34 private TLabel titleField;
f63c4267 35 private TText textField;
6a26aa76
NR
36 private TTable table;
37 private int chapter = -99; // invalid value
edfd3577 38 private List<TButton> navigationButtons;
5b00c122 39 private TLabel currentChapter;
c1873e56 40
6322ab64 41 // chapter: -1 for "none" (0 is desc)
e0fb1417
NR
42 public TuiReaderStoryWindow(TuiReaderApplication app, Story story,
43 int chapter) {
44 super(app, desc(story.getMeta()), 0, 0, 60, 18, CENTERED | RESIZABLE);
68e2c6d2 45
e0fb1417 46 this.story = story;
c1873e56 47
e0fb1417 48 app.setStatusBar(this, desc(story.getMeta()));
c1873e56 49
6a26aa76
NR
50 // last = use window background
51 titleField = new TLabel(this, " Title", 0, 1, "tlabel", false);
e8796963 52 textField = new TText(this, "", 1, 3, getWidth() - 4, getHeight() - 5);
6a26aa76
NR
53 table = new TTable(this, 0, 3, getWidth(), getHeight() - 4, null, null,
54 Arrays.asList("Key", "Value"), true);
edfd3577 55
e8796963
NR
56 titleField.setEnabled(false);
57 textField.getVerticalScroller().setX(
58 textField.getVerticalScroller().getX() + 1);
59
0b7e3d78 60 navigationButtons = new ArrayList<TButton>(5);
edfd3577 61
396e924c 62 // -3 because 0-based and 2 for borders
edfd3577
NR
63 int row = getHeight() - 3;
64
6a26aa76
NR
65 // for bg colour when << button is pressed
66 navigationButtons.add(addButton(" ", 0, row, null));
0861d62a 67 navigationButtons.add(addButton("<< ", 0, row, new TAction() {
211f7ddb 68 @Override
396e924c 69 public void DO() {
6a26aa76 70 setChapter(-1);
396e924c 71 }
edfd3577 72 }));
0861d62a 73 navigationButtons.add(addButton("< ", 4, row, new TAction() {
211f7ddb 74 @Override
edfd3577
NR
75 public void DO() {
76 setChapter(TuiReaderStoryWindow.this.chapter - 1);
77 }
78 }));
0861d62a 79 navigationButtons.add(addButton("> ", 7, row, new TAction() {
211f7ddb 80 @Override
edfd3577
NR
81 public void DO() {
82 setChapter(TuiReaderStoryWindow.this.chapter + 1);
83 }
84 }));
0861d62a 85 navigationButtons.add(addButton(">> ", 10, row, new TAction() {
211f7ddb 86 @Override
edfd3577
NR
87 public void DO() {
88 setChapter(getStory().getChapters().size());
89 }
90 }));
b0e88ebd 91
8670a283
NR
92 navigationButtons.get(0).setEnabled(false);
93 navigationButtons.get(1).setEnabled(false);
94 navigationButtons.get(2).setEnabled(false);
edfd3577 95
5b00c122
NR
96 currentChapter = addLabel("", 14, row);
97 currentChapter.setWidth(getWidth() - 10);
6a26aa76 98
edfd3577 99 setChapter(chapter);
c1873e56
NR
100 }
101
102 @Override
103 public void onResize(TResizeEvent resize) {
104 super.onResize(resize);
105
e8796963
NR
106 // Resize the text field
107 // TODO: why setW/setH/reflow not enough for the scrollbars?
108 textField.onResize(new TResizeEvent(Type.WIDGET, resize.getWidth() - 4,
6a26aa76 109 resize.getHeight() - 5));
e8796963
NR
110 textField.getVerticalScroller().setX(
111 textField.getVerticalScroller().getX() + 1);
6a26aa76
NR
112
113 table.setWidth(getWidth());
114 table.setHeight(getHeight() - 4);
115 table.reflowData();
edfd3577
NR
116
117 // -3 because 0-based and 2 for borders
118 int row = getHeight() - 3;
119
5b00c122
NR
120 String name = currentChapter.getLabel();
121 while (name.length() < resize.getWidth() - currentChapter.getX()) {
edfd3577
NR
122 name += " ";
123 }
5b00c122
NR
124 currentChapter.setLabel(name);
125 currentChapter.setWidth(resize.getWidth() - 10);
126 currentChapter.setY(row);
edfd3577
NR
127
128 for (TButton button : navigationButtons) {
129 button.setY(row);
130 }
131 }
132
5b00c122
NR
133 /**
134 * Display the current chapter in the window, or the {@link Story} info
135 * page.
136 *
137 * @param chapter
138 * the chapter (including "0" which is the description) or "-1"
139 * to display the info page instead
140 */
edfd3577 141 private void setChapter(int chapter) {
edfd3577
NR
142 if (chapter > getStory().getChapters().size()) {
143 chapter = getStory().getChapters().size();
144 }
145
146 if (chapter != this.chapter) {
147 this.chapter = chapter;
b0e88ebd 148
8670a283 149 int max = getStory().getChapters().size();
5b00c122
NR
150 navigationButtons.get(0).setEnabled(chapter > -1);
151 navigationButtons.get(1).setEnabled(chapter > -1);
152 navigationButtons.get(2).setEnabled(chapter > -1);
8670a283
NR
153 navigationButtons.get(3).setEnabled(chapter < max);
154 navigationButtons.get(4).setEnabled(chapter < max);
b0e88ebd 155
5b00c122 156 if (chapter < 0) {
6a26aa76 157 displayInfoPage();
edfd3577 158 } else {
6a26aa76 159 displayChapterPage();
edfd3577 160 }
5b00c122
NR
161 }
162
163 setCurrentChapterText();
164 }
edfd3577 165
5b00c122
NR
166 /**
167 * Append the info page about the current {@link Story}.
168 *
169 * @param builder
170 * the builder to append to
171 */
6a26aa76
NR
172 private void displayInfoPage() {
173 textField.setVisible(false);
174 table.setVisible(true);
e8796963
NR
175 textField.setEnabled(false);
176 table.setEnabled(true);
5b00c122 177
6a26aa76 178 MetaData meta = getStory().getMeta();
5b00c122 179
6a26aa76 180 setCurrentTitle(meta.getTitle());
5b00c122 181
6a26aa76 182 table.setRowData(new String[][] { //
e8796963
NR
183 new String[] { " Author", meta.getAuthor() }, //
184 new String[] { " Publication date", formatDate(meta.getDate()) },
185 new String[] { " Word count", format(meta.getWords()) },
186 new String[] { " Source", meta.getSource() } //
6a26aa76
NR
187 });
188 table.setHeaders(Arrays.asList("key", "value"), false);
189 table.toTop();
5b00c122
NR
190 }
191
e8796963
NR
192 private String format(long value) {
193 String display = "";
194
195 while (value > 0) {
196 if (!display.isEmpty()) {
197 display = "." + display;
198 }
199 display = (value % 1000) + display;
200 value = value / 1000;
201 }
202
203 return display;
204 }
205
206 private String formatDate(String date) {
207 long ms = 0;
208
209 try {
210 ms = StringUtils.toTime(date);
211 } catch (ParseException e) {
212 }
213
214 if (ms <= 0) {
215 SimpleDateFormat sdf = new SimpleDateFormat(
216 "yyyy-MM-dd'T'HH:mm:ssXXX");
217 try {
218 ms = sdf.parse(date).getTime();
219 } catch (ParseException e) {
220 }
221 }
222
223 if (ms > 0) {
224 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
225 return sdf.format(new Date(ms));
226 }
227
228 // :(
229 return date;
230 }
231
5b00c122
NR
232 /**
233 * Append the current chapter.
234 *
235 * @param builder
236 * the builder to append to
237 */
6a26aa76
NR
238 private void displayChapterPage() {
239 table.setVisible(false);
240 textField.setVisible(true);
e8796963
NR
241 table.setEnabled(false);
242 textField.setEnabled(true);
6a26aa76
NR
243
244 StringBuilder builder = new StringBuilder();
245
5b00c122
NR
246 Chapter chap = null;
247 if (chapter == 0) {
248 chap = getStory().getMeta().getResume();
249 } else if (chapter > 0) {
250 chap = getStory().getChapters().get(chapter - 1);
251 }
252
253 // TODO: i18n
254 String chapName = chap == null ? "[No RESUME]" : chap.getName();
6a26aa76 255 setCurrentTitle(String.format("Chapter %d: %s", chapter, chapName));
5b00c122
NR
256
257 if (chap != null) {
258 for (Paragraph para : chap) {
259 if (para.getType() == ParagraphType.BREAK) {
260 builder.append("\n");
261 }
262 builder.append(para.getContent()).append("\n");
263 if (para.getType() == ParagraphType.BREAK) {
264 builder.append("\n");
fdc55375 265 }
edfd3577 266 }
edfd3577 267 }
6a26aa76
NR
268
269 setText(builder.toString());
c1873e56
NR
270 }
271
272 private Story getStory() {
c1873e56
NR
273 return story;
274 }
275
5b00c122
NR
276 /**
277 * Display the given text on the window.
278 *
279 * @param text
280 * the text to display
281 */
282 private void setText(String text) {
283 textField.setText(text);
284 textField.reflowData();
285 textField.toTop();
286 }
287
288 /**
289 * Set the current chapter area to the correct value.
290 */
291 private void setCurrentChapterText() {
292 String name;
293 if (chapter < 0) {
294 name = " " + getStory().getMeta().getTitle();
295 } else if (chapter == 0) {
296 Chapter resume = getStory().getMeta().getResume();
297 if (resume != null) {
298 name = String.format(" %s", resume.getName());
299 } else {
300 // TODO: i18n
301 name = "[No RESUME]";
302 }
303 } else {
304 int max = getStory().getChapters().size();
305 Chapter chap = getStory().getChapters().get(chapter - 1);
306 name = String.format(" %d/%d: %s", chapter, max, chap.getName());
307 }
308
309 int width = getWidth() - currentChapter.getX();
310 while (name.length() < width) {
311 name += " ";
312 }
313
314 if (name.length() > width) {
315 name = name.substring(0, width);
316 }
317
318 currentChapter.setLabel(name);
c1873e56 319 }
5b00c122
NR
320
321 /**
6a26aa76 322 * Set the current title in-window.
5b00c122 323 *
5b00c122 324 * @param title
6a26aa76 325 * the new title
5b00c122 326 */
6a26aa76 327 private void setCurrentTitle(String title) {
e8796963
NR
328 String pad = "";
329 if (title.length() < getWidth()) {
330 int padSize = (getWidth() - title.length()) / 2;
331 pad = String.format("%" + padSize + "s", "");
332 }
333
334 title = pad + title + pad;
6a26aa76
NR
335 titleField.setWidth(title.length());
336 titleField.setLabel(title);
337 }
5b00c122 338
6a26aa76
NR
339 private static String desc(MetaData meta) {
340 return String.format("%s: %s", meta.getLuid(), meta.getTitle());
5b00c122 341 }
cf9c5ed1
NR
342
343 @Override
344 public void onCommand(TCommandEvent command) {
345 if (command.getCmd().equals(TuiReaderApplication.CMD_EXIT)) {
346 TuiReaderApplication.close(this);
347 } else {
348 // Handle our own event if needed here
349 super.onCommand(command);
350 }
351 }
c1873e56 352}