mirror of
https://github.com/MinimalBible/MinimalBible
synced 2024-11-21 23:48:18 -05:00
Refactor the tag parsing system
Much cleaner, I like this a whole lot more.
This commit is contained in:
parent
7f221ed863
commit
caf2227555
@ -2,7 +2,6 @@ package org.bspeice.minimalbible.activity.viewer;
|
|||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.lookup.VerseLookup;
|
|
||||||
import org.bspeice.minimalbible.service.manager.BookManager;
|
import org.bspeice.minimalbible.service.manager.BookManager;
|
||||||
import org.crosswire.jsword.book.Book;
|
import org.crosswire.jsword.book.Book;
|
||||||
|
|
||||||
@ -97,18 +96,11 @@ public class BibleViewerModules {
|
|||||||
return new BookManager();
|
return new BookManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
VerseLookup verseLookup(@Named("MainBook") Book b) {
|
|
||||||
return new VerseLookup(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Named("MainAdapter")
|
@Named("MainAdapter")
|
||||||
@Singleton
|
@Singleton
|
||||||
BookAdapter bookAdapter(@Named("MainBook") Book b, VerseLookup v,
|
BookAdapter bookAdapter(@Named("MainBook") Book b, BibleViewerPreferences prefs) {
|
||||||
BibleViewerPreferences prefs) {
|
return new BookAdapter(b, prefs);
|
||||||
return new BookAdapter(b, v, prefs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* see http://www.crosswire.org/wiki/Frontends:URI_Standard
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class Constants {
|
|
||||||
// Strings for URL protocols/URI schemes
|
|
||||||
public static final String SWORD_PROTOCOL = "sword"; //$NON-NLS-1$
|
|
||||||
public static final String BIBLE_PROTOCOL = "bible"; //$NON-NLS-1$
|
|
||||||
public static final String DICTIONARY_PROTOCOL = "dict"; //$NON-NLS-1$
|
|
||||||
public static final String GREEK_DEF_PROTOCOL = "gdef"; //$NON-NLS-1$
|
|
||||||
public static final String HEBREW_DEF_PROTOCOL = "hdef"; //$NON-NLS-1$
|
|
||||||
public static final String ALL_GREEK_OCCURRENCES_PROTOCOL = "allgoccur"; //$NON-NLS-1$
|
|
||||||
public static final String ALL_HEBREW_OCCURRENCES_PROTOCOL = "allhoccur"; //$NON-NLS-1$
|
|
||||||
public static final String ROBINSON_GREEK_MORPH_PROTOCOL = "robinson"; //$NON-NLS-1$
|
|
||||||
public static final String HEBREW_MORPH_PROTOCOL = "hmorph"; //$NON-NLS-1$
|
|
||||||
public static final String COMMENTARY_PROTOCOL = "comment"; //$NON-NLS-1$
|
|
||||||
|
|
||||||
public static class HTML {
|
|
||||||
public static final String NBSP = " ";
|
|
||||||
public static final String SPACE = " ";
|
|
||||||
public static final String BR = "<br />";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Info on a note or cross reference
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class Note {
|
|
||||||
|
|
||||||
public static final String SUMMARY = "summary";
|
|
||||||
;
|
|
||||||
public static final String DETAIL = "detail";
|
|
||||||
private static final String TAG = "Note";
|
|
||||||
private String noteRef;
|
|
||||||
private String noteText;
|
|
||||||
|
|
||||||
public Note(int verseNo, String noteRef, String noteText, NoteType noteType, String osisRef) {
|
|
||||||
super();
|
|
||||||
this.noteRef = noteRef;
|
|
||||||
this.noteText = noteText;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return noteRef + ":" + noteText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum NoteType {TYPE_GENERAL, TYPE_REFERENCE}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format;
|
|
||||||
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.HtmlTextWriter;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert OSIS input into Canonical text (used when creating search index)
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class OsisSaxHandler extends DefaultHandler {
|
|
||||||
|
|
||||||
// debugging
|
|
||||||
private boolean isDebugMode = false;
|
|
||||||
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
public OsisSaxHandler() {
|
|
||||||
writer = new HtmlTextWriter();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see java.lang.Object#toString()
|
|
||||||
*/
|
|
||||||
/* @Override */
|
|
||||||
public String toString() {
|
|
||||||
return writer.getHtml();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getName(String eName, String qName) {
|
|
||||||
if (eName != null && eName.length() > 0) {
|
|
||||||
return eName;
|
|
||||||
} else {
|
|
||||||
return qName; // not namespace-aware
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void write(String s) {
|
|
||||||
writer.write(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check the value of the specified attribute and return true if same as checkvalue
|
|
||||||
*
|
|
||||||
* @param attrs
|
|
||||||
* @param attrName
|
|
||||||
* @param checkValue
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected boolean isAttrValue(Attributes attrs, String attrName, String checkValue) {
|
|
||||||
if (attrs == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String value = attrs.getValue(attrName);
|
|
||||||
return checkValue.equals(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void debug(String name, Attributes attrs, boolean isStartTag) {
|
|
||||||
if (isDebugMode) {
|
|
||||||
write("*" + name);
|
|
||||||
if (attrs != null) {
|
|
||||||
for (int i = 0; i < attrs.getLength(); i++) {
|
|
||||||
String aName = attrs.getLocalName(i); // Attr name
|
|
||||||
if ("".equals(aName)) aName = attrs.getQName(i);
|
|
||||||
write(" ");
|
|
||||||
write(aName + "=\"" + attrs.getValue(i) + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write("*\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDebugMode(boolean isDebugMode) {
|
|
||||||
this.isDebugMode = isDebugMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void reset() {
|
|
||||||
writer.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public HtmlTextWriter getWriter() {
|
|
||||||
return writer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format;
|
|
||||||
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.TagHandlerHelper;
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import java.util.Stack;
|
|
||||||
/**
|
|
||||||
* Convert OSIS input into Canonical text (used when creating search index)
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class OsisToCanonicalTextSaxHandler extends OsisSaxHandler {
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private int currentVerseNo;
|
|
||||||
|
|
||||||
private Stack<CONTENT_STATE> writeContentStack = new Stack<CONTENT_STATE>();
|
|
||||||
|
|
||||||
public OsisToCanonicalTextSaxHandler() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startDocument() {
|
|
||||||
reset();
|
|
||||||
// default mode is to write
|
|
||||||
writeContentStack.push(CONTENT_STATE.WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*Called when the Parser Completes parsing the Current XML File.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void endDocument() {
|
|
||||||
// pop initial value
|
|
||||||
writeContentStack.pop();
|
|
||||||
assert (writeContentStack.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called when the starting of the Element is reached. For Example if we have Tag
|
|
||||||
* called <Title> ... </Title>, then this method is called when <Title> tag is
|
|
||||||
* Encountered while parsing the Current XML File. The AttributeList Parameter has
|
|
||||||
* the list of all Attributes declared for the Current Element in the XML File.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void startElement(String namespaceURI,
|
|
||||||
String sName, // simple name
|
|
||||||
String qName, // qualified name
|
|
||||||
Attributes attrs) {
|
|
||||||
String name = getName(sName, qName); // element name
|
|
||||||
|
|
||||||
debug(name, attrs, true);
|
|
||||||
|
|
||||||
// if encountering either a verse tag or if the current tag is marked as being canonical then turn on writing
|
|
||||||
if (isAttrValue(attrs, "canonical", "true")) {
|
|
||||||
writeContentStack.push(CONTENT_STATE.WRITE);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_VERSE)) {
|
|
||||||
if (attrs != null) {
|
|
||||||
currentVerseNo = TagHandlerHelper.osisIdToVerseNum(attrs.getValue("", OSISUtil.OSIS_ATTR_OSISID));
|
|
||||||
}
|
|
||||||
writeContentStack.push(CONTENT_STATE.WRITE);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_NOTE)) {
|
|
||||||
writeContentStack.push(CONTENT_STATE.IGNORE);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_TITLE)) {
|
|
||||||
writeContentStack.push(CONTENT_STATE.IGNORE);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_REFERENCE)) {
|
|
||||||
writeContentStack.push(CONTENT_STATE.IGNORE);
|
|
||||||
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_L) ||
|
|
||||||
name.equals(OSISUtil.OSIS_ELEMENT_LB) ||
|
|
||||||
name.equals(OSISUtil.OSIS_ELEMENT_P)) {
|
|
||||||
// these occur in Psalms to separate different paragraphs.
|
|
||||||
// A space is needed for TTS not to be confused by punctuation with a missing space like 'toward us,and the'
|
|
||||||
write(" ");
|
|
||||||
//if writing then continue. Also if ignoring then continue
|
|
||||||
writeContentStack.push(writeContentStack.peek());
|
|
||||||
} else {
|
|
||||||
// unknown tags rely on parent tag to determine if content is canonical e.g. the italic tag in the middle of canonical text
|
|
||||||
writeContentStack.push(writeContentStack.peek());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called when the Ending of the current Element is reached. For example in the
|
|
||||||
* above explanation, this method is called when </Title> tag is reached
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void endElement(String namespaceURI,
|
|
||||||
String sName, // simple name
|
|
||||||
String qName // qualified name
|
|
||||||
) {
|
|
||||||
String name = getName(sName, qName);
|
|
||||||
debug(name, null, false);
|
|
||||||
if (name.equals(OSISUtil.OSIS_ELEMENT_VERSE)) {
|
|
||||||
// A space is needed to separate one verse from the next, otherwise the 2 verses butt up against each other
|
|
||||||
// which looks bad and confuses TTS
|
|
||||||
write(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// now this tag has ended pop the write/ignore state for the parent tag
|
|
||||||
writeContentStack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle characters encountered in tags
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void characters(char buf[], int offset, int len) {
|
|
||||||
if (CONTENT_STATE.WRITE.equals(writeContentStack.peek())) {
|
|
||||||
String s = new String(buf, offset, len);
|
|
||||||
|
|
||||||
write(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeContent(boolean writeContent) {
|
|
||||||
if (writeContent) {
|
|
||||||
writeContentStack.push(CONTENT_STATE.WRITE);
|
|
||||||
} else {
|
|
||||||
writeContentStack.push(CONTENT_STATE.IGNORE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum CONTENT_STATE {WRITE, IGNORE}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlSaxHandler.VerseInfo;
|
|
||||||
import org.crosswire.jsword.passage.Verse;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display an img if the current verse has MyNote
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class BookmarkMarker {
|
|
||||||
|
|
||||||
private Set<Integer> bookmarkedVerses = new HashSet<Integer>();
|
|
||||||
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
|
|
||||||
private VerseInfo verseInfo;
|
|
||||||
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
private boolean bookmarkOpenTagWritten = false;
|
|
||||||
|
|
||||||
public BookmarkMarker(OsisToHtmlParameters parameters, VerseInfo verseInfo, HtmlTextWriter writer) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
this.verseInfo = verseInfo;
|
|
||||||
this.writer = writer;
|
|
||||||
|
|
||||||
// create hashset of verses to optimise verse note lookup
|
|
||||||
bookmarkedVerses.clear();
|
|
||||||
if (parameters.getVersesWithBookmarks() != null) {
|
|
||||||
for (Verse verse : parameters.getVersesWithBookmarks()) {
|
|
||||||
bookmarkedVerses.add(verse.getVerse());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* just after verse start tag
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
if (bookmarkedVerses != null && parameters.isShowBookmarks()) {
|
|
||||||
if (bookmarkedVerses.contains(verseInfo.currentVerseNo)) {
|
|
||||||
writer.write("<img src='file:///android_asset/images/GoldStar16x16.png' class='myNoteImg'/>");
|
|
||||||
// writer.write("<span class='bookmark'>");
|
|
||||||
bookmarkOpenTagWritten = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
if (bookmarkOpenTagWritten) {
|
|
||||||
// writer.write("</span>");
|
|
||||||
bookmarkOpenTagWritten = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle <figure src="imagefile.jpg" /> to display pictures
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class FigureHandler {
|
|
||||||
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
|
|
||||||
public FigureHandler(OsisToHtmlParameters parameters, HtmlTextWriter writer) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "figure";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
// Refer to Gen 3:14 in ESV for example use of type=x-indent
|
|
||||||
String src = attrs.getValue(OSISUtil.ATTRIBUTE_FIGURE_SRC);
|
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(src)) {
|
|
||||||
writer.write("<img src='" + parameters.getModuleBasePath() + "/" + src + "'/>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_ACROSTIC;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_BOLD;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_EMPHASIS;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_ILLUMINATED;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_ITALIC;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_LINETHROUGH;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_NORMAL;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_SMALL_CAPS;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_SUB;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_SUPER;
|
|
||||||
import static org.crosswire.jsword.book.OSISUtil.HI_UNDERLINE;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle hi element e.g. <hi type="italic">the child with his mother Mary</hi>
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class HiHandler {
|
|
||||||
|
|
||||||
// possible values of type attribute
|
|
||||||
private static final List<String> HI_TYPE_LIST = Arrays.asList(new String[]{HI_ACROSTIC, HI_BOLD, HI_EMPHASIS, HI_ILLUMINATED, HI_ITALIC, HI_LINETHROUGH, HI_NORMAL, HI_SMALL_CAPS, HI_SUB, HI_SUPER, HI_UNDERLINE});
|
|
||||||
|
|
||||||
private final static String DEFAULT = "bold";
|
|
||||||
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
public HiHandler(OsisToHtmlParameters parameters, HtmlTextWriter writer) {
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "hi";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
String type = attrs.getValue(OSISUtil.OSIS_ATTR_TYPE);
|
|
||||||
start(type, DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(String style, String defaultStyle) {
|
|
||||||
if (style == null || !HI_TYPE_LIST.contains(style)) {
|
|
||||||
style = defaultStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add any styles that are relevant - the tag name and the style attribute
|
|
||||||
String cssClasses = getTagName() + " hi_" + style;
|
|
||||||
|
|
||||||
// start span with CSS class of 'hi_*' e.g. hi_bold
|
|
||||||
writer.write("<span class=\'" + cssClasses + "\'>");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
writer.write("</span>");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write characters out to a StringBuilder - used while creating html for display
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's authors.
|
|
||||||
*/
|
|
||||||
public class HtmlTextWriter {
|
|
||||||
|
|
||||||
private StringBuilder writer;
|
|
||||||
|
|
||||||
private int dontWriteRequestCount = 0;
|
|
||||||
|
|
||||||
private int writeTempStoreRequestCount = 0;
|
|
||||||
private StringBuilder tempStore = new StringBuilder();
|
|
||||||
|
|
||||||
// allow insert at a certain position
|
|
||||||
private String overwrittenString = "";
|
|
||||||
|
|
||||||
public HtmlTextWriter() {
|
|
||||||
writer = new StringBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(String htmlText) {
|
|
||||||
if (dontWriteRequestCount > 0) {
|
|
||||||
// ignore all text
|
|
||||||
} else if (writeTempStoreRequestCount == 0) {
|
|
||||||
writer.append(htmlText);
|
|
||||||
} else {
|
|
||||||
tempStore.append(htmlText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* allow pre-verse headings
|
|
||||||
*/
|
|
||||||
public void beginInsertAt(int insertOffset) {
|
|
||||||
overwrittenString = writer.substring(insertOffset);
|
|
||||||
writer.delete(insertOffset, writer.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* finish inserting and restore overwritten tail of string
|
|
||||||
*/
|
|
||||||
public void finishInserting() {
|
|
||||||
writer.append(overwrittenString);
|
|
||||||
overwrittenString = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPosition() {
|
|
||||||
return writer.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAfter(int position) {
|
|
||||||
writer.delete(position, writer.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
writer.setLength(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeToTempStore() {
|
|
||||||
writeTempStoreRequestCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void finishWritingToTempStore() {
|
|
||||||
writeTempStoreRequestCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearTempStore() {
|
|
||||||
tempStore.delete(0, tempStore.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTempStoreString() {
|
|
||||||
return tempStore.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHtml() {
|
|
||||||
return writer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDontWrite(boolean dontWrite) {
|
|
||||||
if (dontWrite) {
|
|
||||||
dontWriteRequestCount++;
|
|
||||||
} else {
|
|
||||||
dontWriteRequestCount--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The lg or "line group" element is used to contain any group of poetic lines. Poetic lines are handled at the line level by And Bible, not line group
|
|
||||||
* so this class does nothing.
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class LGHandler {
|
|
||||||
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
|
|
||||||
private Stack<LGType> stack = new Stack<LGType>();
|
|
||||||
|
|
||||||
public LGHandler(OsisToHtmlParameters parameters, HtmlTextWriter writer) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "lg";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
// ignore this for now because it is untested
|
|
||||||
// LGType lgtype = LGType.IGNORE;
|
|
||||||
// if (TagHandlerHelper.isAttr(OSISUtil.OSIS_ATTR_SID, attrs) ||
|
|
||||||
// TagHandlerHelper.isAttr(OSISUtil.OSIS_ATTR_EID, attrs)) {
|
|
||||||
// lgtype = LGType.IGNORE;
|
|
||||||
// } else {
|
|
||||||
// // allow spacing around groups of poetry
|
|
||||||
// writer.write("<div class='lg'>");
|
|
||||||
// lgtype = LGType.DIV;
|
|
||||||
// }
|
|
||||||
// stack.push(lgtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
// LGType lgtype = stack.pop();
|
|
||||||
// if (LGType.DIV.equals(lgtype)) {
|
|
||||||
// writer.write("</div>");
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LGType {DIV, IGNORE}
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import static org.bspeice.minimalbible.service.format.Constants.HTML;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This can either signify a quote or Red Letter
|
|
||||||
* Example from ESV Prov 19:1
|
|
||||||
* <l sID="x9938"/>...<l eID="x9938" type="x-br"/><l sID="x9939" type="x-indent"/>..<l eID="x9939" type="x-br"/>
|
|
||||||
* <p/>
|
|
||||||
* Apparently quotation marks are not supposed to appear in the KJV (https://sites.google.com/site/kjvtoday/home/Features-of-the-KJV/quotation-marks)
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class LHandler {
|
|
||||||
|
|
||||||
private static String indent_html = HTML.NBSP + HTML.NBSP;
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
private Stack<LType> stack = new Stack<LType>();
|
|
||||||
|
|
||||||
public LHandler(OsisToHtmlParameters parameters, HtmlTextWriter writer) {
|
|
||||||
this.writer = writer;
|
|
||||||
int indentCharCount = 4; // TODO: Set a standard value for this
|
|
||||||
indent_html = StringUtils.repeat(HTML.NBSP, indentCharCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "l";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startL(Attributes attrs) {
|
|
||||||
// Refer to Gen 3:14 in ESV for example use of type=x-indent
|
|
||||||
String type = attrs.getValue(OSISUtil.OSIS_ATTR_TYPE);
|
|
||||||
int level = TagHandlerHelper.getAttribute(OSISUtil.OSIS_ATTR_LEVEL, attrs, 1);
|
|
||||||
// make numIndents default to zero
|
|
||||||
int numIndents = Math.max(0, level - 1);
|
|
||||||
|
|
||||||
LType ltype = LType.IGNORE;
|
|
||||||
if (StringUtils.isNotEmpty(type)) {
|
|
||||||
if (type.contains("indent")) {
|
|
||||||
// this tag is specifically for indenting so ensure there is an indent
|
|
||||||
numIndents = numIndents + 1;
|
|
||||||
writer.write(StringUtils.repeat(indent_html, numIndents));
|
|
||||||
ltype = LType.INDENT;
|
|
||||||
} else if (type.contains("br")) {
|
|
||||||
writer.write(HTML.BR);
|
|
||||||
ltype = LType.BR;
|
|
||||||
} else {
|
|
||||||
ltype = LType.IGNORE;
|
|
||||||
Log.d("LHandler", "Unknown <l> tag type:" + type);
|
|
||||||
}
|
|
||||||
} else if (TagHandlerHelper.isAttr(OSISUtil.OSIS_ATTR_SID, attrs)) {
|
|
||||||
writer.write(StringUtils.repeat(indent_html, numIndents));
|
|
||||||
ltype = LType.IGNORE;
|
|
||||||
} else if (TagHandlerHelper.isAttr(OSISUtil.OSIS_ATTR_EID, attrs)) {
|
|
||||||
// e.g. Isaiah 40:12
|
|
||||||
writer.write(HTML.BR);
|
|
||||||
ltype = LType.BR;
|
|
||||||
} else {
|
|
||||||
//simple <l>
|
|
||||||
writer.write(StringUtils.repeat(indent_html, numIndents));
|
|
||||||
ltype = LType.END_BR;
|
|
||||||
}
|
|
||||||
stack.push(ltype);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void endL() {
|
|
||||||
LType type = stack.pop();
|
|
||||||
if (LType.END_BR.equals(type)) {
|
|
||||||
writer.write(HTML.BR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LType {INDENT, BR, END_BR, IGNORE}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlSaxHandler.VerseInfo;
|
|
||||||
import org.crosswire.jsword.passage.Key;
|
|
||||||
import org.crosswire.jsword.passage.KeyUtil;
|
|
||||||
import org.crosswire.jsword.passage.Verse;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display an img if the current verse has MyNote
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class MyNoteMarker {
|
|
||||||
|
|
||||||
private Set<Integer> myNoteVerses = new HashSet<Integer>();
|
|
||||||
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
|
|
||||||
private VerseInfo verseInfo;
|
|
||||||
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
public MyNoteMarker(OsisToHtmlParameters parameters, VerseInfo verseInfo, HtmlTextWriter writer) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
this.verseInfo = verseInfo;
|
|
||||||
this.writer = writer;
|
|
||||||
|
|
||||||
// create hashmap of verses to optimise verse note lookup
|
|
||||||
myNoteVerses.clear();
|
|
||||||
if (parameters.getVersesWithNotes() != null) {
|
|
||||||
for (Key key : parameters.getVersesWithNotes()) {
|
|
||||||
Verse verse = KeyUtil.getVerse(key);
|
|
||||||
myNoteVerses.add(verse.getVerse());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* just after verse start tag
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
if (myNoteVerses != null && parameters.isShowMyNotes()) {
|
|
||||||
if (myNoteVerses.contains(verseInfo.currentVerseNo)) {
|
|
||||||
writer.write("<img src='file:///android_asset/images/pencil16x16.png' class='myNoteImg'/>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.bspeice.minimalbible.service.format.Note;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlSaxHandler.VerseInfo;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.bspeice.minimalbible.service.format.Note.NoteType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert OSIS tags into html tags
|
|
||||||
* <p/>
|
|
||||||
* Example OSIS tags from KJV Ps 119 v1 showing title, w, note
|
|
||||||
* <title canonical="true" subType="x-preverse" type="section">
|
|
||||||
* <foreign n="?">ALEPH.</foreign>
|
|
||||||
* </title>
|
|
||||||
* <w lemma="strong:H0835">Blessed</w> <transChange type="added">are</transChange> <w lemma="strong:H08549">the undefiled</w>
|
|
||||||
* ... <w lemma="strong:H01980" morph="strongMorph:TH8802">who walk</w>
|
|
||||||
* ... <w lemma="strong:H03068">of the <seg><divineName>Lord</divineName></seg></w>.
|
|
||||||
* <note type="study">undefiled: or, perfect, or, sincere</note>
|
|
||||||
* <p/>
|
|
||||||
* Example of notes cross references from ESV
|
|
||||||
* In the <note n="a" osisID="Gen.1.1!crossReference.a" osisRef="Gen.1.1" type="crossReference"><reference osisRef="Job.38.4-Job.38.7">Job 38:4-7</reference>; <reference osisRef="Ps.33.6">Ps. 33:6</reference>; <reference osisRef="Ps.136.5">136:5</reference>; <reference osisRef="Isa.42.5">Isa. 42:5</reference>; <reference osisRef="Isa.45.18">45:18</reference>; <reference osisRef="John.1.1-John.1.3">John 1:1-3</reference>; <reference osisRef="Acts.14.15">Acts 14:15</reference>; <reference osisRef="Acts.17.24">17:24</reference>; <reference osisRef="Col.1.16-Col.1.17">Col. 1:16, 17</reference>; <reference osisRef="Heb.1.10">Heb. 1:10</reference>; <reference osisRef="Heb.11.3">11:3</reference>; <reference osisRef="Rev.4.11">Rev. 4:11</reference></note>beginning
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class NoteHandler {
|
|
||||||
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
private VerseInfo verseInfo;
|
|
||||||
|
|
||||||
private int noteCount = 0;
|
|
||||||
|
|
||||||
//todo temporarily use a string but later switch to Map<int,String> of verse->note
|
|
||||||
private List<Note> notesList = new ArrayList<Note>();
|
|
||||||
private boolean isInNote = false;
|
|
||||||
private String currentNoteRef;
|
|
||||||
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
public NoteHandler(OsisToHtmlParameters osisToHtmlParameters, VerseInfo verseInfo, HtmlTextWriter theWriter) {
|
|
||||||
this.parameters = osisToHtmlParameters;
|
|
||||||
this.verseInfo = verseInfo;
|
|
||||||
this.writer = theWriter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startNote(Attributes attrs) {
|
|
||||||
isInNote = true;
|
|
||||||
currentNoteRef = getNoteRef(attrs);
|
|
||||||
writeNoteRef(currentNoteRef);
|
|
||||||
|
|
||||||
// prepare to fetch the actual note into the notes repo
|
|
||||||
writer.writeToTempStore();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called when the Ending of the current Element is reached. For example in the
|
|
||||||
* above explanation, this method is called when </Title> tag is reached
|
|
||||||
*/
|
|
||||||
public void endNote() {
|
|
||||||
String noteText = writer.getTempStoreString();
|
|
||||||
if (noteText.length() > 0) {
|
|
||||||
if (!StringUtils.containsOnly(noteText, "[];().,")) {
|
|
||||||
Note note = new Note(verseInfo.currentVerseNo, currentNoteRef, noteText, NoteType.TYPE_GENERAL, null);
|
|
||||||
notesList.add(note);
|
|
||||||
}
|
|
||||||
// and clear the buffer
|
|
||||||
writer.clearTempStore();
|
|
||||||
}
|
|
||||||
isInNote = false;
|
|
||||||
writer.finishWritingToTempStore();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* a reference is finished and now the note must be added
|
|
||||||
*/
|
|
||||||
public void addNoteForReference(String refText, String osisRef) {
|
|
||||||
// add teh html to show a note character in the (bible) text
|
|
||||||
// a few modules like HunUj have refs in the text but not surrounded by a Note tag (like esv) so need to add Note here
|
|
||||||
// special code to cope with HunUj problem
|
|
||||||
if (parameters.isAutoWrapUnwrappedRefsInNote() && !isInNote()) {
|
|
||||||
currentNoteRef = createNoteRef();
|
|
||||||
writeNoteRef(currentNoteRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
// record the note information to show if user requests to see notes for this verse
|
|
||||||
if (isInNote || parameters.isAutoWrapUnwrappedRefsInNote()) {
|
|
||||||
Note note = new Note(verseInfo.currentVerseNo, currentNoteRef, refText, NoteType.TYPE_REFERENCE, osisRef);
|
|
||||||
notesList.add(note);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* either use the 'n' attribute for the note ref or just get the next character in a list a-z
|
|
||||||
*
|
|
||||||
* @return a single char to use as a note ref
|
|
||||||
*/
|
|
||||||
private String getNoteRef(Attributes attrs) {
|
|
||||||
// if the ref is specified as an attribute then use that
|
|
||||||
String noteRef = attrs.getValue("n");
|
|
||||||
if (StringUtils.isEmpty(noteRef)) {
|
|
||||||
noteRef = createNoteRef();
|
|
||||||
}
|
|
||||||
return noteRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* either use the character passed in or get the next character in a list a-z
|
|
||||||
*
|
|
||||||
* @return a single char to use as a note ref
|
|
||||||
*/
|
|
||||||
private String createNoteRef() {
|
|
||||||
// else just get the next char
|
|
||||||
int inta = (int) 'a';
|
|
||||||
char nextNoteChar = (char) (inta + (noteCount++ % 26));
|
|
||||||
return String.valueOf(nextNoteChar);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* write noteref html to outputstream
|
|
||||||
*/
|
|
||||||
private void writeNoteRef(String noteRef) {
|
|
||||||
if (parameters.isShowNotes()) {
|
|
||||||
writer.write("<span class='noteRef'>" + noteRef + "</span> ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInNote() {
|
|
||||||
return isInNote;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Note> getNotesList() {
|
|
||||||
return notesList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,225 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.crosswire.jsword.passage.Key;
|
|
||||||
import org.crosswire.jsword.passage.KeyUtil;
|
|
||||||
import org.crosswire.jsword.passage.Verse;
|
|
||||||
import org.crosswire.jsword.versification.Versification;
|
|
||||||
import org.crosswire.jsword.versification.system.Versifications;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters passed into the Osis to HTML converter
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class OsisToHtmlParameters {
|
|
||||||
private String languageCode = "en";
|
|
||||||
private boolean isLeftToRight = true;
|
|
||||||
private boolean isShowTitles = true;
|
|
||||||
private boolean isShowVerseNumbers = false;
|
|
||||||
private boolean isVersePerline = false;
|
|
||||||
private boolean isShowMyNotes = false;
|
|
||||||
private boolean isShowBookmarks = false;
|
|
||||||
private boolean isShowNotes = false;
|
|
||||||
private boolean isAutoWrapUnwrappedRefsInNote = false;
|
|
||||||
// used as a basis if a reference has only chapter and no book
|
|
||||||
private Verse basisRef;
|
|
||||||
private Versification documentVersification;
|
|
||||||
private String font;
|
|
||||||
private String cssClassForCustomFont;
|
|
||||||
|
|
||||||
private boolean isShowStrongs = false;
|
|
||||||
private boolean isShowMorphology = false;
|
|
||||||
private boolean isRedLetter = false;
|
|
||||||
private String extraStylesheet;
|
|
||||||
private String extraFooter;
|
|
||||||
private boolean convertStrongsRefsToLinks;
|
|
||||||
private List<Verse> versesWithNotes;
|
|
||||||
private List<Verse> versesWithBookmarks;
|
|
||||||
private URI moduleBasePath;
|
|
||||||
|
|
||||||
public String getLanguageCode() {
|
|
||||||
return languageCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLanguageCode(String languageCode) {
|
|
||||||
this.languageCode = languageCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLeftToRight() {
|
|
||||||
return isLeftToRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLeftToRight(boolean isLeftToRight) {
|
|
||||||
this.isLeftToRight = isLeftToRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShowTitles() {
|
|
||||||
return isShowTitles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowTitles(boolean isShowTitles) {
|
|
||||||
this.isShowTitles = isShowTitles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShowVerseNumbers() {
|
|
||||||
return isShowVerseNumbers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowVerseNumbers(boolean isShowVerseNumbers) {
|
|
||||||
this.isShowVerseNumbers = isShowVerseNumbers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVersePerline() {
|
|
||||||
return isVersePerline;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersePerline(boolean isVersePerline) {
|
|
||||||
this.isVersePerline = isVersePerline;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShowMyNotes() {
|
|
||||||
return isShowMyNotes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowMyNotes(boolean isShowMyNotes) {
|
|
||||||
this.isShowMyNotes = isShowMyNotes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShowBookmarks() {
|
|
||||||
return isShowBookmarks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowBookmarks(boolean isShowBookmarks) {
|
|
||||||
this.isShowBookmarks = isShowBookmarks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShowNotes() {
|
|
||||||
return isShowNotes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowNotes(boolean isShowNotes) {
|
|
||||||
this.isShowNotes = isShowNotes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAutoWrapUnwrappedRefsInNote() {
|
|
||||||
return isAutoWrapUnwrappedRefsInNote;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAutoWrapUnwrappedRefsInNote(boolean isAutoWrapUnwrappedRefsInNote) {
|
|
||||||
this.isAutoWrapUnwrappedRefsInNote = isAutoWrapUnwrappedRefsInNote;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShowStrongs() {
|
|
||||||
return isShowStrongs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowStrongs(boolean isShowStrongs) {
|
|
||||||
this.isShowStrongs = isShowStrongs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShowMorphology() {
|
|
||||||
return isShowMorphology;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowMorphology(boolean isShowMorphology) {
|
|
||||||
this.isShowMorphology = isShowMorphology;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExtraStylesheet() {
|
|
||||||
return extraStylesheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExtraStylesheet(String extraStylesheet) {
|
|
||||||
this.extraStylesheet = extraStylesheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExtraFooter() {
|
|
||||||
return extraFooter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExtraFooter(String extraFooter) {
|
|
||||||
this.extraFooter = extraFooter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Verse getBasisRef() {
|
|
||||||
return basisRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBasisRef(Key basisRef) {
|
|
||||||
// KeyUtil always returns a Verse even if it is only Gen 1:1
|
|
||||||
this.basisRef = KeyUtil.getVerse(basisRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRedLetter() {
|
|
||||||
return isRedLetter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRedLetter(boolean isRedLetter) {
|
|
||||||
this.isRedLetter = isRedLetter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFont() {
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFont(String font) {
|
|
||||||
this.font = font;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCssClassForCustomFont() {
|
|
||||||
return cssClassForCustomFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCssClassForCustomFont(String cssClassForCustomFont) {
|
|
||||||
this.cssClassForCustomFont = cssClassForCustomFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConvertStrongsRefsToLinks() {
|
|
||||||
return convertStrongsRefsToLinks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConvertStrongsRefsToLinks(boolean convertStrongsRefsToLinks) {
|
|
||||||
this.convertStrongsRefsToLinks = convertStrongsRefsToLinks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Verse> getVersesWithNotes() {
|
|
||||||
return versesWithNotes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersesWithNotes(List<Verse> versesWithNotes) {
|
|
||||||
this.versesWithNotes = versesWithNotes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Verse> getVersesWithBookmarks() {
|
|
||||||
return versesWithBookmarks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersesWithBookmarks(List<Verse> versesWithBookmarks) {
|
|
||||||
this.versesWithBookmarks = versesWithBookmarks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public URI getModuleBasePath() {
|
|
||||||
return moduleBasePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setModuleBasePath(URI moduleBasePath) {
|
|
||||||
this.moduleBasePath = moduleBasePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Versification getDocumentVersification() {
|
|
||||||
if (documentVersification != null) {
|
|
||||||
return documentVersification;
|
|
||||||
} else {
|
|
||||||
return Versifications.instance().getVersification(Versifications.DEFAULT_V11N);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDocumentVersification(Versification documentVersification) {
|
|
||||||
this.documentVersification = documentVersification;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,325 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.bspeice.minimalbible.service.format.OsisSaxHandler;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.preprocessor.HebrewCharacterPreprocessor;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.preprocessor.TextPreprocessor;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.strongs.StrongsHandler;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.strongs.StrongsLinkCreator;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.tei.OrthHandler;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.tei.PronHandler;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.tei.RefHandler;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.tei.TEIUtil;
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import static org.bspeice.minimalbible.service.format.Constants.HTML;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert OSIS tags into html tags
|
|
||||||
* <p/>
|
|
||||||
* Example OSIS tags from KJV Ps 119 v1 showing title, w, note <title
|
|
||||||
* canonical="true" subType="x-preverse" type="section"> <foreign
|
|
||||||
* n="?">ALEPH.</foreign> </title> <w lemma="strong:H0835">Blessed</w>
|
|
||||||
* <transChange type="added">are</transChange> <w lemma="strong:H08549">the
|
|
||||||
* undefiled</w> ... <w lemma="strong:H01980" morph="strongMorph:TH8802">who
|
|
||||||
* walk</w> ... <w lemma="strong:H03068">of the
|
|
||||||
* <seg><divineName>Lord</divineName></seg></w>. <note type="study">undefiled:
|
|
||||||
* or, perfect, or, sincere</note>
|
|
||||||
* <p/>
|
|
||||||
* Example of notes cross references from ESV In the <note n="a"
|
|
||||||
* osisID="Gen.1.1!crossReference.a" osisRef="Gen.1.1"
|
|
||||||
* type="crossReference"><reference osisRef="Job.38.4-Job.38.7">Job
|
|
||||||
* 38:4-7</reference>; <reference osisRef="Ps.33.6">Ps. 33:6</reference>;
|
|
||||||
* <reference osisRef="Ps.136.5">136:5</reference>; <reference
|
|
||||||
* osisRef="Isa.42.5">Isa. 42:5</reference>; <reference
|
|
||||||
* osisRef="Isa.45.18">45:18</reference>; <reference
|
|
||||||
* osisRef="John.1.1-John.1.3">John 1:1-3</reference>; <reference
|
|
||||||
* osisRef="Acts.14.15">Acts 14:15</reference>; <reference
|
|
||||||
* osisRef="Acts.17.24">17:24</reference>; <reference
|
|
||||||
* osisRef="Col.1.16-Col.1.17">Col. 1:16, 17</reference>; <reference
|
|
||||||
* osisRef="Heb.1.10">Heb. 1:10</reference>; <reference
|
|
||||||
* osisRef="Heb.11.3">11:3</reference>; <reference osisRef="Rev.4.11">Rev.
|
|
||||||
* 4:11</reference></note>beginning
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class OsisToHtmlSaxHandler extends OsisSaxHandler {
|
|
||||||
|
|
||||||
private static final String HEBREW_LANGUAGE_CODE = "he";
|
|
||||||
// properties
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
// tag handlers for the different OSIS tags
|
|
||||||
private VerseHandler verseHandler;
|
|
||||||
private MyNoteMarker myNoteMarker;
|
|
||||||
private BookmarkMarker bookmarkMarker;
|
|
||||||
private NoteHandler noteHandler;
|
|
||||||
private ReferenceHandler referenceHandler;
|
|
||||||
private RefHandler refHandler;
|
|
||||||
private TitleHandler titleHandler;
|
|
||||||
private QHandler qHandler;
|
|
||||||
private LGHandler lgHandler;
|
|
||||||
private LHandler lHandler;
|
|
||||||
private HiHandler hiHandler;
|
|
||||||
private OrthHandler orthHandler;
|
|
||||||
private PronHandler pronHandler;
|
|
||||||
private StrongsHandler strongsHandler;
|
|
||||||
private FigureHandler figureHandler;
|
|
||||||
// processor for the tag content
|
|
||||||
private TextPreprocessor textPreprocessor;
|
|
||||||
// internal logic
|
|
||||||
private VerseInfo verseInfo = new VerseInfo();
|
|
||||||
private boolean isAnyTextWritten = false;
|
|
||||||
|
|
||||||
public OsisToHtmlSaxHandler(OsisToHtmlParameters parameters) {
|
|
||||||
super();
|
|
||||||
this.parameters = parameters;
|
|
||||||
verseHandler = new VerseHandler(parameters, verseInfo, getWriter());
|
|
||||||
myNoteMarker = new MyNoteMarker(parameters, verseInfo, getWriter());
|
|
||||||
bookmarkMarker = new BookmarkMarker(parameters, verseInfo, getWriter());
|
|
||||||
noteHandler = new NoteHandler(parameters, verseInfo, getWriter());
|
|
||||||
referenceHandler = new ReferenceHandler(parameters, noteHandler, getWriter());
|
|
||||||
refHandler = new RefHandler(parameters, noteHandler, getWriter());
|
|
||||||
titleHandler = new TitleHandler(parameters, verseInfo, getWriter());
|
|
||||||
qHandler = new QHandler(parameters, getWriter());
|
|
||||||
hiHandler = new HiHandler(parameters, getWriter());
|
|
||||||
orthHandler = new OrthHandler(parameters, getWriter());
|
|
||||||
pronHandler = new PronHandler(parameters, getWriter());
|
|
||||||
lgHandler = new LGHandler(parameters, getWriter());
|
|
||||||
lHandler = new LHandler(parameters, getWriter());
|
|
||||||
strongsHandler = new StrongsHandler(parameters, getWriter());
|
|
||||||
figureHandler = new FigureHandler(parameters, getWriter());
|
|
||||||
|
|
||||||
//TODO at the moment we can only have a single TextPreprocesor, need to chain them and maybe make the writer a TextPreprocessor and put it at the end of the chain
|
|
||||||
if (HEBREW_LANGUAGE_CODE.equals(parameters.getLanguageCode())) {
|
|
||||||
textPreprocessor = new HebrewCharacterPreprocessor();
|
|
||||||
} else if (parameters.isConvertStrongsRefsToLinks()) {
|
|
||||||
textPreprocessor = new StrongsLinkCreator();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startDocument() {
|
|
||||||
// force rtl for rtl languages - rtl support on Android is poor but
|
|
||||||
// forcing it seems to help occasionally
|
|
||||||
write("<p>");
|
|
||||||
if (!parameters.isLeftToRight()) {
|
|
||||||
write("<span dir='rtl'>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called when the Parser Completes parsing the Current XML File.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void endDocument() {
|
|
||||||
|
|
||||||
// close last verse
|
|
||||||
if (parameters.isVersePerline()) {
|
|
||||||
//close last verse
|
|
||||||
if (verseInfo.currentVerseNo > 1) {
|
|
||||||
write("</div>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add optional footer e.g. Strongs show all occurrences link
|
|
||||||
if (StringUtils.isNotEmpty(parameters.getExtraFooter())) {
|
|
||||||
write(parameters.getExtraFooter());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parameters.isLeftToRight()) {
|
|
||||||
write("</span>");
|
|
||||||
}
|
|
||||||
write("</p>");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called when the starting of the Element is reached. For Example if we
|
|
||||||
* have Tag called <Title> ... </Title>, then this method is called when
|
|
||||||
* <Title> tag is Encountered while parsing the Current XML File. The
|
|
||||||
* AttributeList Parameter has the list of all Attributes declared for the
|
|
||||||
* Current Element in the XML File.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void startElement(String namespaceURI,
|
|
||||||
String sName, // simple name
|
|
||||||
String qName, // qualified name
|
|
||||||
Attributes attrs) {
|
|
||||||
String name = getName(sName, qName); // element name
|
|
||||||
|
|
||||||
debug(name, attrs, true);
|
|
||||||
|
|
||||||
if (name.equals(OSISUtil.OSIS_ELEMENT_VERSE)) {
|
|
||||||
verseHandler.startAndUpdateVerse(attrs);
|
|
||||||
bookmarkMarker.start();
|
|
||||||
myNoteMarker.start();
|
|
||||||
// record that we are into a new verse
|
|
||||||
verseInfo.isTextSinceVerse = false;
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_TITLE)) {
|
|
||||||
titleHandler.start(attrs);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_NOTE)) {
|
|
||||||
noteHandler.startNote(attrs);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_REFERENCE)) {
|
|
||||||
referenceHandler.start(attrs);
|
|
||||||
} else if (name.equals(TEIUtil.TEI_ELEMENT_REF)) {
|
|
||||||
refHandler.start(attrs);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_LB)) {
|
|
||||||
if (isAnyTextWritten) {
|
|
||||||
write(HTML.BR);
|
|
||||||
}
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_LG)) {
|
|
||||||
lgHandler.start(attrs);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_L)) {
|
|
||||||
lHandler.startL(attrs);
|
|
||||||
} else if (name.equals("div")) {
|
|
||||||
String type = attrs.getValue("type");
|
|
||||||
if ("paragraph".equals(type)) {
|
|
||||||
// ignore sID start paragraph sID because it often comes after the verse no and causes a gap between verse no verse text
|
|
||||||
String eID = attrs.getValue("eID");
|
|
||||||
if (eID != null && isAnyTextWritten) {
|
|
||||||
write("<p />");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_P)) {
|
|
||||||
write("<p>");
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_Q)) {
|
|
||||||
qHandler.start(attrs);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_HI)) {
|
|
||||||
hiHandler.start(attrs);
|
|
||||||
} else if (name.equals(TEIUtil.TEI_ELEMENT_ORTH)) {
|
|
||||||
orthHandler.start(attrs);
|
|
||||||
} else if (name.equals(TEIUtil.TEI_ELEMENT_PRON)) {
|
|
||||||
pronHandler.start(attrs);
|
|
||||||
} else if (name.equals("milestone")) {
|
|
||||||
String type = attrs.getValue(OSISUtil.OSIS_ATTR_TYPE);
|
|
||||||
if (StringUtils.isNotEmpty(type)) {
|
|
||||||
if (type.equals("line") || type.equals("x-p")) {
|
|
||||||
if (isAnyTextWritten) {
|
|
||||||
//e.g. NETtext Mt 4:14; KJV Gen 1:6
|
|
||||||
writeOptionallyBeforeVerse(HTML.BR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (name.equals("transChange")) {
|
|
||||||
write("<span class='transChange'>");
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_W)) {
|
|
||||||
strongsHandler.start(attrs);
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_FIGURE)) {
|
|
||||||
figureHandler.start(attrs);
|
|
||||||
} else {
|
|
||||||
// TODO: Cleanup
|
|
||||||
Log.i("OsisToHtmlSaxHandler", "Verse " + verseInfo.currentVerseNo + " unsupported OSIS tag:" + name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called when the Ending of the current Element is reached. For example in
|
|
||||||
* the above explanation, this method is called when </Title> tag is reached
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void endElement(String namespaceURI, String sName, // simple name
|
|
||||||
String qName // qualified name
|
|
||||||
) {
|
|
||||||
String name = getName(sName, qName);
|
|
||||||
|
|
||||||
debug(name, null, false);
|
|
||||||
|
|
||||||
if (name.equals(OSISUtil.OSIS_ELEMENT_TITLE)) {
|
|
||||||
titleHandler.end();
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_VERSE)) {
|
|
||||||
myNoteMarker.end();
|
|
||||||
bookmarkMarker.end();
|
|
||||||
verseHandler.end();
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_NOTE)) {
|
|
||||||
noteHandler.endNote();
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_REFERENCE)) {
|
|
||||||
referenceHandler.end();
|
|
||||||
} else if (name.equals(TEIUtil.TEI_ELEMENT_REF)) {
|
|
||||||
refHandler.end();
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_LG)) {
|
|
||||||
lgHandler.end();
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_L)) {
|
|
||||||
lHandler.endL();
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_P)) {
|
|
||||||
write("</p>");
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_Q)) {
|
|
||||||
// end quotation, but <q /> tag is a marker and contains no content
|
|
||||||
// so <q /> will appear at beginning and end of speech
|
|
||||||
qHandler.end();
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_HI)) {
|
|
||||||
hiHandler.end();
|
|
||||||
} else if (name.equals(TEIUtil.TEI_ELEMENT_ORTH)) {
|
|
||||||
orthHandler.end();
|
|
||||||
} else if (name.equals(TEIUtil.TEI_ELEMENT_PRON)) {
|
|
||||||
pronHandler.end();
|
|
||||||
} else if (name.equals("transChange")) {
|
|
||||||
write("</span>");
|
|
||||||
} else if (name.equals(OSISUtil.OSIS_ELEMENT_W)) {
|
|
||||||
strongsHandler.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* While Parsing the XML file, if extra characters like space or enter
|
|
||||||
* Character are encountered then this method is called. If you don't want
|
|
||||||
* to do anything special with these characters, then you can normally leave
|
|
||||||
* this method blank.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void characters(char buf[], int offset, int len) {
|
|
||||||
String s = new String(buf, offset, len);
|
|
||||||
|
|
||||||
// record that we are now beyond the verse, but do it quickly so as not to slow down parsing
|
|
||||||
verseInfo.isTextSinceVerse = verseInfo.isTextSinceVerse ||
|
|
||||||
len > 2 ||
|
|
||||||
StringUtils.isNotBlank(s);
|
|
||||||
isAnyTextWritten = isAnyTextWritten || verseInfo.isTextSinceVerse;
|
|
||||||
|
|
||||||
if (textPreprocessor != null) {
|
|
||||||
s = textPreprocessor.process(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
write(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* allow line breaks and titles to be moved before verse number
|
|
||||||
*/
|
|
||||||
protected void writeOptionallyBeforeVerse(String s) {
|
|
||||||
boolean writeBeforeVerse = !verseInfo.isTextSinceVerse;
|
|
||||||
if (writeBeforeVerse) {
|
|
||||||
getWriter().beginInsertAt(verseInfo.positionToInsertBeforeVerse);
|
|
||||||
}
|
|
||||||
getWriter().write(s);
|
|
||||||
if (writeBeforeVerse) {
|
|
||||||
getWriter().finishInserting();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In the XML File if the parser encounters a Processing Instruction which
|
|
||||||
* is declared like this <?ProgramName:BooksLib
|
|
||||||
* QUERY="author, isbn, price"?> Then this method is called where Target
|
|
||||||
* parameter will have "ProgramName:BooksLib" and data parameter will have
|
|
||||||
* QUERY="author, isbn, price". You can invoke a External Program from this
|
|
||||||
* Method if required.
|
|
||||||
*/
|
|
||||||
public void processingInstruction(String target, String data) {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDirection() {
|
|
||||||
return parameters.isLeftToRight() ? "ltr" : "rtl";
|
|
||||||
}
|
|
||||||
|
|
||||||
class VerseInfo {
|
|
||||||
int currentVerseNo;
|
|
||||||
int positionToInsertBeforeVerse;
|
|
||||||
boolean isTextSinceVerse = false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This can either signify a quote or Red Letter
|
|
||||||
* Example from ESV
|
|
||||||
* But he answered them, <q marker="" who="Jesus"><q level="1" marker="<EFBFBD>" sID="40024002.1"/>You see all these
|
|
||||||
* Example from KJV
|
|
||||||
* said ... unto them, <q who="Jesus">...See ye
|
|
||||||
* <p/>
|
|
||||||
* Apparently quotation marks are not supposed to appear in the KJV (https://sites.google.com/site/kjvtoday/home/Features-of-the-KJV/quotation-marks)
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class QHandler {
|
|
||||||
|
|
||||||
private static final String MARKER = "marker";
|
|
||||||
private static final String HTML_QUOTE_ENTITY = """;
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
;
|
|
||||||
// quotes can be embedded so maintain a stack of info about each quote to be used when closing quote
|
|
||||||
private Stack<QuoteInfo> stack = new Stack<QuoteInfo>();
|
|
||||||
|
|
||||||
public QHandler(OsisToHtmlParameters parameters, HtmlTextWriter writer) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "q";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
QuoteInfo quoteInfo = new QuoteInfo();
|
|
||||||
|
|
||||||
String who = attrs.getValue(OSISUtil.ATTRIBUTE_Q_WHO);
|
|
||||||
boolean isWho = who != null;
|
|
||||||
|
|
||||||
quoteInfo.isMilestone = TagHandlerHelper.isAttr(OSISUtil.OSIS_ATTR_SID, attrs) || TagHandlerHelper.isAttr(OSISUtil.OSIS_ATTR_EID, attrs);
|
|
||||||
|
|
||||||
// Jesus -> no default quote
|
|
||||||
quoteInfo.marker = TagHandlerHelper.getAttribute(MARKER, attrs, isWho ? "" : HTML_QUOTE_ENTITY);
|
|
||||||
|
|
||||||
quoteInfo.isRedLetter = parameters.isRedLetter() && "Jesus".equals(who);
|
|
||||||
|
|
||||||
// apply the above logic
|
|
||||||
writer.write(quoteInfo.marker);
|
|
||||||
if (quoteInfo.isRedLetter) {
|
|
||||||
writer.write("<span class='redLetter'>");
|
|
||||||
}
|
|
||||||
|
|
||||||
// and save the info for the closing tag
|
|
||||||
stack.push(quoteInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
QuoteInfo quoteInfo = stack.pop();
|
|
||||||
|
|
||||||
// Jesus words
|
|
||||||
if (quoteInfo.isRedLetter) {
|
|
||||||
writer.write("</span>");
|
|
||||||
}
|
|
||||||
|
|
||||||
// milestone opening and closing tags are doubled up so ensure not double quotes
|
|
||||||
if (!quoteInfo.isMilestone) {
|
|
||||||
writer.write(quoteInfo.marker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum QType {quote, redLetter}
|
|
||||||
|
|
||||||
private static class QuoteInfo {
|
|
||||||
private boolean isMilestone;
|
|
||||||
private boolean isRedLetter;
|
|
||||||
private String marker = HTML_QUOTE_ENTITY;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,157 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.crosswire.jsword.passage.Key;
|
|
||||||
import org.crosswire.jsword.passage.Passage;
|
|
||||||
import org.crosswire.jsword.passage.PassageKeyFactory;
|
|
||||||
import org.crosswire.jsword.passage.RestrictionType;
|
|
||||||
import org.crosswire.jsword.passage.VerseRange;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import static org.bspeice.minimalbible.service.format.Constants.BIBLE_PROTOCOL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert OSIS tags into html tags
|
|
||||||
* <p/>
|
|
||||||
* Example OSIS tags from KJV Ps 119 v1 showing title, w, note
|
|
||||||
* <title canonical="true" subType="x-preverse" type="section">
|
|
||||||
* <foreign n="?">ALEPH.</foreign>
|
|
||||||
* </title>
|
|
||||||
* <w lemma="strong:H0835">Blessed</w> <transChange type="added">are</transChange> <w lemma="strong:H08549">the undefiled</w>
|
|
||||||
* ... <w lemma="strong:H01980" morph="strongMorph:TH8802">who walk</w>
|
|
||||||
* ... <w lemma="strong:H03068">of the <seg><divineName>Lord</divineName></seg></w>.
|
|
||||||
* <note type="study">undefiled: or, perfect, or, sincere</note>
|
|
||||||
* <p/>
|
|
||||||
* Example of notes cross references from ESV
|
|
||||||
* In the <note n="a" osisID="Gen.1.1!crossReference.a" osisRef="Gen.1.1" type="crossReference"><reference osisRef="Job.38.4-Job.38.7">Job 38:4-7</reference>; <reference osisRef="Ps.33.6">Ps. 33:6</reference>; <reference osisRef="Ps.136.5">136:5</reference>; <reference osisRef="Isa.42.5">Isa. 42:5</reference>; <reference osisRef="Isa.45.18">45:18</reference>; <reference osisRef="John.1.1-John.1.3">John 1:1-3</reference>; <reference osisRef="Acts.14.15">Acts 14:15</reference>; <reference osisRef="Acts.17.24">17:24</reference>; <reference osisRef="Col.1.16-Col.1.17">Col. 1:16, 17</reference>; <reference osisRef="Heb.1.10">Heb. 1:10</reference>; <reference osisRef="Heb.11.3">11:3</reference>; <reference osisRef="Rev.4.11">Rev. 4:11</reference></note>beginning
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class ReferenceHandler {
|
|
||||||
|
|
||||||
private final String TAG = "ReferenceHandler";
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
private String currentRefOsisRef;
|
|
||||||
private NoteHandler noteHandler;
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
public ReferenceHandler(OsisToHtmlParameters osisToHtmlParameters, NoteHandler noteHandler, HtmlTextWriter theWriter) {
|
|
||||||
this.parameters = osisToHtmlParameters;
|
|
||||||
this.noteHandler = noteHandler;
|
|
||||||
this.writer = theWriter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
// store the osisRef attribute for use with the note
|
|
||||||
String target = attrs.getValue(OSISUtil.OSIS_ATTR_REF);
|
|
||||||
start(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void start(String target) {
|
|
||||||
// don't need to do anything until closing reference tag except..
|
|
||||||
// delete separators like ';' that sometimes occur between reference tags
|
|
||||||
writer.clearTempStore();
|
|
||||||
writer.writeToTempStore();
|
|
||||||
// store the osisRef attribute for use with the note
|
|
||||||
this.currentRefOsisRef = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
writer.finishWritingToTempStore();
|
|
||||||
|
|
||||||
if (noteHandler.isInNote() || parameters.isAutoWrapUnwrappedRefsInNote()) {
|
|
||||||
noteHandler.addNoteForReference(writer.getTempStoreString(), currentRefOsisRef);
|
|
||||||
} else {
|
|
||||||
String refText = writer.getTempStoreString();
|
|
||||||
writer.write(getReferenceTag(currentRefOsisRef, refText));
|
|
||||||
}
|
|
||||||
|
|
||||||
// and clear the buffer
|
|
||||||
writer.clearTempStore();
|
|
||||||
currentRefOsisRef = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a link tag from an OSISref and the content of the tag
|
|
||||||
*/
|
|
||||||
private String getReferenceTag(String reference, String content) {
|
|
||||||
Log.d(TAG, "Ref:" + reference + " Content:" + content);
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
try {
|
|
||||||
|
|
||||||
//JSword does not know the basis (default book) so prepend it if it looks like JSword failed to work it out
|
|
||||||
//We only need to worry about the first ref because JSword uses the first ref as the basis for the subsequent refs
|
|
||||||
// if content starts with a number and is not followed directly by an alpha char e.g. 1Sa
|
|
||||||
if (reference == null && content != null && content.length() > 0 && StringUtils.isNumeric(content.subSequence(0, 1)) &&
|
|
||||||
(content.length() < 2 || !StringUtils.isAlphaSpace(content.subSequence(1, 2)))) {
|
|
||||||
|
|
||||||
// maybe should use VerseRangeFactory.fromstring(orig, basis)
|
|
||||||
// this check for a colon to see if the first ref is verse:chap is not perfect but it will do until JSword adds a fix
|
|
||||||
int firstColonPos = content.indexOf(":");
|
|
||||||
boolean isVerseAndChapter = firstColonPos > 0 && firstColonPos < 4;
|
|
||||||
if (isVerseAndChapter) {
|
|
||||||
reference = parameters.getBasisRef().getBook().getOSIS() + " " + content;
|
|
||||||
} else {
|
|
||||||
reference = parameters.getBasisRef().getBook().getOSIS() + " " + parameters.getBasisRef().getChapter() + ":" + content;
|
|
||||||
}
|
|
||||||
Log.d(TAG, "Patched reference:" + reference);
|
|
||||||
} else if (reference == null) {
|
|
||||||
reference = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert urns of type book:key to sword://book/key to simplify urn parsing (1 fewer case to check for).
|
|
||||||
// Avoid urls of type 'matt 3:14' by excludng urns with a space
|
|
||||||
if (reference.contains(":") && !reference.contains(" ") && !reference.startsWith("sword://")) {
|
|
||||||
reference = "sword://" + reference.replace(":", "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isFullSwordUrn = reference.contains("/") && reference.contains(":");
|
|
||||||
if (isFullSwordUrn) {
|
|
||||||
// e.g. sword://StrongsRealGreek/01909
|
|
||||||
// don't play with the reference - just assume it is correct
|
|
||||||
result.append("<a href='").append(reference).append("'>");
|
|
||||||
result.append(content);
|
|
||||||
result.append("</a>");
|
|
||||||
} else {
|
|
||||||
Passage ref = (Passage) PassageKeyFactory.instance().getKey(parameters.getDocumentVersification(), reference);
|
|
||||||
boolean isSingleVerse = ref.countVerses() == 1;
|
|
||||||
boolean isSimpleContent = content.length() < 3 && content.length() > 0;
|
|
||||||
Iterator<VerseRange> it = ref.rangeIterator(RestrictionType.CHAPTER);
|
|
||||||
|
|
||||||
if (isSingleVerse && isSimpleContent) {
|
|
||||||
// simple verse no e.g. 1 or 2 preceding the actual verse in TSK
|
|
||||||
result.append("<a href='").append(BIBLE_PROTOCOL).append(":").append(it.next().getOsisRef()).append("'>");
|
|
||||||
result.append(content);
|
|
||||||
result.append("</a>");
|
|
||||||
} else {
|
|
||||||
// multiple complex references
|
|
||||||
boolean isFirst = true;
|
|
||||||
while (it.hasNext()) {
|
|
||||||
Key key = it.next();
|
|
||||||
if (!isFirst) {
|
|
||||||
result.append(" ");
|
|
||||||
}
|
|
||||||
result.append("<a href='").append(BIBLE_PROTOCOL).append(":").append(key.iterator().next().getOsisRef()).append("'>");
|
|
||||||
result.append(key);
|
|
||||||
result.append("</a>");
|
|
||||||
isFirst = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Error parsing OSIS reference:" + reference);
|
|
||||||
// just return the content with no html markup
|
|
||||||
result.append(content);
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class TagHandlerHelper {
|
|
||||||
|
|
||||||
private static final String TAG = "TagHandlerHelper";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* support defaultvalue with attribute fetch
|
|
||||||
*/
|
|
||||||
public static String getAttribute(String attributeName, Attributes attrs, String defaultValue) {
|
|
||||||
String attrValue = attrs.getValue(attributeName);
|
|
||||||
if (attrValue != null) {
|
|
||||||
return attrValue;
|
|
||||||
} else {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* support defaultvalue with attribute fetch
|
|
||||||
*/
|
|
||||||
public static int getAttribute(String attributeName, Attributes attrs, int defaultValue) {
|
|
||||||
int retval = defaultValue;
|
|
||||||
try {
|
|
||||||
String attrValue = attrs.getValue(attributeName);
|
|
||||||
if (attrValue != null) {
|
|
||||||
retval = Integer.parseInt(attrValue);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.w(TAG, "Non numeric but expected integer for " + attributeName);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* see if an attribute exists and has a value
|
|
||||||
*
|
|
||||||
* @param attributeName
|
|
||||||
* @param attrs
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean isAttr(String attributeName, Attributes attrs) {
|
|
||||||
String attrValue = attrs.getValue(attributeName);
|
|
||||||
return StringUtils.isNotEmpty(attrValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return verse from osis id of format book.chap.verse
|
|
||||||
*
|
|
||||||
* @param osisID osis Id
|
|
||||||
* @return verse number
|
|
||||||
*/
|
|
||||||
public static int osisIdToVerseNum(String osisID) {
|
|
||||||
/* You have to use "\\.", the first backslash is interpreted as an escape by the
|
|
||||||
Java compiler, so you have to use two to get a String that contains one
|
|
||||||
backslash and a dot, which is what you want the regexp engine to see.*/
|
|
||||||
if (osisID != null) {
|
|
||||||
String[] parts = osisID.split("\\.");
|
|
||||||
if (parts.length > 1) {
|
|
||||||
String verse = parts[parts.length - 1];
|
|
||||||
return Integer.valueOf(verse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void printAttributes(Attributes attrs) {
|
|
||||||
for (int i = 0; i < attrs.getLength(); i++) {
|
|
||||||
Log.d(TAG, attrs.getLocalName(i) + ":" + attrs.getValue(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlSaxHandler.VerseInfo;
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This can either signify a quote or Red Letter
|
|
||||||
* Example
|
|
||||||
* ESV section heading <title subType="x-preverse" type="section">
|
|
||||||
* ESV canonical heading<title canonical="true" subType="x-preverse" type="section">To the choirmaster. Of David,
|
|
||||||
* WEB when formatted with JSword seems to have type="x-gen"
|
|
||||||
* <p/>
|
|
||||||
* Apparently quotation marks are not supposed to appear in the KJV (https://sites.google.com/site/kjvtoday/home/Features-of-the-KJV/quotation-marks)
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class TitleHandler {
|
|
||||||
|
|
||||||
private static final String PREVERSE = "preverse"; // the full string is 'x-preverse' but we just check for contains for extra tolerance
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
private VerseInfo verseInfo;
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
private boolean isShowTitle;
|
|
||||||
private boolean isMoveBeforeVerse;
|
|
||||||
|
|
||||||
public TitleHandler(OsisToHtmlParameters parameters, VerseInfo verseInfo, HtmlTextWriter writer) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
this.verseInfo = verseInfo;
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return OSISUtil.OSIS_ELEMENT_TITLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
//JSword adds the chapter no at the top but hide this because the chapter is in the And Bible header
|
|
||||||
boolean addedByJSword = attrs.getLength() == 1 && OSISUtil.GENERATED_CONTENT.equals(attrs.getValue(OSISUtil.OSIS_ATTR_TYPE));
|
|
||||||
// otherwise show if user wants Titles or the title is canonical
|
|
||||||
isShowTitle = !addedByJSword &&
|
|
||||||
(parameters.isShowTitles() ||
|
|
||||||
"true".equalsIgnoreCase(attrs.getValue(OSISUtil.OSIS_ATTR_CANONICAL)));
|
|
||||||
|
|
||||||
if (isShowTitle) {
|
|
||||||
// ESV has subType butNETtext has lower case subtype so concatenate both and search with contains()
|
|
||||||
String subtype = attrs.getValue(OSISUtil.OSIS_ATTR_SUBTYPE) + attrs.getValue(OSISUtil.OSIS_ATTR_SUBTYPE.toLowerCase());
|
|
||||||
isMoveBeforeVerse = StringUtils.containsIgnoreCase(subtype, PREVERSE) || (!verseInfo.isTextSinceVerse && verseInfo.currentVerseNo > 0);
|
|
||||||
if (isMoveBeforeVerse) {
|
|
||||||
// section Titles normally come before a verse, so overwrite the, already written verse, which is rewritten on writer.finishedInserting
|
|
||||||
writer.beginInsertAt(verseInfo.positionToInsertBeforeVerse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get title type from level
|
|
||||||
String titleClass = "heading" + TagHandlerHelper.getAttribute(OSISUtil.OSIS_ATTR_LEVEL, attrs, "1");
|
|
||||||
|
|
||||||
writer.write("<h1 class='" + titleClass + "'>");
|
|
||||||
} else {
|
|
||||||
writer.setDontWrite(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
if (isShowTitle) {
|
|
||||||
writer.write("</h1>");
|
|
||||||
if (isMoveBeforeVerse) {
|
|
||||||
// move positionToInsertBeforeVerse forward to after this title otherwise any subtitle will be above the title
|
|
||||||
verseInfo.positionToInsertBeforeVerse = writer.getPosition();
|
|
||||||
writer.finishInserting();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
writer.setDontWrite(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml;
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlSaxHandler.VerseInfo;
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import static org.bspeice.minimalbible.service.format.Constants.HTML;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write the verse number at the beginning of a verse
|
|
||||||
* Also handle verse per line
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class VerseHandler {
|
|
||||||
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
|
|
||||||
private VerseInfo verseInfo;
|
|
||||||
|
|
||||||
private int writerRollbackPosition;
|
|
||||||
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
public VerseHandler(OsisToHtmlParameters parameters, VerseInfo verseInfo, HtmlTextWriter writer) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
this.verseInfo = verseInfo;
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return OSISUtil.OSIS_ELEMENT_VERSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startAndUpdateVerse(Attributes attrs) {
|
|
||||||
writerRollbackPosition = writer.getPosition();
|
|
||||||
|
|
||||||
if (attrs != null) {
|
|
||||||
verseInfo.currentVerseNo = TagHandlerHelper.osisIdToVerseNum(attrs.getValue("", OSISUtil.OSIS_ATTR_OSISID));
|
|
||||||
} else {
|
|
||||||
verseInfo.currentVerseNo++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parameters.isVersePerline()) {
|
|
||||||
//close preceding verse
|
|
||||||
if (verseInfo.currentVerseNo > 1) {
|
|
||||||
writer.write("</div>");
|
|
||||||
}
|
|
||||||
// start current verse
|
|
||||||
writer.write("<div>");
|
|
||||||
}
|
|
||||||
|
|
||||||
writeVerse(verseInfo.currentVerseNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
if (!verseInfo.isTextSinceVerse) {
|
|
||||||
writer.removeAfter(writerRollbackPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeVerse(int verseNo) {
|
|
||||||
verseInfo.positionToInsertBeforeVerse = writer.getPosition();
|
|
||||||
|
|
||||||
// The id is used to 'jump to' the verse using javascript so always need the verse tag with an id
|
|
||||||
// Do not show verse 0
|
|
||||||
StringBuilder verseHtml = new StringBuilder();
|
|
||||||
if (parameters.isShowVerseNumbers() && verseNo != 0) {
|
|
||||||
verseHtml.append(" <span class='verse' id='").append(verseNo).append("'>").append(verseNo).append("</span>").append(HTML.NBSP);
|
|
||||||
} else {
|
|
||||||
// we really want an empty span but that is illegal and causes problems such as incorrect verse calculation in Psalms
|
|
||||||
// so use something that will hopefully interfere as little as possible - a zero-width-space
|
|
||||||
// also put a space before it to allow a separation from the last word of previous verse or to be ignored if start of line
|
|
||||||
verseHtml.append(" <span class='verse' id='").append(verseNo).append("'/>​</span>");
|
|
||||||
}
|
|
||||||
writer.write(verseHtml.toString());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.preprocessor;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class HebrewCharacterPreprocessor implements TextPreprocessor {
|
|
||||||
|
|
||||||
// the following characters are not handled well in Android 2.2 & 2.3 and
|
|
||||||
// need special processing which for all except Sof Pasuq means removal
|
|
||||||
// puctuation char at the end of hebrew verses that looks like a ':'
|
|
||||||
private static final String HEBREW_SOF_PASUQ_CHAR = "\u05C3";
|
|
||||||
// vowels are on the first row and cantillations on the second
|
|
||||||
private static final char[] HEBREW_VOWELS_AND_CANTILLATIONS = new char[]{
|
|
||||||
'\u05B0', '\u05B1', '\u05B2', '\u05B3', '\u05B4', '\u05B5',
|
|
||||||
'\u05B6', '\u05B7', '\u05B8', '\u05B9', '\u05BA', '\u05BB',
|
|
||||||
'\u05BC', '\u05BD', '\u05BE', '\u05BF', '\u05C1', '\u05C2',
|
|
||||||
'\u0591', '\u0592', '\u0593', '\u0594', '\u0595', '\u0596',
|
|
||||||
'\u0597', '\u0598', '\u0599', '\u059A', '\u059B', '\u059C',
|
|
||||||
'\u059D', '\u059E', '\u05A0', '\u05A1', '\u05A2', '\u05A3',
|
|
||||||
'\u05A4', '\u05A5', '\u05A6', '\u05A7', '\u05A8', '\u05A9',
|
|
||||||
'\u05AA', '\u05AB', '\u05AC', '\u05AD', '\u05AE', '\u05AF'};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* StringUtils methods only compare with a single char and hence create lots
|
|
||||||
* of temporary Strings This method compares with all chars and just creates
|
|
||||||
* one new string for each original string. This is to minimise memory
|
|
||||||
* overhead & gc.
|
|
||||||
*
|
|
||||||
* @param str
|
|
||||||
* @param removeChars
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String remove(String str, char[] removeChars) {
|
|
||||||
if (StringUtils.isEmpty(str)
|
|
||||||
|| !StringUtils.containsAny(str, removeChars)) {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
StringBuilder r = new StringBuilder(str.length());
|
|
||||||
// for all chars in string
|
|
||||||
for (int i = 0; i < str.length(); i++) {
|
|
||||||
char strCur = str.charAt(i);
|
|
||||||
// compare with all chars to be removed
|
|
||||||
boolean matched = false;
|
|
||||||
for (int j = 0; j < removeChars.length && !matched; j++) {
|
|
||||||
if (removeChars[j] == strCur) {
|
|
||||||
matched = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if current char does not match any in the list then add it to the
|
|
||||||
if (!matched) {
|
|
||||||
r.append(strCur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Some characters are not handled well in Android 2.2 & 2.3 and need
|
|
||||||
* special processing which for all except Sof Pasuq means removal
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
* @return adjusted string
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String process(String text) {
|
|
||||||
if (isVowelsBugFixed()) {
|
|
||||||
return text;
|
|
||||||
} else {
|
|
||||||
return doHebrewCharacterAdjustments(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* vowels rtl problem fixed in recent cyanogenmod and 4.0.3
|
|
||||||
*/
|
|
||||||
private boolean isVowelsBugFixed() {
|
|
||||||
return Build.VERSION.SDK_INT >= 15 || //Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1;
|
|
||||||
(Build.VERSION.SDK_INT >= 10 && System.getProperty("os.version").contains("cyanogenmod")); // 10 is GINGERBREAD_MR1 (2.3.3)
|
|
||||||
}
|
|
||||||
|
|
||||||
private String doHebrewCharacterAdjustments(String s) {
|
|
||||||
// remove Hebrew vowels because i) they confuse bidi and ii) they are
|
|
||||||
// not positioned correctly under/over the appropriate letter
|
|
||||||
// http://groups.google.com/group/android-contrib/browse_thread/thread/5b6b079f9ec7792a?pli=1
|
|
||||||
s = remove(s, HEBREW_VOWELS_AND_CANTILLATIONS);
|
|
||||||
|
|
||||||
// even without vowel points the : at the end of each verse confuses
|
|
||||||
// Android's bidi but specifying the char as rtl helps
|
|
||||||
s = s.replace(HEBREW_SOF_PASUQ_CHAR, "<span dir='rtl'>"
|
|
||||||
+ HEBREW_SOF_PASUQ_CHAR + "</span> ");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.preprocessor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* preprocess text content in the Sword module
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public interface TextPreprocessor {
|
|
||||||
/* convert module text to that required for display
|
|
||||||
*/
|
|
||||||
String process(String text);
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.strongs;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.HtmlTextWriter;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlParameters;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.TagHandlerHelper;
|
|
||||||
import org.crosswire.jsword.book.OSISUtil;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.bspeice.minimalbible.service.format.Constants.HTML;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class StrongsHandler {
|
|
||||||
|
|
||||||
List<String> pendingStrongsAndMorphTags;
|
|
||||||
;
|
|
||||||
private HtmlTextWriter writer;
|
|
||||||
|
|
||||||
private OsisToHtmlParameters parameters;
|
|
||||||
|
|
||||||
public StrongsHandler(OsisToHtmlParameters parameters, HtmlTextWriter writer) {
|
|
||||||
this.parameters = parameters;
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "q";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
if ((parameters.isShowStrongs() || parameters.isShowMorphology()) && TagHandlerHelper.isAttr(OSISUtil.ATTRIBUTE_W_LEMMA, attrs)) {
|
|
||||||
// Strongs & morphology references
|
|
||||||
// example of strongs refs: <w lemma="strong:H0430">God</w> <w lemma="strong:H0853 strong:H01254" morph="strongMorph:TH8804">created</w>
|
|
||||||
// better example, because we just use Robinson: <w lemma="strong:G652" morph="robinson:N-NSM" src="2">an apostle</w>
|
|
||||||
String strongsLemma = attrs.getValue(OSISUtil.ATTRIBUTE_W_LEMMA);
|
|
||||||
if (strongsLemma.startsWith(OSISUtil.LEMMA_STRONGS)) {
|
|
||||||
String morphology = attrs.getValue(OSISUtil.ATTRIBUTE_W_MORPH);
|
|
||||||
pendingStrongsAndMorphTags = getStrongsAndMorphTags(strongsLemma, morphology);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
if ((parameters.isShowStrongs() || parameters.isShowMorphology())) {
|
|
||||||
if (pendingStrongsAndMorphTags != null) {
|
|
||||||
for (int i = 0; i < pendingStrongsAndMorphTags.size(); i++) {
|
|
||||||
writer.write(HTML.SPACE); // separator between adjacent tags and words
|
|
||||||
writer.write(pendingStrongsAndMorphTags.get(i));
|
|
||||||
}
|
|
||||||
writer.write(HTML.SPACE); // separator between adjacent tags and words
|
|
||||||
pendingStrongsAndMorphTags = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a Strongs lemma into a url E.g. lemmas "strong:H0430",
|
|
||||||
* "strong:H0853 strong:H01254"
|
|
||||||
*
|
|
||||||
* @return a single char to use as a note ref
|
|
||||||
*/
|
|
||||||
private List<String> getStrongsAndMorphTags(String strongsLemma,
|
|
||||||
String morphology) {
|
|
||||||
// there may occasionally be more than on ref so split them into a list
|
|
||||||
// of single refs
|
|
||||||
List<String> strongsTags = getStrongsTags(strongsLemma);
|
|
||||||
List<String> morphTags = getMorphTags(morphology);
|
|
||||||
|
|
||||||
List<String> mergedStrongsAndMorphTags = new ArrayList<String>();
|
|
||||||
|
|
||||||
// each morph tag should relate to a Strongs tag so they should be same
|
|
||||||
// length but can't assume that
|
|
||||||
// merge the tags into the merge list
|
|
||||||
for (int i = 0; i < Math.max(strongsTags.size(), morphTags.size()); i++) {
|
|
||||||
StringBuilder merged = new StringBuilder();
|
|
||||||
if (i < strongsTags.size()) {
|
|
||||||
merged.append(strongsTags.get(i));
|
|
||||||
}
|
|
||||||
if (i < morphTags.size()) {
|
|
||||||
merged.append(morphTags.get(i));
|
|
||||||
}
|
|
||||||
mergedStrongsAndMorphTags.add(merged.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// for some reason the generic tags should come last and the order seems
|
|
||||||
// always reversed in other systems
|
|
||||||
// the second tag (once reversed) seems to relate to a missing word like
|
|
||||||
// eth
|
|
||||||
Collections.reverse(mergedStrongsAndMorphTags);
|
|
||||||
return mergedStrongsAndMorphTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getStrongsTags(String strongsLemma) {
|
|
||||||
// there may occasionally be more than on ref so split them into a list
|
|
||||||
// of single refs
|
|
||||||
List<String> strongsTags = new ArrayList<String>();
|
|
||||||
|
|
||||||
if (parameters.isShowStrongs()) {
|
|
||||||
String[] refList = strongsLemma.split(" ");
|
|
||||||
for (String ref : refList) {
|
|
||||||
// ignore if string doesn't start with "strong;"
|
|
||||||
if (ref.startsWith(OSISUtil.LEMMA_STRONGS)
|
|
||||||
&& ref.length() > OSISUtil.LEMMA_STRONGS.length() + 2) {
|
|
||||||
// reduce ref like "strong:H0430" to "H0430"
|
|
||||||
ref = ref.substring(OSISUtil.LEMMA_STRONGS.length());
|
|
||||||
|
|
||||||
// select Hebrew or Greek protocol
|
|
||||||
String protocol = StrongsUtil.getStrongsProtocol(ref);
|
|
||||||
|
|
||||||
if (protocol != null) {
|
|
||||||
// remove initial G or H
|
|
||||||
String strongsNumber = ref.substring(1);
|
|
||||||
|
|
||||||
String strTag = StrongsUtil.createStrongsLink(protocol, strongsNumber);
|
|
||||||
|
|
||||||
strongsTags.add(strTag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strongsTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* example of strongs and morphology, we just use Robinson: <w
|
|
||||||
* lemma="strong:G652" morph="robinson:N-NSM" src="2">an apostle</w>
|
|
||||||
*
|
|
||||||
* @param morphology
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private List<String> getMorphTags(String morphology) {
|
|
||||||
// there may occasionally be more than on ref so split them into a list
|
|
||||||
// of single refs
|
|
||||||
List<String> morphTags = new ArrayList<String>();
|
|
||||||
|
|
||||||
if (parameters.isShowMorphology()) {
|
|
||||||
if (StringUtils.isNotEmpty(morphology)) {
|
|
||||||
String[] refList = morphology.split(" ");
|
|
||||||
for (String ref : refList) {
|
|
||||||
// ignore if string doesn't start with "robinson"
|
|
||||||
if (ref.startsWith(OSISUtil.MORPH_ROBINSONS)
|
|
||||||
&& ref.length() > OSISUtil.MORPH_ROBINSONS.length() + 2) {
|
|
||||||
// reduce ref like "robinson:N-NSM" to "N-NSM" for
|
|
||||||
// display
|
|
||||||
String display = ref.substring(OSISUtil.MORPH_ROBINSONS
|
|
||||||
.length());
|
|
||||||
|
|
||||||
StringBuilder tag = new StringBuilder();
|
|
||||||
tag.append("<a href='").append(ref).append(
|
|
||||||
"' class='morphology'>").append(display)
|
|
||||||
.append("</a>");
|
|
||||||
|
|
||||||
morphTags.add(tag.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return morphTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum QType {quote, redLetter}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.strongs;
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.preprocessor.TextPreprocessor;
|
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used with StrongsGreek and StrongsHebrew to find text like 'see HEBREW for 0433' and 'see GREEK for 1223' and converts to links
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class StrongsLinkCreator implements TextPreprocessor {
|
|
||||||
|
|
||||||
static Pattern patt = Pattern.compile("see (HEBREW|GREEK) for (\\d{1,5})"); //".*see ([HEBREW|GREEK]) for (\\d{1,5}).*");
|
|
||||||
|
|
||||||
public String process(String text) {
|
|
||||||
StringBuffer result = new StringBuffer();
|
|
||||||
Matcher m = patt.matcher(text);
|
|
||||||
|
|
||||||
while (m.find()) {
|
|
||||||
String lang = m.group(1);
|
|
||||||
String refNo = m.group(2);
|
|
||||||
|
|
||||||
// select Hebrew or Greek protocol
|
|
||||||
String protocol = StrongsUtil.getStrongsProtocol(lang);
|
|
||||||
|
|
||||||
// append the actual link to the Strongs ref
|
|
||||||
String refLink = StrongsUtil.createStrongsLink(protocol, refNo, m.group(), "");
|
|
||||||
m.appendReplacement(result, refLink);
|
|
||||||
}
|
|
||||||
|
|
||||||
// append any trailing space after the last match, or if no match then the whole string
|
|
||||||
m.appendTail(result);
|
|
||||||
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.strongs;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import static org.bspeice.minimalbible.service.format.Constants.GREEK_DEF_PROTOCOL;
|
|
||||||
import static org.bspeice.minimalbible.service.format.Constants.HEBREW_DEF_PROTOCOL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class StrongsUtil {
|
|
||||||
|
|
||||||
private static final String DEFAULT_CSS_CLASS = "strongs";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an html link for teh passed in strongs number and protocol
|
|
||||||
*
|
|
||||||
* @param protocol = G or H
|
|
||||||
* @param strongsNumber
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String createStrongsLink(String protocol, String strongsNumber) {
|
|
||||||
return createStrongsLink(protocol, strongsNumber, strongsNumber, DEFAULT_CSS_CLASS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String createStrongsLink(String protocol, String strongsNumber, String content, String cssClass) {
|
|
||||||
// pad with leading zeros to 5 characters
|
|
||||||
String paddedRef = StringUtils.leftPad(strongsNumber, 5, "0");
|
|
||||||
|
|
||||||
StringBuilder tag = new StringBuilder();
|
|
||||||
// create opening tag for Strong's link
|
|
||||||
tag.append("<a href='");
|
|
||||||
|
|
||||||
// calculate uri e.g. H:01234
|
|
||||||
tag.append(protocol).append(":").append(paddedRef);
|
|
||||||
|
|
||||||
// set css class
|
|
||||||
tag.append("' class='" + cssClass + "'>");
|
|
||||||
|
|
||||||
// descriptive string
|
|
||||||
tag.append(content);
|
|
||||||
|
|
||||||
// link closing tag
|
|
||||||
tag.append("</a>");
|
|
||||||
|
|
||||||
String strTag = tag.toString();
|
|
||||||
return strTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getStrongsProtocol(String ref) {
|
|
||||||
if (ref.startsWith("H")) {
|
|
||||||
return HEBREW_DEF_PROTOCOL;
|
|
||||||
} else if (ref.startsWith("G")) {
|
|
||||||
return GREEK_DEF_PROTOCOL;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.tei;
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.HiHandler;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.HtmlTextWriter;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlParameters;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle orth tag very similarly to hi tag
|
|
||||||
* <orth>?????????</orth>
|
|
||||||
* <orth rend="bold" type="trans">aneuthetos</orth>
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class OrthHandler extends HiHandler {
|
|
||||||
|
|
||||||
private final static String DEFAULT = "bold";
|
|
||||||
|
|
||||||
public OrthHandler(OsisToHtmlParameters parameters, HtmlTextWriter writer) {
|
|
||||||
super(parameters, writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "orth";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
String rend = attrs.getValue(TEIUtil.TEI_ATTR_REND);
|
|
||||||
start(rend, DEFAULT);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.tei;
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.HiHandler;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.HtmlTextWriter;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlParameters;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle orth tag very similarly to hi tag
|
|
||||||
* <orth>?????????</orth>
|
|
||||||
* <orth rend="bold" type="trans">aneuthetos</orth>
|
|
||||||
*
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class PronHandler extends HiHandler {
|
|
||||||
|
|
||||||
private final static String DEFAULT = "italic";
|
|
||||||
|
|
||||||
public PronHandler(OsisToHtmlParameters parameters, HtmlTextWriter writer) {
|
|
||||||
super(parameters, writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTagName() {
|
|
||||||
return "pron";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
String rend = attrs.getValue(TEIUtil.TEI_ATTR_REND);
|
|
||||||
start(rend, DEFAULT);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.tei;
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.HtmlTextWriter;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.NoteHandler;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.OsisToHtmlParameters;
|
|
||||||
import org.bspeice.minimalbible.service.format.osistohtml.ReferenceHandler;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class RefHandler extends ReferenceHandler {
|
|
||||||
|
|
||||||
public RefHandler(OsisToHtmlParameters osisToHtmlParameters, NoteHandler noteHandler, HtmlTextWriter theWriter) {
|
|
||||||
super(osisToHtmlParameters, noteHandler, theWriter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Attributes attrs) {
|
|
||||||
String target = attrs.getValue(TEIUtil.TEI_ATTR_TARGET);
|
|
||||||
start(target);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.format.osistohtml.tei;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Martin Denham [mjdenham at gmail dot com]
|
|
||||||
* @see gnu.lgpl.License for license details.<br>
|
|
||||||
* The copyright to this program is held by it's author.
|
|
||||||
*/
|
|
||||||
public class TEIUtil {
|
|
||||||
|
|
||||||
// E.g. <ref target="StrongsHebrew:00411">H411</ref> taken from StrongsHebrew:00428
|
|
||||||
public static final String TEI_ELEMENT_REF = "ref";
|
|
||||||
public static final String TEI_ATTR_TARGET = "target";
|
|
||||||
|
|
||||||
public static final String TEI_ELEMENT_ORTH = "orth";
|
|
||||||
public static final String TEI_ELEMENT_PRON = "pron";
|
|
||||||
// the way tag contents are rendered e.g. 'bold'. 'italic'
|
|
||||||
public static final String TEI_ATTR_REND = "rend";
|
|
||||||
}
|
|
@ -11,21 +11,17 @@ import org.crosswire.jsword.versification.getBooks
|
|||||||
import org.crosswire.jsword.versification.BibleBook
|
import org.crosswire.jsword.versification.BibleBook
|
||||||
import org.bspeice.minimalbible.activity.viewer.BookAdapter.ChapterInfo
|
import org.bspeice.minimalbible.activity.viewer.BookAdapter.ChapterInfo
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
import org.bspeice.minimalbible.service.lookup.VerseLookup
|
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
import android.text.style.StyleSpan
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.text.style.SuperscriptSpan
|
|
||||||
import android.text.style.RelativeSizeSpan
|
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.OsisParser
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter used for displaying a book
|
* Adapter used for displaying a book
|
||||||
* Displays one chapter at a time,
|
* Displays one chapter at a time,
|
||||||
* as each TextView widget is it's own line break
|
* as each TextView widget is it's own line break
|
||||||
*/
|
*/
|
||||||
class BookAdapter(val b: Book, val lookup: VerseLookup,
|
class BookAdapter(val b: Book, val prefs: BibleViewerPreferences)
|
||||||
val prefs: BibleViewerPreferences)
|
|
||||||
: RecyclerView.Adapter<PassageView>() {
|
: RecyclerView.Adapter<PassageView>() {
|
||||||
|
|
||||||
val versification = b.getVersification()
|
val versification = b.getVersification()
|
||||||
@ -81,7 +77,7 @@ class BookAdapter(val b: Book, val lookup: VerseLookup,
|
|||||||
// TODO: Prefs object for handling this?
|
// TODO: Prefs object for handling this?
|
||||||
emptyView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
|
emptyView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
|
||||||
|
|
||||||
val passage = PassageView(emptyView, b, lookup)
|
val passage = PassageView(emptyView, b)
|
||||||
return passage
|
return passage
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,85 +110,20 @@ class BookAdapter(val b: Book, val lookup: VerseLookup,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PassageView(val v: TextView, val b: Book, val lookup: VerseLookup)
|
class PassageView(val v: TextView, val b: Book)
|
||||||
: RecyclerView.ViewHolder(v) {
|
: RecyclerView.ViewHolder(v) {
|
||||||
|
|
||||||
// Span to be applied to an individual verse - doesn't know about the sizes
|
fun buildOrdinal(verse: Int, info: ChapterInfo) =
|
||||||
// of other verses so that's why start and end are relative
|
b.getVersification().decodeOrdinal(verse + info.vOffset)
|
||||||
/**
|
|
||||||
* A holder object that knows how apply itself to a SpannableStringBuilder
|
fun getAllVerses(verses: Progression<Int>, info: ChapterInfo): SpannableStringBuilder {
|
||||||
* Since we don't know ahead of time where this verse will end up relative to the
|
val builder = SpannableStringBuilder()
|
||||||
* entire TextView (since there is one chapter per TextView) we use a start and end
|
verses.forEach { OsisParser(builder).appendVerse(b, buildOrdinal(it, info)) }
|
||||||
* relative to the verse text itself. That is, rStart of 0 indicates verse text start,
|
return builder
|
||||||
* and rEnd of (text.length - 1) indicates the end of verse text
|
|
||||||
* @param span The span object we should apply
|
|
||||||
* @param rStart When the span should begin, relative to the verse
|
|
||||||
* @param rEnd When the span should end, relative to the verse
|
|
||||||
*/
|
|
||||||
data class SpanHolder(val span: Any?, val rStart: Int, val rEnd: Int) {
|
|
||||||
// TODO: Is there a more case-class like way of doing this?
|
|
||||||
class object {
|
|
||||||
val EMPTY = SpanHolder(null, 0, 0)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Apply this span object to the specified builder
|
|
||||||
* Tries to be as close to immutable as possible. The offset is used to calculate
|
|
||||||
* the absolute position of when this span should start and end, since
|
|
||||||
* rStart and rEnd are relative to the verse text, and know nothing about the
|
|
||||||
* rest of the text in the TextView
|
|
||||||
*/
|
|
||||||
fun apply(builder: SpannableStringBuilder, offset: Int): SpannableStringBuilder {
|
|
||||||
if (span != null)
|
|
||||||
builder.setSpan(span, rStart + offset, rEnd + offset, 0)
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: getRawVerse shouldn't know how to decode ints
|
|
||||||
fun getRawVerse(verse: Int): String =
|
|
||||||
lookup.getText(b.getVersification().decodeOrdinal(verse))
|
|
||||||
|
|
||||||
// TODO: This code is nasty, not sure how to refactor, but it needs doing
|
|
||||||
fun getProcessedVerse(verseOrdinal: Int, info: ChapterInfo): Pair<String, List<SpanHolder>> {
|
|
||||||
val rawText = getRawVerse(verseOrdinal)
|
|
||||||
// To be honest, I have no idea why I need to subtract one. But I do.
|
|
||||||
val relativeVerse = verseOrdinal - info.vOffset - 1
|
|
||||||
val processedText = when (relativeVerse) {
|
|
||||||
0 -> ""
|
|
||||||
1 -> "${info.chapter} $rawText"
|
|
||||||
else -> "$relativeVerse$rawText"
|
|
||||||
}
|
|
||||||
val spans: List<SpanHolder> = listOf(
|
|
||||||
when (relativeVerse) {
|
|
||||||
0 -> SpanHolder.EMPTY
|
|
||||||
1 -> SpanHolder(StyleSpan(Typeface.BOLD), 0, info.chapter.toString().length)
|
|
||||||
else -> SpanHolder(SuperscriptSpan(), 0, relativeVerse.toString().length)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val secondSpan =
|
|
||||||
if (relativeVerse > 1)
|
|
||||||
// TODO: No magic numbers!
|
|
||||||
spans plus SpanHolder(RelativeSizeSpan(0.6f), 0, relativeVerse.toString().length)
|
|
||||||
else
|
|
||||||
spans
|
|
||||||
|
|
||||||
return Pair(processedText, secondSpan)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAllVerses(verses: Progression<Int>, info: ChapterInfo) =
|
|
||||||
verses.map { getProcessedVerse(it + info.vOffset, info) }
|
|
||||||
// For each verse, get the text
|
|
||||||
.fold(SpannableStringBuilder(), { initialBuilder, versePair ->
|
|
||||||
val offset = initialBuilder.length()
|
|
||||||
val builderWithText = initialBuilder append versePair.first
|
|
||||||
|
|
||||||
// And apply all spans
|
|
||||||
versePair.second.fold(builderWithText, { postBuilder, span ->
|
|
||||||
span.apply(postBuilder, offset)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
fun bind(info: ChapterInfo) {
|
fun bind(info: ChapterInfo) {
|
||||||
|
Log.d("PassageView", "Binding chapter ${info.chapter}")
|
||||||
v setText getAllVerses(info.vStart..info.vEnd, info)
|
v setText getAllVerses(info.vStart..info.vEnd, info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,21 +8,26 @@ import org.crosswire.jsword.book.OSISUtil
|
|||||||
import org.crosswire.jsword.book.BookData
|
import org.crosswire.jsword.book.BookData
|
||||||
import org.crosswire.jsword.book.Book
|
import org.crosswire.jsword.book.Book
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.handler.TagHandler
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.handler.VerseHandler
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.handler.UnknownHandler
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.handler.DivineHandler
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse out the OSIS XML into whatever we want!
|
* Parse out the OSIS XML into whatever we want!
|
||||||
* TODO: Speed up parsing. This is the single most expensive repeated operation
|
* TODO: Speed up parsing. This is the single most expensive repeated operation
|
||||||
*/
|
*/
|
||||||
class OsisParser() : DefaultHandler() {
|
class OsisParser(val builder: SpannableStringBuilder) : DefaultHandler() {
|
||||||
|
|
||||||
// Don't pass a verse as part of the constructor, but still guarantee
|
// Don't pass a verse as part of the constructor, but still guarantee
|
||||||
// that it will exist
|
// that it will exist
|
||||||
var verseContent: VerseContent by Delegates.notNull()
|
var verseContent: VerseContent by Delegates.notNull()
|
||||||
|
|
||||||
// TODO: Implement a stack to keep min API 8
|
// TODO: Implement a stack to keep min API 8
|
||||||
val doWrite = ArrayDeque<Boolean>()
|
val handlerStack = ArrayDeque<TagHandler>()
|
||||||
|
|
||||||
fun getVerse(b: Book, v: Verse): VerseContent {
|
fun appendVerse(b: Book, v: Verse): VerseContent {
|
||||||
verseContent = VerseContent(v)
|
verseContent = VerseContent(v)
|
||||||
BookData(b, v).getSAXEventProvider() provideSAXEvents this
|
BookData(b, v).getSAXEventProvider() provideSAXEvents this
|
||||||
return verseContent
|
return verseContent
|
||||||
@ -31,18 +36,17 @@ class OsisParser() : DefaultHandler() {
|
|||||||
override fun startElement(uri: String, localName: String,
|
override fun startElement(uri: String, localName: String,
|
||||||
qName: String, attributes: Attributes) {
|
qName: String, attributes: Attributes) {
|
||||||
when (localName) {
|
when (localName) {
|
||||||
OSISUtil.OSIS_ELEMENT_VERSE -> doWrite.push(true)
|
OSISUtil.OSIS_ELEMENT_VERSE -> handlerStack push VerseHandler()
|
||||||
"divineName" -> doWrite.push(true)
|
"divineName" -> handlerStack push DivineHandler()
|
||||||
else -> doWrite.push(false)
|
else -> handlerStack push UnknownHandler(localName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun endElement(uri: String, localName: String, qName: String) {
|
override fun endElement(uri: String, localName: String, qName: String) {
|
||||||
doWrite.pop()
|
handlerStack.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun characters(ch: CharArray, start: Int, length: Int) {
|
override fun characters(ch: CharArray, start: Int, length: Int) {
|
||||||
if (doWrite.peek())
|
handlerStack.peek().render(builder, verseContent, String(ch))
|
||||||
verseContent = verseContent appendContent String(ch)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ import com.google.gson.Gson
|
|||||||
import org.crosswire.jsword.passage.Verse
|
import org.crosswire.jsword.passage.Verse
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
//TODO: JSON Streaming parsing? http://instagram-engineering.tumblr.com/post/97147584853/json-parsing
|
// TODO: Refactor to a VerseInfo class, not the actual content to support "streaming" parsing
|
||||||
data class VerseContent(val v: Verse,
|
data class VerseContent(val v: Verse,
|
||||||
val id: Int = v.getOrdinal(),
|
val id: Int = v.getOrdinal(),
|
||||||
val bookName: String = v.getName(),
|
val bookName: String = v.getName(),
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package org.bspeice.minimalbible.service.format.osisparser.handler
|
||||||
|
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.VerseContent
|
||||||
|
import android.text.style.RelativeSizeSpan
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by bspeice on 12/1/14.
|
||||||
|
*/
|
||||||
|
class DivineHandler() : TagHandler {
|
||||||
|
override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String) {
|
||||||
|
this buildDivineName chars forEach { it apply builder }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildDivineName(chars: String) =
|
||||||
|
listOf(AppendArgs(chars take 1, null),
|
||||||
|
AppendArgs(chars drop 1, RelativeSizeSpan(.9f))
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package org.bspeice.minimalbible.service.format.osisparser.handler
|
||||||
|
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.VerseContent
|
||||||
|
import android.text.style.CharacterStyle
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by bspeice on 12/1/14.
|
||||||
|
*/
|
||||||
|
|
||||||
|
trait TagHandler {
|
||||||
|
fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AppendArgs(val text: String, val span: Any?) {
|
||||||
|
fun apply(builder: SpannableStringBuilder) {
|
||||||
|
val offset = builder.length()
|
||||||
|
builder.append(text)
|
||||||
|
when (span) {
|
||||||
|
is List<*> -> span.forEach { builder.setSpan(it, offset, offset + text.length, 0) }
|
||||||
|
is CharacterStyle -> builder.setSpan(span, offset, offset + text.length, 0)
|
||||||
|
}
|
||||||
|
builder.setSpan(span, offset, offset + text.length, 0)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.bspeice.minimalbible.service.format.osisparser.handler
|
||||||
|
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import android.util.Log
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.VerseContent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by bspeice on 12/1/14.
|
||||||
|
*/
|
||||||
|
class UnknownHandler(val tagName: String) : TagHandler {
|
||||||
|
override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String) {
|
||||||
|
Log.d("UnknownHandler", "Unknown tag $tagName received text: $chars")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.bspeice.minimalbible.service.format.osisparser.handler
|
||||||
|
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import org.bspeice.minimalbible.service.format.osisparser.VerseContent
|
||||||
|
import android.text.style.StyleSpan
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.text.style.SuperscriptSpan
|
||||||
|
import android.text.style.RelativeSizeSpan
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by bspeice on 12/1/14.
|
||||||
|
*/
|
||||||
|
class VerseHandler() : TagHandler {
|
||||||
|
var isVerseStart = true
|
||||||
|
|
||||||
|
override fun render(builder: SpannableStringBuilder, info: VerseContent, chars: String) {
|
||||||
|
buildVerseHeader(info.chapter, info.verseNum, isVerseStart) apply builder
|
||||||
|
builder append chars
|
||||||
|
isVerseStart = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildVerseHeader(chapter: Int, verseNum: Int, verseStart: Boolean): AppendArgs =
|
||||||
|
when {
|
||||||
|
!verseStart -> AppendArgs("", null)
|
||||||
|
verseNum == 1 -> AppendArgs("$chapter", StyleSpan(Typeface.BOLD))
|
||||||
|
else -> AppendArgs("${verseNum}", listOf(SuperscriptSpan(), RelativeSizeSpan(.75f)))
|
||||||
|
}
|
||||||
|
}
|
@ -1,86 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.service.lookup
|
|
||||||
|
|
||||||
import org.crosswire.jsword.book.Book
|
|
||||||
import android.support.v4.util.LruCache
|
|
||||||
import rx.functions.Action1
|
|
||||||
import org.crosswire.jsword.passage.Verse
|
|
||||||
import rx.subjects.PublishSubject
|
|
||||||
import rx.schedulers.Schedulers
|
|
||||||
import org.bspeice.minimalbible.service.format.osisparser.OsisParser
|
|
||||||
import org.crosswire.jsword.book.getVersification
|
|
||||||
import org.bspeice.minimalbible.service.format.osisparser.VerseContent
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do the low-level work of getting a verse's content
|
|
||||||
* This class is currently impossible to test because I can't mock Verse objects
|
|
||||||
*/
|
|
||||||
open class VerseLookup(val b: Book) : Action1<Verse> {
|
|
||||||
|
|
||||||
val cache = VerseCache()
|
|
||||||
/**
|
|
||||||
* The listener servers to let other objects notify us we should pre-cache verses
|
|
||||||
*/
|
|
||||||
val listener: PublishSubject<Verse> = PublishSubject.create();
|
|
||||||
|
|
||||||
{
|
|
||||||
listener.observeOn(Schedulers.io())
|
|
||||||
.subscribe(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getVerseId(v: Verse) = v.getOrdinal()
|
|
||||||
|
|
||||||
fun getText(v: Verse): String =
|
|
||||||
if (cache contains v)
|
|
||||||
cache[getVerseId(v)]
|
|
||||||
else {
|
|
||||||
val content = doLookup(v).content
|
|
||||||
notify(v)
|
|
||||||
content
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform the ugly work of getting the actual data for a verse
|
|
||||||
* Note that we build the verse object, JS should be left to determine how
|
|
||||||
* it is displayed.
|
|
||||||
*
|
|
||||||
* @param v The verse to look up
|
|
||||||
* @return The string content of this verse
|
|
||||||
*/
|
|
||||||
fun doLookup(v: Verse): VerseContent = OsisParser().getVerse(b, v)
|
|
||||||
fun doLookup(ordinal: Int): VerseContent = OsisParser()
|
|
||||||
.getVerse(b, b.getVersification() decodeOrdinal ordinal)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not necessary, but helpful if you let us know ahead of time we should pre-cache a verse.
|
|
||||||
* For example, if something showed up in search results, it'd be helpful to start
|
|
||||||
* looking up some of the results.
|
|
||||||
*
|
|
||||||
* @param v The verse we should pre-cache
|
|
||||||
*/
|
|
||||||
fun notify(v: Verse) = listener onNext v
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Let someone know if the cache contains a verse we want
|
|
||||||
* Also provides a nice wrapper if the underlying cache isn't working properly.
|
|
||||||
*
|
|
||||||
* @param v The verse to check
|
|
||||||
* @return Whether we can retrieve the verse from our cache
|
|
||||||
*/
|
|
||||||
open fun contains(v: Verse) = cache[v.getOrdinal()] != null
|
|
||||||
|
|
||||||
// IO Thread operations begin here
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Someone was nice enough to let us know that a verse was recently called,
|
|
||||||
* we should probably cache its neighbors!
|
|
||||||
*/
|
|
||||||
override fun call(t1: Verse?) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class VerseCache : LruCache<Int, String>(1000000) {
|
|
||||||
|
|
||||||
fun getId(v: Verse) = v.getOrdinal()
|
|
||||||
fun contains(v: Verse) = (this get getId(v)) != null
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user