tui: fix meta/story use
[fanfix.git] / src / be / nikiroo / fanfix / reader / tui / TuiReaderApplication.java
CommitLineData
16a81ef7 1package be.nikiroo.fanfix.reader.tui;
c1873e56 2
e2d017a3
NR
3import java.awt.Toolkit;
4import java.awt.datatransfer.DataFlavor;
c1873e56 5import java.io.IOException;
6322ab64 6import java.net.URL;
4f9478dc 7import java.net.UnknownHostException;
c1873e56
NR
8
9import jexer.TApplication;
e2d017a3
NR
10import jexer.TCommand;
11import jexer.TKeypress;
c1873e56 12import jexer.TMessageBox;
e2d017a3 13import jexer.TStatusBar;
cf9c5ed1 14import jexer.TWidget;
6322ab64 15import jexer.TWindow;
e2d017a3
NR
16import jexer.event.TMenuEvent;
17import jexer.menu.TMenu;
a8209dd0 18import be.nikiroo.fanfix.Instance;
c1873e56 19import be.nikiroo.fanfix.data.MetaData;
6322ab64
NR
20import be.nikiroo.fanfix.data.Story;
21import be.nikiroo.fanfix.library.BasicLibrary;
16a81ef7
NR
22import be.nikiroo.fanfix.reader.BasicReader;
23import be.nikiroo.fanfix.reader.Reader;
6322ab64 24import be.nikiroo.utils.Progress;
c1873e56 25
6322ab64 26/**
bc2ea776
NR
27 * Manages the TUI general mode and links and manages the {@link TWindow}s.
28 * <p>
29 * It will also enclose a {@link Reader} and simply handle the reading part
30 * differently (it will create the required sub-windows and display them).
6322ab64
NR
31 *
32 * @author niki
33 */
34class TuiReaderApplication extends TApplication implements Reader {
e2d017a3
NR
35 public static final int MENU_OPEN = 1025;
36 public static final int MENU_IMPORT_URL = 1026;
37 public static final int MENU_IMPORT_FILE = 1027;
38 public static final int MENU_EXPORT = 1028;
4f66bfa8
NR
39 public static final int MENU_LIBRARY = 1029;
40 public static final int MENU_EXIT = 1030;
e2d017a3 41
cf9c5ed1
NR
42 public static final TCommand CMD_EXIT = new TCommand(MENU_EXIT) {
43 };
44
6322ab64 45 private Reader reader;
e2d017a3 46 private TuiReaderMainWindow main;
4f66bfa8 47 private String source;
4f66bfa8 48
bc2ea776
NR
49 // start reading if meta present
50 public TuiReaderApplication(Reader reader, BackendType backend)
51 throws Exception {
52 super(backend);
53 init(reader);
c1873e56 54
e0fb1417
NR
55 MetaData meta = getMeta();
56 if (meta != null) {
57 read();
58 }
6322ab64
NR
59 }
60
e2d017a3 61 public TuiReaderApplication(Reader reader, String source,
bc2ea776 62 TApplication.BackendType backend) throws Exception {
c1873e56 63 super(backend);
bc2ea776 64 init(reader);
c1873e56 65
e0fb1417
NR
66 showMain();
67 setSource(source);
4f66bfa8
NR
68 }
69
211f7ddb 70 @Override
6322ab64 71 public void read() throws IOException {
e0fb1417 72 read(getStory(null));
c1873e56 73 }
6322ab64 74
211f7ddb 75 @Override
bc2ea776
NR
76 public MetaData getMeta() {
77 return reader.getMeta();
78 }
79
211f7ddb 80 @Override
bc2ea776
NR
81 public Story getStory(Progress pg) {
82 return reader.getStory(pg);
6322ab64
NR
83 }
84
211f7ddb 85 @Override
6322ab64
NR
86 public BasicLibrary getLibrary() {
87 return reader.getLibrary();
88 }
89
211f7ddb 90 @Override
bc2ea776 91 public void setLibrary(BasicLibrary lib) {
6322ab64
NR
92 reader.setLibrary(lib);
93 }
94
211f7ddb 95 @Override
bc2ea776
NR
96 public void setMeta(MetaData meta) throws IOException {
97 reader.setMeta(meta);
98 }
99
211f7ddb 100 @Override
bc2ea776
NR
101 public void setMeta(String luid) throws IOException {
102 reader.setMeta(luid);
6322ab64
NR
103 }
104
211f7ddb 105 @Override
bc2ea776
NR
106 public void setMeta(URL source, Progress pg) throws IOException {
107 reader.setMeta(source, pg);
6322ab64
NR
108 }
109
211f7ddb 110 @Override
6322ab64
NR
111 public void browse(String source) {
112 reader.browse(source);
113 }
bc2ea776 114
211f7ddb 115 @Override
bc2ea776
NR
116 public int getChapter() {
117 return reader.getChapter();
118 }
119
211f7ddb 120 @Override
bc2ea776
NR
121 public void setChapter(int chapter) {
122 reader.setChapter(chapter);
123 }
124
e0fb1417
NR
125 public void read(Story story) throws IOException {
126 if (story == null) {
127 throw new IOException("No story to read");
128 }
129
130 // TODO: open in editor + external option
131 if (!story.getMeta().isImageDocument()) {
132 TWindow window = new TuiReaderStoryWindow(this, story, getChapter());
133 window.maximize();
134 } else {
135 try {
136 openExternal(getLibrary(), story.getMeta().getLuid());
137 } catch (IOException e) {
138 messageBox("Error when trying to open the story",
139 e.getMessage(), TMessageBox.Type.OK);
140 }
141 }
142 }
143
5b00c122
NR
144 /**
145 * Set the default status bar when this window appear.
146 * <p>
147 * Some shortcuts are always visible, and will be put here.
148 * <p>
149 * Note that shortcuts placed this way on menu won't work unless the menu
150 * also implement them.
151 *
152 * @param window
153 * the new window or menu on screen
154 * @param description
155 * the description to show on the status ba
156 */
157 public TStatusBar setStatusBar(TWindow window, String description) {
158 TStatusBar statusBar = window.newStatusBar(description);
cf9c5ed1 159 statusBar.addShortcutKeypress(TKeypress.kbF10, CMD_EXIT, "Exit");
5b00c122
NR
160 return statusBar;
161
162 }
163
e0fb1417 164 private void showMain() {
5b00c122
NR
165 if (main != null && main.isVisible()) {
166 main.activate();
167 } else {
168 if (main != null) {
169 main.close();
170 }
171 main = new TuiReaderMainWindow(this);
11758a0f 172 main.maximize();
5b00c122
NR
173 }
174 }
175
e0fb1417
NR
176 private void setSource(String source) {
177 this.source = source;
178 showMain();
179 main.setSource(source);
180 }
181
bc2ea776
NR
182 private void init(Reader reader) {
183 this.reader = reader;
184
581d42c0
NR
185 // TODO: traces/errors?
186 Instance.setTraceHandler(null);
a8209dd0 187
e2d017a3
NR
188 // Add the menus TODO: i18n
189 TMenu fileMenu = addMenu("&File");
190 fileMenu.addItem(MENU_OPEN, "&Open");
191 fileMenu.addItem(MENU_EXPORT, "&Save as...");
192 // TODO: Move to...
193 fileMenu.addSeparator();
194 fileMenu.addItem(MENU_IMPORT_URL, "Import &URL...");
195 fileMenu.addItem(MENU_IMPORT_FILE, "Import &file...");
196 fileMenu.addSeparator();
4f66bfa8
NR
197 fileMenu.addItem(MENU_LIBRARY, "Lib&rary");
198 fileMenu.addSeparator();
e2d017a3
NR
199 fileMenu.addItem(MENU_EXIT, "E&xit");
200
5b00c122 201 setStatusBar(fileMenu, "File-management "
e2d017a3 202 + "commands (Open, Save, Print, etc.)");
e2d017a3
NR
203
204 // TODO: Edit: re-download, delete
205
206 //
207
bc2ea776 208 addWindowMenu();
bc2ea776
NR
209
210 getBackend().setTitle("Fanfix");
211 }
e2d017a3
NR
212
213 @Override
214 protected boolean onMenu(TMenuEvent menu) {
215 // TODO: i18n
216 switch (menu.getId()) {
217 case MENU_EXIT:
cf9c5ed1 218 close(this);
e0fb1417
NR
219 return true;
220 case MENU_OPEN:
221 String openfile = null;
222 try {
223 openfile = fileOpenBox(".");
224 reader.setMeta(BasicReader.getUrl(openfile), null);
225 read();
226 } catch (IOException e) {
227 // TODO: i18n
228 error("Fail to open file"
229 + (openfile == null ? "" : ": " + openfile),
230 "Import error", e);
231 }
232
e2d017a3
NR
233 return true;
234 case MENU_IMPORT_URL:
235 String clipboard = "";
236 try {
237 clipboard = ("" + Toolkit.getDefaultToolkit()
238 .getSystemClipboard().getData(DataFlavor.stringFlavor))
239 .trim();
240 } catch (Exception e) {
241 // No data will be handled
242 }
243
244 if (clipboard == null || !clipboard.startsWith("http")) {
245 clipboard = "";
246 }
247
248 String url = inputBox("Import story", "URL to import", clipboard)
249 .getText();
250
4f9478dc
NR
251 try {
252 if (!imprt(url)) {
e0fb1417 253 // TODO: i18n
4f9478dc
NR
254 error("URK not supported: " + url, "Import error");
255 }
256 } catch (IOException e) {
e0fb1417 257 // TODO: i18n
4f9478dc 258 error("Fail to import URL: " + url, "Import error", e);
e2d017a3
NR
259 }
260
261 return true;
262 case MENU_IMPORT_FILE:
4f9478dc 263 String filename = null;
e2d017a3 264 try {
4f9478dc 265 filename = fileOpenBox(".");
e2d017a3 266 if (!imprt(filename)) {
e0fb1417 267 // TODO: i18n
4f9478dc 268 error("File not supported: " + filename, "Import error");
e2d017a3
NR
269 }
270 } catch (IOException e) {
e0fb1417 271 // TODO: i18n
4f9478dc
NR
272 error("Fail to import file"
273 + (filename == null ? "" : ": " + filename),
274 "Import error", e);
e2d017a3 275 }
4f66bfa8
NR
276 return true;
277 case MENU_LIBRARY:
e0fb1417
NR
278 showMain();
279 setSource(source);
e2d017a3
NR
280 return true;
281 }
282
283 return super.onMenu(menu);
284 }
285
4f9478dc
NR
286 /**
287 * Import the given url.
288 * <p>
289 * Can fail if the host is not supported.
290 *
291 * @param url
292 *
293 * @return TRUE in case of success, FALSE if the host is not supported
294 *
295 * @throws IOException
296 * in case of I/O error
297 */
298 private boolean imprt(String url) throws IOException {
e2d017a3
NR
299 try {
300 reader.getLibrary().imprt(BasicReader.getUrl(url), null);
301 main.refreshStories();
302 return true;
4f9478dc 303 } catch (UnknownHostException e) {
e2d017a3
NR
304 return false;
305 }
306 }
16a81ef7
NR
307
308 @Override
309 public void openExternal(BasicLibrary lib, String luid) throws IOException {
310 reader.openExternal(lib, luid);
311 }
cf9c5ed1 312
4f9478dc
NR
313 /**
314 * Display an error message and log it.
315 *
316 * @param message
317 * the message
318 * @param title
319 * the title of the error message
320 */
321 private void error(String message, String title) {
322 error(message, title, null);
323 }
324
325 /**
326 * Display an error message and log it, including the linked
327 * {@link Exception}.
328 *
329 * @param message
330 * the message
331 * @param title
332 * the title of the error message
333 * @param e
334 * the exception to log if any (can be NULL)
335 */
336 private void error(String message, String title, Exception e) {
337 Instance.getTraceHandler().error(title + ": " + message);
338 if (e != null) {
339 Instance.getTraceHandler().error(e);
340 }
341
342 if (e != null) {
343 messageBox(title, message //
344 + "\n" + e.getMessage());
345 } else {
346 messageBox(title, message);
347 }
348 }
349
cf9c5ed1
NR
350 /**
351 * Ask the user and, if confirmed, close the {@link TApplication} this
352 * {@link TWidget} is running on.
353 * <p>
354 * This should result in the program terminating.
355 *
356 * @param widget
357 * the {@link TWidget}
358 */
359 static public void close(TWidget widget) {
360 close(widget.getApplication());
361 }
362
363 /**
364 * Ask the user and, if confirmed, close the {@link TApplication}.
365 * <p>
366 * This should result in the program terminating.
367 *
368 * @param app
369 * the {@link TApplication}
370 */
371 static void close(TApplication app) {
372 // TODO: i18n
373 if (app.messageBox("Confirmation", "(TODO: i18n) Exit application?",
374 TMessageBox.Type.YESNO).getResult() == TMessageBox.Result.YES) {
375 app.exit();
376 }
377 }
c1873e56 378}