Partial HTML implementation, partial GUI support
authorNiki Roo <niki@nikiroo.be>
Mon, 13 Feb 2017 22:23:54 +0000 (23:23 +0100)
committerNiki Roo <niki@nikiroo.be>
Mon, 13 Feb 2017 22:23:54 +0000 (23:23 +0100)
The HTML implementation is working, but subpar, and with lots of copy-pasted code
The LocalReader is a work in progress

12 files changed:
Makefile.base
configure.sh
libs/nikiroo-utils-0.9.6-sources.jar [moved from libs/nikiroo-utils-0.9.5-sources.jar with 66% similarity]
src/be/nikiroo/fanfix/Main.java
src/be/nikiroo/fanfix/bundles/Config.java
src/be/nikiroo/fanfix/bundles/config.properties
src/be/nikiroo/fanfix/bundles/resources.properties
src/be/nikiroo/fanfix/output/BasicOutput.java
src/be/nikiroo/fanfix/output/Html.java
src/be/nikiroo/fanfix/reader/LocalReader.java [new file with mode: 0644]
src/be/nikiroo/fanfix/reader/LocalReaderFrame.java [new file with mode: 0644]
src/be/nikiroo/fanfix/supported/BasicSupport.java

index 559b89d9020a53df2b6212600233c68cd88841a2..9901644035cee9e0610447751befe4b1e28cb7cc 100644 (file)
@@ -7,6 +7,7 @@
 #TEST = path to main test source to compile
 #JAR_FLAGS += a list of things to pack, each usually prefixed with "-C bin/"
 #SJAR_FLAGS += a list of things to pack, each usually prefixed with "-C src/", for *-sources.jar files
+#TEST_PARAMS = any parameter to pass to the test runnable when "test-run"
 
 JAVAC = javac
 JAVAC_FLAGS += -encoding UTF-8 -d ./bin/ -cp ./src/
@@ -34,7 +35,7 @@ RJAR_FLAGS += -jar
 
 all: build jar
 
-.PHONY: all clean mrproper mrpropre build run jrun jar resources install libs love 
+.PHONY: all clean mrproper mrpropre build run jrun jar resources test-resources install libs love 
 
 bin:
        @mkdir -p bin
@@ -50,7 +51,7 @@ build: resources
                $(JAVAC) $(JAVAC_FLAGS) "src/$$sup.java" ; \
        done
 
-test: 
+test: test-resources
        @[ -e bin/$(MAIN).class ] || echo You need to build the sources
        @[ -e bin/$(MAIN).class ]
        @echo Compiling test program...
@@ -86,7 +87,17 @@ love:
 
 resources: libs
        @echo Copying resources into bin/...
-       @cd src && find . | grep -v '\.java$$' | while read -r ln; do \
+       @cd src && find . | grep -v '\.java$$' | grep -v '/test/' | while read -r ln; do \
+               if [ -f "$$ln" ]; then \
+                       dir="`dirname "$$ln"`"; \
+                       mkdir -p "../bin/$$dir" ; \
+                       cp "$$ln" "../bin/$$ln" ; \
+               fi ; \
+       done
+
+test-resources: resources
+       @echo Copying test resources into bin/...
+       @cd src && find . | grep -v '\.java$$' | grep '/test/' | while read -r ln; do \
                if [ -f "$$ln" ]; then \
                        dir="`dirname "$$ln"`"; \
                        mkdir -p "../bin/$$dir" ; \
@@ -134,7 +145,7 @@ run-test:
        @[ "$(TEST)" = "" -o -e "bin/$(TEST).class" ]
        @echo Running tests for "$(NAME)"...
        @[ "$(TEST)" != "" ] || echo No test sources defined.
-       [ "$(TEST)"  = "" ] || $(JAVA) $(JAVA_FLAGS) $(TEST)
+       [ "$(TEST)"  = "" ] || ( clear ; $(JAVA) $(JAVA_FLAGS) $(TEST) $(TEST_PARAMS) )
 
 install:
        @[ -e $(NAME).jar ] || echo You need to build the jar
