- [x] New API on FimFiction.net (faster)
- [ ] Others? Any ideas? I'm open for requests
- [x] [e-Hentai](https://e-hentai.org/) requested
- - [ ] Find some FR comics/manga websites
-- [x] A GUI library
+ - [x] Find some FR comics/manga websites
+ - [ ] Find more FR thingies
+- [ ] A GUI library
- [x] Make one
- [x] Make it run when no args passed
- [x] Fix the UI, it is ugly
- [x] ..as a screen view
- [x] options screen
- [x] support progress events
+ - [x] Real menus
+ - [ ] Store the long lists in [A-B], [BA-BB], ...
- [ ] A TUI library
- [x] Choose an output (Jexer)
- [x] Implement it from --set-reader to the actual window
}
}
- // We cannot do it when in GUI mode, because it is async...
- // So if we close the temp files before it is actually used,
- // we have a problem...
- // TODO: close it at the correct time (for now, finalize try to do it)
- if (false) {
- try {
- Instance.getTempFiles().close();
- } catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException(
- "Cannot dispose of the temporary files", e));
- }
+ try {
+ Instance.getTempFiles().close();
+ } catch (IOException e) {
+ Instance.getTraceHandler()
+ .error(new IOException(
+ "Cannot dispose of the temporary files", e));
}
if (exitCode == 255) {
}
/**
- * Start the CLI reader for this {@link Story}.
+ * Start the current reader for this {@link Story}.
*
* @param story
* the LUID of the {@link Story} in the {@link LocalLibrary}
if (chapString != null) {
try {
reader.setChapter(Integer.parseInt(chapString));
- reader.read();
+ reader.read(true);
} catch (NumberFormatException e) {
Instance.getTraceHandler().error(
new IOException("Chapter number cannot be parsed: "
return 2;
}
} else {
- reader.read();
+ reader.read(true);
}
} catch (IOException e) {
Instance.getTraceHandler().error(e);
BasicSupport support = BasicSupport.getSupport(source);
if (support != null) {
- Instance.getTraceHandler().trace("Support found: " + support.getClass());
+ Instance.getTraceHandler().trace(
+ "Support found: " + support.getClass());
Progress pgIn = new Progress();
Progress pgOut = new Progress();
if (pg != null) {
}
@Override
- public synchronized void setMeta(URL url, Progress pg)
- throws IOException {
+ public synchronized void setMeta(URL url, Progress pg) throws IOException {
BasicSupport support = BasicSupport.getSupport(url);
if (support == null) {
throw new IOException("URL not supported: " + url.toString());
* the {@link BasicLibrary} to select the {@link Story} from
* @param luid
* the {@link Story} LUID
+ * @param sync
+ * execute the process synchronously (wait until it is terminated
+ * before returning)
*
* @throws IOException
* in case of I/O error
*/
@Override
- public void openExternal(BasicLibrary lib, String luid) throws IOException {
+ public void openExternal(BasicLibrary lib, String luid, boolean sync)
+ throws IOException {
MetaData meta = lib.getInfo(luid);
File target = lib.getFile(luid, null);
- openExternal(meta, target);
+ openExternal(meta, target, sync);
}
/**
* the {@link Story} to load
* @param target
* the target {@link File}
+ * @param sync
+ * execute the process synchronously (wait until it is terminated
+ * before returning)
*
* @throws IOException
* in case of I/O error
*/
- protected void openExternal(MetaData meta, File target) throws IOException {
+ protected void openExternal(MetaData meta, File target, boolean sync)
+ throws IOException {
String program = null;
if (meta.isImageDocument()) {
program = Instance.getUiConfig().getString(
program = null;
}
- start(target, program);
+ start(target, program, sync);
}
/**
* the target to open
* @param program
* the program to use or NULL for the default system starter
+ * @param sync
+ * execute the process synchronously (wait until it is terminated
+ * before returning)
*
* @throws IOException
* in case of I/O error
*/
- protected void start(File target, String program) throws IOException {
+ protected void start(File target, String program, boolean sync)
+ throws IOException {
+
+ Process proc = null;
if (program == null) {
boolean ok = false;
for (String starter : new String[] { "xdg-open", "open", "see",
try {
Instance.getTraceHandler().trace(
"starting external program");
- Runtime.getRuntime().exec(
+ proc = Runtime.getRuntime().exec(
new String[] { starter, target.getAbsolutePath() });
ok = true;
break;
}
} else {
Instance.getTraceHandler().trace("starting external program");
- Runtime.getRuntime().exec(
+ proc = Runtime.getRuntime().exec(
new String[] { program, target.getAbsolutePath() });
}
+
+ if (proc != null && sync) {
+ while (proc.isAlive()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
}
}
/**
* Start the {@link Story} Reading.
*
+ * @param sync
+ * execute the process synchronously (wait until it is terminated
+ * before returning)
+ *
* @throws IOException
* in case of I/O error or if the {@link Story} was not
* previously set
*/
- public void read() throws IOException;
+ public void read(boolean sync) throws IOException;
/**
* The selected chapter to start reading at (starting at 1, 0 = description,
/**
* Start the reader in browse mode for the given source (or pass NULL for
* all sources).
+ * <p>
+ * Note that this must be a <b>synchronous</b> action.
*
* @param source
* the type of {@link Story} to take into account, or NULL for
public void browse(String source);
/**
- * Open the {@link Story} with an external reader (the program will be
+ * Open the {@link Story} with an external reader (the program should be
* passed the main file associated with this {@link Story}).
*
* @param lib
* the {@link BasicLibrary} to select the {@link Story} from
* @param luid
* the {@link Story} LUID
+ * @param sync
+ * execute the process synchronously (wait until it is terminated
+ * before returning)
*
* @throws IOException
* in case of I/O error
*/
- public void openExternal(BasicLibrary lib, String luid) throws IOException;
+ public void openExternal(BasicLibrary lib, String luid, boolean sync)
+ throws IOException;
}
}
@Override
- public void read() throws IOException {
+ public void read(boolean sync) throws IOException {
}
@Override
}
@Override
- protected void start(File target, String program) throws IOException {
+ protected void start(File target, String program, boolean sync) throws IOException {
if (program == null) {
try {
Intent[] intents = new Intent[] { //
app.startActivity(chooserIntent);
} catch (UnsupportedOperationException e) {
- super.start(target, program);
+ super.start(target, program, sync);
}
} else {
- super.start(target, program);
+ super.start(target, program, sync);
}
}
}
*/
class CliReader extends BasicReader {
@Override
- public void read() throws IOException {
+ public void read(boolean sync) throws IOException {
MetaData meta = getMeta();
if (meta == null) {
}
@Override
- public void read() throws IOException {
+ public void read(boolean sync) throws IOException {
try {
TuiReaderApplication app = new TuiReaderApplication(this,
guessBackendType());
super(backend);
init(reader);
- MetaData meta = getMeta();
- if (meta != null) {
- read();
+ if (getMeta() != null) {
+ read(false);
}
}
}
@Override
- public void read() throws IOException {
- read(getStory(null));
+ public void read(boolean sync) throws IOException {
+ read(getStory(null), sync);
}
@Override
reader.setChapter(chapter);
}
- public void read(Story story) throws IOException {
+ /**
+ * Open the given {@link Story} for reading. This may or may not start an
+ * external program to read said {@link Story}.
+ *
+ * @param story
+ * the {@link Story} to read
+ * @param sync
+ * execute the process synchronously (wait until it is terminated
+ * before returning)
+ *
+ * @throws IOException
+ * in case of I/O errors
+ */
+ public void read(Story story, boolean sync) throws IOException {
if (story == null) {
throw new IOException("No story to read");
}
window.maximize();
} else {
try {
- openExternal(getLibrary(), story.getMeta().getLuid());
+ openExternal(getLibrary(), story.getMeta().getLuid(), sync);
} catch (IOException e) {
messageBox("Error when trying to open the story",
e.getMessage(), TMessageBox.Type.OK);
try {
openfile = fileOpenBox(".");
reader.setMeta(BasicReader.getUrl(openfile), null);
- read();
+ read(false);
} catch (IOException e) {
// TODO: i18n
error("Fail to open file"
}
@Override
- public void openExternal(BasicLibrary lib, String luid) throws IOException {
- reader.openExternal(lib, luid);
+ public void openExternal(BasicLibrary lib, String luid, boolean sync)
+ throws IOException {
+ reader.openExternal(lib, luid, sync);
}
/**
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.library.BasicLibrary;
import be.nikiroo.fanfix.output.BasicOutput.OutputType;
-import be.nikiroo.fanfix.reader.Reader;
import be.nikiroo.jexer.TSizeConstraint;
/**
private TList list;
private List<MetaData> listKeys;
private List<String> listItems;
- private Reader reader;
+ private TuiReaderApplication reader;
private Mode mode = Mode.SOURCE;
private String target = null;
try {
reader.setChapter(-1);
reader.setMeta(meta);
- reader.read();
+ reader.read(false);
} catch (IOException e) {
Instance.getTraceHandler().error(e);
}
import java.awt.Desktop;
import java.awt.EventQueue;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
}
@Override
- public void read() throws IOException {
+ public void read(boolean sync) throws IOException {
MetaData meta = getMeta();
if (meta == null) {
throw new IOException("No story to read");
}
- read(meta.getLuid(), null);
+ read(meta.getLuid(), sync, null);
}
/**
// TODO: improve presentation of update message
final VersionCheck updates = VersionCheck.check();
StringBuilder builder = new StringBuilder();
+ final Boolean[] done = new Boolean[] { false };
final JEditorPane updateMessage = new JEditorPane("text/html", "");
if (updates.isNewVersionAvailable()) {
}
}
- new GuiReaderFrame(GuiReader.this, typeFinal).setVisible(true);
+ try {
+ GuiReaderFrame gui = new GuiReaderFrame(GuiReader.this,
+ typeFinal);
+ gui.setVisible(true);
+ gui.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ super.windowClosed(e);
+ done[0] = true;
+ }
+ });
+ } catch (Exception e) {
+ Instance.getTraceHandler().error(e);
+ done[0] = true;
+ }
}
});
+
+ // This action must be synchronous, so wait until the frame is closed
+ while (!done[0]) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
}
@Override
- public void start(File target, String program) throws IOException {
- if (program == null) {
+ public void start(File target, String program, boolean sync)
+ throws IOException {
+
+ boolean handled = false;
+ if (program == null && !sync) {
try {
Desktop.getDesktop().browse(target.toURI());
+ handled = true;
} catch (UnsupportedOperationException e) {
- super.start(target, program);
}
- } else {
- super.start(target, program);
+ }
+
+ if (!handled) {
+ super.start(target, program, sync);
}
}
/**
* "Open" the given {@link Story}. It usually involves starting an external
* program adapted to the given file type.
+ * <p>
+ * Asynchronous method.
*
* @param luid
* the luid of the {@link Story} to open
+ * @param sync
+ * execute the process synchronously (wait until it is terminated
+ * before returning)
* @param pg
* the optional progress (we may need to prepare the
* {@link Story} for reading
* @throws IOException
* in case of I/O errors
*/
- void read(String luid, Progress pg) throws IOException {
+ void read(String luid, boolean sync, Progress pg) throws IOException {
File file = cacheLib.getFile(luid, pg);
// TODO: show a special page for the chapter?
// We could also implement an internal viewer, both for image and
// non-image documents
- openExternal(getLibrary().getInfo(luid), file);
+ openExternal(getLibrary().getInfo(luid), file, sync);
}
/**
@Override
public void run() {
try {
- reader.read(book.getMeta().getLuid(), pg);
+ reader.read(book.getMeta().getLuid(), false, pg);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {