1 package be
.nikiroo
.fanfix
.reader
.tui
;
3 import java
.awt
.Toolkit
;
4 import java
.awt
.datatransfer
.DataFlavor
;
5 import java
.io
.IOException
;
7 import java
.net
.UnknownHostException
;
9 import jexer
.TApplication
;
10 import jexer
.TCommand
;
11 import jexer
.TKeypress
;
12 import jexer
.TMessageBox
;
13 import jexer
.TStatusBar
;
16 import jexer
.event
.TCommandEvent
;
17 import jexer
.event
.TMenuEvent
;
18 import jexer
.menu
.TMenu
;
19 import be
.nikiroo
.fanfix
.Instance
;
20 import be
.nikiroo
.fanfix
.data
.MetaData
;
21 import be
.nikiroo
.fanfix
.data
.Story
;
22 import be
.nikiroo
.fanfix
.library
.BasicLibrary
;
23 import be
.nikiroo
.fanfix
.reader
.BasicReader
;
24 import be
.nikiroo
.fanfix
.reader
.Reader
;
25 import be
.nikiroo
.utils
.Progress
;
28 * Manages the TUI general mode and links and manages the {@link TWindow}s.
30 * It will also enclose a {@link Reader} and simply handle the reading part
31 * differently (it will create the required sub-windows and display them).
35 class TuiReaderApplication
extends TApplication
implements Reader
{
36 public static final int MENU_OPEN
= 1025;
37 public static final int MENU_IMPORT_URL
= 1026;
38 public static final int MENU_IMPORT_FILE
= 1027;
39 public static final int MENU_EXPORT
= 1028;
40 public static final int MENU_LIBRARY
= 1029;
41 public static final int MENU_EXIT
= 1030;
43 public static final TCommand CMD_EXIT
= new TCommand(MENU_EXIT
) {
46 private Reader reader
;
47 private TuiReaderMainWindow main
;
48 private String source
;
50 // start reading if meta present
51 public TuiReaderApplication(Reader reader
, BackendType backend
)
56 MetaData meta
= getMeta();
62 public TuiReaderApplication(Reader reader
, String source
,
63 TApplication
.BackendType backend
) throws Exception
{
72 public void read() throws IOException
{
77 public MetaData
getMeta() {
78 return reader
.getMeta();
82 public Story
getStory(Progress pg
) {
83 return reader
.getStory(pg
);
87 public BasicLibrary
getLibrary() {
88 return reader
.getLibrary();
92 public void setLibrary(BasicLibrary lib
) {
93 reader
.setLibrary(lib
);
97 public void setMeta(MetaData meta
) throws IOException
{
102 public void setMeta(String luid
) throws IOException
{
103 reader
.setMeta(luid
);
107 public void setMeta(URL source
, Progress pg
) throws IOException
{
108 reader
.setMeta(source
, pg
);
112 public void browse(String source
) {
113 reader
.browse(source
);
117 public int getChapter() {
118 return reader
.getChapter();
122 public void setChapter(int chapter
) {
123 reader
.setChapter(chapter
);
126 public void read(Story story
) throws IOException
{
128 throw new IOException("No story to read");
131 // TODO: open in editor + external option
132 if (!story
.getMeta().isImageDocument()) {
133 TWindow window
= new TuiReaderStoryWindow(this, story
, getChapter());
137 openExternal(getLibrary(), story
.getMeta().getLuid());
138 } catch (IOException e
) {
139 messageBox("Error when trying to open the story",
140 e
.getMessage(), TMessageBox
.Type
.OK
);
146 * Set the default status bar when this window appear.
148 * Some shortcuts are always visible, and will be put here.
150 * Note that shortcuts placed this way on menu won't work unless the menu
151 * also implement them.
154 * the new window or menu on screen
156 * the description to show on the status ba
158 public TStatusBar
setStatusBar(TWindow window
, String description
) {
159 TStatusBar statusBar
= window
.newStatusBar(description
);
160 statusBar
.addShortcutKeypress(TKeypress
.kbF10
, CMD_EXIT
, "Exit");
165 private void showMain() {
166 if (main
!= null && main
.isVisible()) {
172 main
= new TuiReaderMainWindow(this);
177 private void setSource(String source
) {
178 this.source
= source
;
180 main
.setSource(source
);
183 private void init(Reader reader
) {
184 this.reader
= reader
;
186 // TODO: traces/errors?
187 Instance
.setTraceHandler(null);
189 // Add the menus TODO: i18n
190 TMenu fileMenu
= addMenu("&File");
191 fileMenu
.addItem(MENU_OPEN
, "&Open");
192 fileMenu
.addItem(MENU_EXPORT
, "&Save as...");
194 fileMenu
.addSeparator();
195 fileMenu
.addItem(MENU_IMPORT_URL
, "Import &URL...");
196 fileMenu
.addItem(MENU_IMPORT_FILE
, "Import &file...");
197 fileMenu
.addSeparator();
198 fileMenu
.addItem(MENU_LIBRARY
, "Lib&rary");
199 fileMenu
.addSeparator();
200 fileMenu
.addItem(MENU_EXIT
, "E&xit");
202 setStatusBar(fileMenu
, "File-management "
203 + "commands (Open, Save, Print, etc.)");
205 // TODO: Edit: re-download, delete
211 getBackend().setTitle("Fanfix");
215 protected boolean onCommand(TCommandEvent command
) {
216 if (command
.getCmd().equals(TuiReaderMainWindow
.CMD_SEARCH
)) {
217 messageBox("title", "caption");
220 return super.onCommand(command
);
224 protected boolean onMenu(TMenuEvent menu
) {
226 switch (menu
.getId()) {
231 String openfile
= null;
233 openfile
= fileOpenBox(".");
234 reader
.setMeta(BasicReader
.getUrl(openfile
), null);
236 } catch (IOException e
) {
238 error("Fail to open file"
239 + (openfile
== null ?
"" : ": " + openfile
),
244 case MENU_IMPORT_URL
:
245 String clipboard
= "";
247 clipboard
= ("" + Toolkit
.getDefaultToolkit()
248 .getSystemClipboard().getData(DataFlavor
.stringFlavor
))
250 } catch (Exception e
) {
251 // No data will be handled
254 if (clipboard
== null || !clipboard
.startsWith("http")) {
258 String url
= inputBox("Import story", "URL to import", clipboard
)
264 error("URK not supported: " + url
, "Import error");
266 } catch (IOException e
) {
268 error("Fail to import URL: " + url
, "Import error", e
);
272 case MENU_IMPORT_FILE
:
273 String filename
= null;
275 filename
= fileOpenBox(".");
276 if (!imprt(filename
)) {
278 error("File not supported: " + filename
, "Import error");
280 } catch (IOException e
) {
282 error("Fail to import file"
283 + (filename
== null ?
"" : ": " + filename
),
293 return super.onMenu(menu
);
297 * Import the given url.
299 * Can fail if the host is not supported.
303 * @return TRUE in case of success, FALSE if the host is not supported
305 * @throws IOException
306 * in case of I/O error
308 private boolean imprt(String url
) throws IOException
{
310 reader
.getLibrary().imprt(BasicReader
.getUrl(url
), null);
311 main
.refreshStories();
313 } catch (UnknownHostException e
) {
319 public void openExternal(BasicLibrary lib
, String luid
) throws IOException
{
320 reader
.openExternal(lib
, luid
);
324 * Display an error message and log it.
329 * the title of the error message
331 private void error(String message
, String title
) {
332 error(message
, title
, null);
336 * Display an error message and log it, including the linked
342 * the title of the error message
344 * the exception to log if any (can be NULL)
346 private void error(String message
, String title
, Exception e
) {
347 Instance
.getTraceHandler().error(title
+ ": " + message
);
349 Instance
.getTraceHandler().error(e
);
353 messageBox(title
, message
//
354 + "\n" + e
.getMessage());
356 messageBox(title
, message
);
361 * Ask the user and, if confirmed, close the {@link TApplication} this
362 * {@link TWidget} is running on.
364 * This should result in the program terminating.
367 * the {@link TWidget}
369 static public void close(TWidget widget
) {
370 close(widget
.getApplication());
374 * Ask the user and, if confirmed, close the {@link TApplication}.
376 * This should result in the program terminating.
379 * the {@link TApplication}
381 static void close(TApplication app
) {
383 if (app
.messageBox("Confirmation", "(TODO: i18n) Exit application?",
384 TMessageBox
.Type
.YESNO
).getResult() == TMessageBox
.Result
.YES
) {