index 2954620ed4927ab5954729caf8fc558694f55cdc..1da9835fa5a4c402432551f4ae832c06d36dee04 100755 (executable)
@@ -33,7 +33,19 @@ done
 
 [ $valid = false ] && exit 2
 
+if [ "`whereis tput`" = "tput:" ]; then
+       ok='"[ ok ]"';
+       ko='"[ !! ]"';
+       cols=80;
+else
+       ok='"`tput bold`[`tput setf 2` OK `tput init``tput bold`]`tput init`"';
+       ko='"`tput bold`[`tput setf 4` !! `tput init``tput bold`]`tput init`"';
+       cols='"`tput cols`"';
+fi;
+
 echo "MAIN = be/nikiroo/fanfix/Main" > Makefile
+echo "TEST = " >> Makefile
+echo "TEST_PARAMS = $cols $ok $ko" >> Makefile
 echo "NAME = fanfix" >> Makefile
 echo "PREFIX = $PREFIX" >> Makefile
 echo "JAR_FLAGS += -C bin/ org -C bin/ be -C ./ VERSION" >> Makefile
similarity index 66%
rename from libs/nikiroo-utils-0.9.5-sources.jar
rename to libs/nikiroo-utils-0.9.6-sources.jar
index 7e424791ebb8637014546b728cc47b6f1b97eee7..42d2774f3505998f1b129f265c13509ee36188f7 100644 (file)
Binary files a/libs/nikiroo-utils-0.9.5-sources.jar and b/libs/nikiroo-utils-0.9.6-sources.jar differ
index d5669d56622750e754ae9a8288221a0f2c531872..46eb0b5ab9fc08becb2b55924aa9ef2bb6b9f092 100644 (file)
@@ -379,6 +379,7 @@ public class Main {
                        } else {
                                try {
                                        BasicSupport support = BasicSupport.getSupport(source);
+                                       
                                        if (support != null) {
                                                Story story = support.process(source);
 
index 060bc8126ac9dee202ce2c78a21b810c76c6c10b..86f480d421db9b1345ca9fe4e3a7b21f2c2571d6 100644 (file)
@@ -46,4 +46,9 @@ public enum Config {
        CHAPTER_EN, //
        @Meta(what = "Chapter identification string", where = "", format = "", info = "used to identify a starting chapter in text mode")
        CHAPTER_FR, //
+       @Meta(what = "Output type", where = "Local Reader", format = "One of the known output type", info = "The type of output for the Local Reader for non-images documents")
+       LOCAL_READER_NON_IMAGES_DOCUMENT_TYPE, //
+       @Meta(what = "Output type", where = "Local Reader", format = "One of the known output type", info = "The type of output for the Local Reader for images documents")
+       LOCAL_READER_IMAGES_DOCUMENT_TYPE, //
+
 }
index 67b5e7fcc93fdd8496badf884eda26f551eb615a..535fb32617e0a32e15b912a39ee77007979479f9 100644 (file)
@@ -59,3 +59,9 @@ CHAPTER_EN = Chapter
 # (WHAT: Chapter identification string)
 # used to identify a starting chapter in text mode
 CHAPTER_FR = Chapitre
+# (WHAT: Output type, WHERE: Local Reader, FORMAT: One of the known output type)
+# The type of output for the Local Reader for non-images documents
+LOCAL_READER_NON_IMAGES_DOCUMENT_TYPE = HTML
+# (WHAT: Output type, WHERE: Local Reader, FORMAT: One of the known output type)
+# The type of output for the Local Reader for images documents
+LOCAL_READER_IMAGES_DOCUMENT_TYPE = CBZ
index 035594f6728299d9fc4702ed23cf7221bd422179..37ecd554999b0b15ac9768c94e0305898ca6c700 100644 (file)
@@ -133,4 +133,4 @@ OUTPUT_DESC_SYSOUT = A simple DEBUG console output
 LATEX_LANG_UNKNOWN = Unknown language: %s
 # (WHAT: 'by' prefix before author name)
 # used to output the author, make sure it is covered by Config.BYS for input detection
-BY = By
+BY = by
index 9b53859a199c05aa7742b8cd259a310230f5167d..33a42c574bed176d90556bce1c447fba61ed26fe 100644 (file)
@@ -92,7 +92,7 @@ public abstract class BasicOutput {
 
                /**
                 * Call {@link OutputType#valueOf(String.toUpperCase())} but return NULL
-                * for NULL instead of raising exception.
+                * for NULL and empty instead of raising an exception.
                 * 
                 * @param typeName
                 *            the possible type name
@@ -100,7 +100,7 @@ public abstract class BasicOutput {
                 * @return NULL or the type
                 */
                public static OutputType valueOfNullOkUC(String typeName) {
-                       if (typeName == null) {
+                       if (typeName == null || typeName.isEmpty()) {
                                return null;
                        }
 
@@ -441,7 +441,7 @@ public abstract class BasicOutput {
                        case LATEX:
                                return new LaTeX().setType(type, infoCover, infoCover);
                        case HTML:
-                               return new Html().setType(type, false, false);
+                               return new Html().setType(type, infoCover, infoCover);
                        }
                }
 
index 4226bf84b75dfa6ea97d3770c93a44416f04e38d..29a0f32b6404e6b1c0822e6e45d11b6783601905 100644 (file)
@@ -1,6 +1,167 @@
 package be.nikiroo.fanfix.output;
 
-//TODO: implement it for LocalReader
-class Html extends Text {
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
 
+import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.bundles.StringId;
+import be.nikiroo.fanfix.data.Chapter;
+import be.nikiroo.fanfix.data.Paragraph;
+import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
+import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.utils.StringUtils;
+
+class Html extends BasicOutput {
+       protected FileWriter writer;
+       private boolean inDialogue = false;
+       private boolean inNormal = false;
+
+       @Override
+       public File process(Story story, File targetDir, String targetName)
+                       throws IOException {
+               File target = new File(targetDir, targetName);
+               target.mkdir();
+
+               targetName = new File(targetName, "index").getPath();
+
+               String targetNameOrig = targetName;
+               targetName += getDefaultExtension();
+
+               target = new File(targetDir, targetName);
+
+               writer = new FileWriter(target);
+               try {
+                       super.process(story, targetDir, targetNameOrig);
+               } finally {
+                       writer.close();
+                       writer = null;
+               }
+
+               return target;
+       }
+
+       @Override
+       public String getDefaultExtension() {
+               return ".html";
+       }
+
+       @Override
+       protected void writeStoryHeader(Story story) throws IOException {
+               String title = "";
+               if (story.getMeta() != null) {
+                       title = story.getMeta().getTitle();
+               }
+
+               writer.write("<!DOCTYPE html>");
+               writer.write("\n<html>");
+               writer.write("\n<head>");
+               writer.write("\n        <meta http-equiv='content-type' content='text/html; charset=utf-8'>");
+               writer.write("\n        <meta name='viewport' content='width=device-width, initial-scale=1.0'>");
+               writer.write("\n        <title>" + StringUtils.xmlEscape(title) + "</title>");
+               writer.write("\n</head>");
+               writer.write("\n<body>\n");
+
+               writer.write("<h1>" + StringUtils.xmlEscape(title) + "</h1>\n\n");
+       }
+
+       @Override
+       protected void writeStoryFooter(Story story) throws IOException {
+               writer.write("</body>\n");
+       }
+
+       @Override
+       protected void writeChapterHeader(Chapter chap) throws IOException {
+               String txt;
+               if (chap.getName() != null && !chap.getName().isEmpty()) {
+                       txt = Instance.getTrans().getString(StringId.CHAPTER_NAMED,
+                                       chap.getNumber(), chap.getName());
+               } else {
+                       txt = Instance.getTrans().getString(StringId.CHAPTER_UNNAMED,
+                                       chap.getNumber());
+               }
+
+               writer.write("<h1>" + StringUtils.xmlEscape(txt) + "</h1>\n\n");
+
+               inDialogue = false;
+               inNormal = false;
+       }
+
+       @Override
+       protected void writeParagraphHeader(Paragraph para) throws IOException {
+               if (para.getType() == ParagraphType.QUOTE && !inDialogue) {
+                       writer.write("          <div class='dialogues'>\n");
+                       inDialogue = true;
+               } else if (para.getType() != ParagraphType.QUOTE && inDialogue) {
+                       writer.write("          </div>\n");
+                       inDialogue = false;
+               }
+
+               if (para.getType() == ParagraphType.NORMAL && !inNormal) {
+                       writer.write("          <div class='normals'>\n");
+                       inNormal = true;
+               } else if (para.getType() != ParagraphType.NORMAL && inNormal) {
+                       writer.write("          </div>\n");
+                       inNormal = false;
+               }
+
+               switch (para.getType()) {
+               case BLANK:
+                       writer.write("          <div class='blank'></div>");
+                       break;
+               case BREAK:
+                       writer.write("          <hr/>");
+                       break;
+               case NORMAL:
+                       writer.write("          <span class='normal'>");
+                       break;
+               case QUOTE:
+                       writer.write("                  <div class='dialogue'>&mdash; ");
+                       break;
+               case IMAGE:
+                       // TODO
+                       writer.write("<a href='"
+                                       + StringUtils.xmlEscapeQuote(para.getContent()) + "'>"
+                                       + StringUtils.xmlEscape(para.getContent()) + "</a>");
+                       break;
+               }
+       }
+
+       @Override
+       protected void writeParagraphFooter(Paragraph para) throws IOException {
+               switch (para.getType()) {
+               case NORMAL:
+                       writer.write("</span>\n");
+                       break;
+               case QUOTE:
+                       writer.write("</div>\n");
+                       break;
+               default:
+                       writer.write("\n");
+                       break;
+               }
+       }
+
+       @Override
+       protected void writeTextLine(ParagraphType type, String line)
+                       throws IOException {
+               switch (type) {
+               case QUOTE:
+               case NORMAL:
+                       writer.write(decorateText(StringUtils.xmlEscape(line)));
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       @Override
+       protected String enbold(String word) {
+               return "<strong>" + word + "</strong>";
+       }
+
+       @Override
+       protected String italize(String word) {
+               return "<emph>" + word + "</emph>";
+       }
 }
diff --git a/src/be/nikiroo/fanfix/reader/LocalReader.java b/src/be/nikiroo/fanfix/reader/LocalReader.java
new file mode 100644 (file)
index 0000000..26f48f5
--- /dev/null
@@ -0,0 +1,92 @@
+package be.nikiroo.fanfix.reader;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.io.IOException;
+
+import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.Library;
+import be.nikiroo.fanfix.bundles.Config;
+import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.fanfix.output.BasicOutput.OutputType;
+import be.nikiroo.fanfix.supported.BasicSupport.SupportType;
+
+class LocalReader extends BasicReader {
+       private Library lib;
+
+       public LocalReader() throws IOException {
+               File dir = Instance.getReaderDir();
+               dir.mkdirs();
+               if (!dir.exists()) {
+                       throw new IOException(
+                                       "Cannote create cache directory for local reader: " + dir);
+               }
+
+               // TODO: can throw an exception, manage that (convert to IOEx ?)
+               OutputType text = OutputType.valueOfNullOkUC(Instance.getConfig()
+                               .getString(Config.LOCAL_READER_NON_IMAGES_DOCUMENT_TYPE));
+               if (text == null) {
+                       text = OutputType.HTML;
+               }
+
+               OutputType images = OutputType.valueOfNullOkUC(Instance.getConfig()
+                               .getString(Config.LOCAL_READER_IMAGES_DOCUMENT_TYPE));
+               if (images == null) {
+                       images = OutputType.CBZ;
+               }
+               //
+
+               lib = new Library(dir, text, images);
+       }
+
+       @Override
+       public void read() throws IOException {
+       }
+
+       @Override
+       public void read(int chapter) {
+       }
+
+       // return new luid
+       public String imprt(String luid) {
+               try {
+                       Story story = Instance.getLibrary().getStory(luid);
+                       story = lib.save(story);
+                       return story.getMeta().getLuid();
+               } catch (IOException e) {
+                       Instance.syserr(new IOException(
+                                       "Cannot import story from library to LocalReader library: "
+                                                       + luid, e));
+               }
+
+               return null;
+       }
+
+       public File getTarget(String luid) {
+               MetaData meta = lib.getInfo(luid);
+               File file = lib.getFile(luid);
+               if (file == null) {
+                       luid = imprt(luid);
+                       file = lib.getFile(luid);
+                       meta = lib.getInfo(luid);
+               }
+
+               return file;
+       }
+
+       @Override
+       public void start(SupportType type) {
+               final SupportType typeFinal = type;
+               EventQueue.invokeLater(new Runnable() {
+                       public void run() {
+                               new LocalReaderFrame(LocalReader.this, typeFinal)
+                                               .setVisible(true);
+                       }
+               });
+       }
+
+       public static void main(String[] args) throws IOException {
+               new LocalReader().start(null);
+       }
+}
diff --git a/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java b/src/be/nikiroo/fanfix/reader/LocalReaderFrame.java
new file mode 100644 (file)
index 0000000..f196f95
--- /dev/null
@@ -0,0 +1,55 @@
+package be.nikiroo.fanfix.reader;
+
+import java.awt.Desktop;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.List;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+
+import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.supported.BasicSupport.SupportType;
+
+class LocalReaderFrame extends JFrame {
+       private static final long serialVersionUID = 1L;
+       private LocalReader reader;
+
+       public LocalReaderFrame(LocalReader reader, SupportType type) {
+               super("HTML reader");
+
+               this.reader = reader;
+
+               setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+               setSize(800, 600);
+               setLayout(new FlowLayout());
+
+               // TODO: list all stories, list all TMP stories (and format?)
+
+               List<MetaData> stories = Instance.getLibrary().getList(type);
+               for (MetaData story : stories) {
+                       JButton button = new JButton(story.getTitle());
+                       final String luid = story.getLuid();
+                       button.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       try {
+                                               // TODO: config option (image, non image): TXT,
+                                               // custom-HTML, CBZ, EPUB
+                                               Desktop.getDesktop().browse(
+                                                               LocalReaderFrame.this.reader.getTarget(luid)
+                                                                               .toURI());
+                                       } catch (IOException e1) {
+                                               e1.printStackTrace();
+                                       }
+                               }
+                       });
+
+                       add(button);
+               }
+
+               setVisible(true);
+       }
+}
index 6d44c047d6dccf89907a4345e80b03a670c22ad5..ed7c4db1455bbff75c39c2b1fa95369ba8ba3968 100644 (file)
@@ -360,6 +360,7 @@ public abstract class BasicSupport {
                                        } finally {
                                                chapIn.close();
                                        }
+
                                        i++;
                                }
                        }
@@ -767,11 +768,22 @@ public abstract class BasicSupport {
                                line = openDoubleQuote + line + closeDoubleQuote;
                                newParas.add(new Paragraph(ParagraphType.QUOTE, line));
                        } else {
+                               char open = singleQ ? openQuote : openDoubleQuote;
                                char close = singleQ ? closeQuote : closeDoubleQuote;
-                               int posClose = line.indexOf(close, 1);
-                               int posDot = line.indexOf(".");
-                               while (posDot >= 0 && posDot < posClose) {
-                                       posDot = line.indexOf(".", posDot + 1);
+
+                               int posDot = -1;
+                               boolean inQuote = false;
+                               int i = 0;
+                               for (char car : line.toCharArray()) {
+                                       if (car == open) {
+                                               inQuote = true;
+                                       } else if (car == close) {
+                                               inQuote = false;
+                                       } else if (car == '.' && !inQuote) {
+                                               posDot = i;
+                                               break;
+                                       }
+                                       i++;
                                }
 
                                if (posDot >= 0) {