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