Merge branch 'subtree'
[nikiroo-utils.git] / src / be / nikiroo / fanfix / reader / tui / TuiReaderStoryWindow.java
CommitLineData
16a81ef7 1package be.nikiroo.fanfix.reader.tui;
c1873e56 2
edfd3577 3import java.util.ArrayList;
6a26aa76 4import java.util.Arrays;
edfd3577 5import java.util.List;
df6e2d88 6import java.util.Map;
edfd3577 7
0861d62a 8import jexer.TAction;
0861d62a 9import jexer.TButton;
0861d62a 10import jexer.TLabel;
f63c4267 11import jexer.TText;
0861d62a 12import jexer.TWindow;
cf9c5ed1 13import jexer.event.TCommandEvent;
c1873e56 14import jexer.event.TResizeEvent;
c1873e56
NR
15import be.nikiroo.fanfix.data.Chapter;
16import be.nikiroo.fanfix.data.MetaData;
17import be.nikiroo.fanfix.data.Paragraph;
9293188f 18import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
c1873e56 19import be.nikiroo.fanfix.data.Story;
df6e2d88 20import be.nikiroo.fanfix.reader.BasicReader;
0bcb5c7f 21import be.nikiroo.jexer.TSizeConstraint;
8f34a795 22import be.nikiroo.jexer.TTable;
c1873e56 23
6a26aa76
NR
24/**
25 * This window will contain the {@link Story} in a readable format, with a
26 * chapter browser.
27 *
28 * @author niki
29 */
5dd985cf 30class TuiReaderStoryWindow extends TWindow {
c1873e56 31 private Story story;
6a26aa76 32 private TLabel titleField;
f63c4267 33 private TText textField;
6a26aa76
NR
34 private TTable table;
35 private int chapter = -99; // invalid value
edfd3577 36 private List<TButton> navigationButtons;
5b00c122 37 private TLabel currentChapter;
f00daa5e 38 private List<TSizeConstraint> sizeConstraints = new ArrayList<TSizeConstraint>();
c1873e56 39
6322ab64 40 // chapter: -1 for "none" (0 is desc)
e0fb1417
NR
41 public TuiReaderStoryWindow(TuiReaderApplication app, Story story,
42 int chapter) {
43 super(app, desc(story.getMeta()), 0, 0, 60, 18, CENTERED | RESIZABLE);
68e2c6d2 44
e0fb1417 45 this.story = story;
c1873e56 46
e0fb1417 47 app.setStatusBar(this, desc(story.getMeta()));
c1873e56 48
6a26aa76
NR
49 // last = use window background
50 titleField = new TLabel(this, " Title", 0, 1, "tlabel", false);
f00daa5e 51 textField = new TText(this, "", 0, 0, 1, 1);
494877be
NR
52 table = new TTable(this, 0, 0, 1, 1, null, null, Arrays.asList("Key",
53 "Value"), true);
edfd3577 54
e8796963 55 titleField.setEnabled(false);
e8796963 56
0b7e3d78 57 navigationButtons = new ArrayList<TButton>(5);
edfd3577 58
494877be 59 navigationButtons.add(addButton("<<", 0, 0, new TAction() {
211f7ddb 60 @Override
396e924c 61 public void DO() {
6a26aa76 62 setChapter(-1);
396e924c 63 }
edfd3577 64 }));
494877be 65 navigationButtons.add(addButton("< ", 4, 0, new TAction() {
211f7ddb 66 @Override
edfd3577
NR
67 public void DO() {
68 setChapter(TuiReaderStoryWindow.this.chapter - 1);
69 }
70 }));
494877be 71 navigationButtons.add(addButton("> ", 7, 0, new TAction() {
211f7ddb 72 @Override
edfd3577
NR
73 public void DO() {
74 setChapter(TuiReaderStoryWindow.this.chapter + 1);
75 }
76 }));
494877be 77 navigationButtons.add(addButton(">>", 10, 0, new TAction() {
211f7ddb 78 @Override
edfd3577
NR
79 public void DO() {
80 setChapter(getStory().getChapters().size());
81 }
82 }));
b0e88ebd 83
8670a283
NR
84 navigationButtons.get(0).setEnabled(false);
85 navigationButtons.get(1).setEnabled(false);
edfd3577 86
f00daa5e
NR
87 currentChapter = addLabel("", 0, 0);
88
494877be
NR
89 TSizeConstraint.setSize(sizeConstraints, textField, 1, 3, -1, -1);
90 TSizeConstraint.setSize(sizeConstraints, table, 0, 3, 0, -1);
f00daa5e
NR
91 TSizeConstraint.setSize(sizeConstraints, currentChapter, 14, -3, -1,
92 null);
93
94 for (TButton navigationButton : navigationButtons) {
494877be
NR
95 navigationButton.setShadowColor(null);
96 // navigationButton.setEmptyBorders(false);
f00daa5e
NR
97 TSizeConstraint.setSize(sizeConstraints, navigationButton, null,
98 -3, null, null);
99 }
100
101 onResize(null);
6a26aa76 102
edfd3577 103 setChapter(chapter);
c1873e56
NR
104 }
105
106 @Override
107 public void onResize(TResizeEvent resize) {
f00daa5e
NR
108 if (resize != null) {
109 super.onResize(resize);
110 }
c1873e56 111
f00daa5e
NR
112 // TODO: find out why TText and TTable does not behave the same way
113 // (offset of 2 for height and width)
6a26aa76 114
f00daa5e 115 TSizeConstraint.resize(sizeConstraints);
edfd3577 116
494877be
NR
117 // Improve the disposition of the scrollbars
118 textField.getVerticalScroller().setX(textField.getWidth());
119 textField.getVerticalScroller().setHeight(textField.getHeight());
120 textField.getHorizontalScroller().setX(-1);
121 textField.getHorizontalScroller().setWidth(textField.getWidth() + 1);
edfd3577 122
ce424b19 123 setCurrentChapterText();
edfd3577
NR
124 }
125
5b00c122
NR
126 /**
127 * Display the current chapter in the window, or the {@link Story} info
128 * page.
129 *
130 * @param chapter
131 * the chapter (including "0" which is the description) or "-1"
132 * to display the info page instead
133 */
edfd3577 134 private void setChapter(int chapter) {
edfd3577
NR
135 if (chapter > getStory().getChapters().size()) {
136 chapter = getStory().getChapters().size();
137 }
138
139 if (chapter != this.chapter) {
140 this.chapter = chapter;
b0e88ebd 141
8670a283 142 int max = getStory().getChapters().size();
5b00c122
NR
143 navigationButtons.get(0).setEnabled(chapter > -1);
144 navigationButtons.get(1).setEnabled(chapter > -1);
494877be 145 navigationButtons.get(2).setEnabled(chapter < max);
8670a283 146 navigationButtons.get(3).setEnabled(chapter < max);
b0e88ebd 147
5b00c122 148 if (chapter < 0) {
6a26aa76 149 displayInfoPage();
edfd3577 150 } else {
6a26aa76 151 displayChapterPage();
edfd3577 152 }
5b00c122
NR
153 }
154
155 setCurrentChapterText();
156 }
edfd3577 157
5b00c122
NR
158 /**
159 * Append the info page about the current {@link Story}.
160 *
161 * @param builder
162 * the builder to append to
163 */
6a26aa76
NR
164 private void displayInfoPage() {
165 textField.setVisible(false);
166 table.setVisible(true);
e8796963
NR
167 textField.setEnabled(false);
168 table.setEnabled(true);
5b00c122 169
6a26aa76 170 MetaData meta = getStory().getMeta();
5b00c122 171
6a26aa76 172 setCurrentTitle(meta.getTitle());
5b00c122 173
a6c830bb 174 Map<String, String> metaDesc = BasicReader.getMetaDesc(meta);
df6e2d88
NR
175 String[][] metaDescObj = new String[metaDesc.size()][2];
176 int i = 0;
a6c830bb
NR
177 for (String key : metaDesc.keySet()) {
178 metaDescObj[i][0] = " " + key;
179 metaDescObj[i][1] = metaDesc.get(key);
df6e2d88 180 i++;
f435c113
NR
181 }
182
df6e2d88 183 table.setRowData(metaDescObj);
6a26aa76
NR
184 table.setHeaders(Arrays.asList("key", "value"), false);
185 table.toTop();
5b00c122
NR
186 }
187
188 /**
189 * Append the current chapter.
190 *
191 * @param builder
192 * the builder to append to
193 */
6a26aa76
NR
194 private void displayChapterPage() {
195 table.setVisible(false);
196 textField.setVisible(true);
e8796963
NR
197 table.setEnabled(false);
198 textField.setEnabled(true);
6a26aa76
NR
199
200 StringBuilder builder = new StringBuilder();
201
5b00c122
NR
202 Chapter chap = null;
203 if (chapter == 0) {
204 chap = getStory().getMeta().getResume();
205 } else if (chapter > 0) {
206 chap = getStory().getChapters().get(chapter - 1);
207 }
208
209 // TODO: i18n
210 String chapName = chap == null ? "[No RESUME]" : chap.getName();
6a26aa76 211 setCurrentTitle(String.format("Chapter %d: %s", chapter, chapName));
5b00c122
NR
212
213 if (chap != null) {
214 for (Paragraph para : chap) {
215 if (para.getType() == ParagraphType.BREAK) {
216 builder.append("\n");
217 }
218 builder.append(para.getContent()).append("\n");
219 if (para.getType() == ParagraphType.BREAK) {
220 builder.append("\n");
fdc55375 221 }
edfd3577 222 }
edfd3577 223 }
6a26aa76
NR
224
225 setText(builder.toString());
c1873e56
NR
226 }
227
228 private Story getStory() {
c1873e56
NR
229 return story;
230 }
231
5b00c122
NR
232 /**
233 * Display the given text on the window.
234 *
235 * @param text
236 * the text to display
237 */
238 private void setText(String text) {
239 textField.setText(text);
240 textField.reflowData();
241 textField.toTop();
242 }
243
244 /**
245 * Set the current chapter area to the correct value.
246 */
247 private void setCurrentChapterText() {
248 String name;
249 if (chapter < 0) {
250 name = " " + getStory().getMeta().getTitle();
251 } else if (chapter == 0) {
252 Chapter resume = getStory().getMeta().getResume();
253 if (resume != null) {
254 name = String.format(" %s", resume.getName());
255 } else {
256 // TODO: i18n
257 name = "[No RESUME]";
258 }
259 } else {
260 int max = getStory().getChapters().size();
261 Chapter chap = getStory().getChapters().get(chapter - 1);
262 name = String.format(" %d/%d: %s", chapter, max, chap.getName());
263 }
264
265 int width = getWidth() - currentChapter.getX();
ce424b19 266 name = String.format("%-" + width + "s", name);
5b00c122
NR
267 if (name.length() > width) {
268 name = name.substring(0, width);
269 }
270
271 currentChapter.setLabel(name);
c1873e56 272 }
5b00c122
NR
273
274 /**
6a26aa76 275 * Set the current title in-window.
5b00c122 276 *
5b00c122 277 * @param title
6a26aa76 278 * the new title
5b00c122 279 */
6a26aa76 280 private void setCurrentTitle(String title) {
e8796963
NR
281 String pad = "";
282 if (title.length() < getWidth()) {
283 int padSize = (getWidth() - title.length()) / 2;
284 pad = String.format("%" + padSize + "s", "");
285 }
286
287 title = pad + title + pad;
6a26aa76
NR
288 titleField.setWidth(title.length());
289 titleField.setLabel(title);
290 }
5b00c122 291
6a26aa76
NR
292 private static String desc(MetaData meta) {
293 return String.format("%s: %s", meta.getLuid(), meta.getTitle());
5b00c122 294 }
cf9c5ed1
NR
295
296 @Override
297 public void onCommand(TCommandEvent command) {
298 if (command.getCmd().equals(TuiReaderApplication.CMD_EXIT)) {
299 TuiReaderApplication.close(this);
300 } else {
301 // Handle our own event if needed here
302 super.onCommand(command);
303 }
304 }
c1873e56 305}