From bc3f86c3fee720a7ff0bf3d27384dadfb0e5a5cd Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Tue, 30 Apr 2013 00:26:44 +0200 Subject: [PATCH] store end position in bookmarks; set end position for new bookmarks --- .../android/fbreader/FBReader.java | 1 + .../libraryService/SQLiteBooksDatabase.java | 8 +- .../geometerplus/fbreader/book/Bookmark.java | 226 +++++++++++------- .../fbreader/book/BooksDatabase.java | 18 +- .../fbreader/book/XMLSerializer.java | 65 ++++- .../fbreader/fbreader/FBReaderApp.java | 4 +- 6 files changed, 213 insertions(+), 109 deletions(-) diff --git a/src/org/geometerplus/android/fbreader/FBReader.java b/src/org/geometerplus/android/fbreader/FBReader.java index 9ca921762..10ccbd78e 100644 --- a/src/org/geometerplus/android/fbreader/FBReader.java +++ b/src/org/geometerplus/android/fbreader/FBReader.java @@ -646,6 +646,7 @@ public final class FBReader extends Activity { myFBReaderApp.Model.Book, fbView.getModel().getId(), fbView.getSelectionStartPosition(), + fbView.getSelectionEndPosition(), text, true ); diff --git a/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java b/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java index 0c52d54d4..603699cd8 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java +++ b/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java @@ -839,7 +839,8 @@ final class SQLiteBooksDatabase extends BooksDatabase { final StringBuilder sql = new StringBuilder("SELECT") .append(" bm.bookmark_id,bm.book_id,b.title,bm.bookmark_text,") .append("bm.creation_time,bm.modification_time,bm.access_time,bm.access_counter,") - .append("bm.model_id,bm.paragraph,bm.word,bm.char") + .append("bm.model_id,bm.paragraph,bm.word,bm.char,") + .append("bm.end_paragraph,bm.end_word,bm.end_character,") .append(" FROM Bookmarks AS bm INNER JOIN Books AS b ON b.book_id = bm.book_id") .append(" WHERE"); if (query.Book != null) { @@ -864,7 +865,10 @@ final class SQLiteBooksDatabase extends BooksDatabase { (int)cursor.getLong(9), (int)cursor.getLong(10), (int)cursor.getLong(11), - true + (int)cursor.getLong(12), + cursor.isNull(13) ? -1 : (int)cursor.getLong(13), + cursor.isNull(14) ? -1 : (int)cursor.getLong(14), + query.Visible )); } cursor.close(); diff --git a/src/org/geometerplus/fbreader/book/Bookmark.java b/src/org/geometerplus/fbreader/book/Bookmark.java index d7c824ce6..d00cd5f54 100644 --- a/src/org/geometerplus/fbreader/book/Bookmark.java +++ b/src/org/geometerplus/fbreader/book/Bookmark.java @@ -40,12 +40,21 @@ public final class Bookmark extends ZLTextFixedPosition { private Date myAccessDate; private int myAccessCount; private Date myLatestDate; + private ZLTextFixedPosition myEnd; + private int myLength; public final String ModelId; public final boolean IsVisible; - Bookmark(long id, long bookId, String bookTitle, String text, Date creationDate, Date modificationDate, Date accessDate, int accessCount, String modelId, int paragraphIndex, int elementIndex, int charIndex, boolean isVisible) { - super(paragraphIndex, elementIndex, charIndex); + Bookmark( + long id, long bookId, String bookTitle, String text, + Date creationDate, Date modificationDate, Date accessDate, int accessCount, + String modelId, + int start_paragraphIndex, int start_elementIndex, int start_charIndex, + int end_paragraphIndex, int end_elementIndex, int end_charIndex, + boolean isVisible + ) { + super(start_paragraphIndex, start_elementIndex, start_charIndex); myId = id; myBookId = bookId; @@ -63,14 +72,128 @@ public final class Bookmark extends ZLTextFixedPosition { myAccessCount = accessCount; ModelId = modelId; IsVisible = isVisible; + + if (end_charIndex >= 0) { + myEnd = new ZLTextFixedPosition(end_paragraphIndex, end_elementIndex, end_charIndex); + } else { + myLength = end_paragraphIndex; + } } + private static class Buffer { + final StringBuilder Builder = new StringBuilder(); + final ZLTextWordCursor Cursor; + + Buffer(ZLTextWordCursor cursor) { + Cursor = new ZLTextWordCursor(cursor); + } + + boolean isEmpty() { + return Builder.length() == 0; + } + + void append(Buffer buffer) { + Builder.append(buffer.Builder); + Cursor.setCursor(buffer.Cursor); + buffer.Builder.delete(0, buffer.Builder.length()); + } + + void append(CharSequence data) { + Builder.append(data); + } + } + + public static Bookmark createBookmark(Book book, String modelId, ZLTextWordCursor startCursor, int maxWords, boolean isVisible) { + final ZLTextWordCursor cursor = new ZLTextWordCursor(startCursor); + + final Buffer buffer = new Buffer(cursor); + final Buffer sentenceBuffer = new Buffer(cursor); + final Buffer phraseBuffer = new Buffer(cursor); + + int wordCounter = 0; + int sentenceCounter = 0; + int storedWordCounter = 0; + boolean lineIsNonEmpty = false; + boolean appendLineBreak = false; +mainLoop: + while (wordCounter < maxWords && sentenceCounter < 3) { + while (cursor.isEndOfParagraph()) { + if (!cursor.nextParagraph()) { + break mainLoop; + } + if (!buffer.isEmpty() && cursor.getParagraphCursor().isEndOfSection()) { + break mainLoop; + } + if (!phraseBuffer.isEmpty()) { + sentenceBuffer.append(phraseBuffer); + } + if (!sentenceBuffer.isEmpty()) { + if (appendLineBreak) { + buffer.append("\n"); + } + buffer.append(sentenceBuffer); + ++sentenceCounter; + storedWordCounter = wordCounter; + } + lineIsNonEmpty = false; + if (!buffer.isEmpty()) { + appendLineBreak = true; + } + } + final ZLTextElement element = cursor.getElement(); + if (element instanceof ZLTextWord) { + final ZLTextWord word = (ZLTextWord)element; + if (lineIsNonEmpty) { + phraseBuffer.append(" "); + } + phraseBuffer.Builder.append(word.Data, word.Offset, word.Length); + phraseBuffer.Cursor.setCursor(cursor); + phraseBuffer.Cursor.setCharIndex(word.Length); + ++wordCounter; + lineIsNonEmpty = true; + switch (word.Data[word.Offset + word.Length - 1]) { + case ',': + case ':': + case ';': + case ')': + sentenceBuffer.append(phraseBuffer); + break; + case '.': + case '!': + case '?': + ++sentenceCounter; + if (appendLineBreak) { + buffer.append("\n"); + appendLineBreak = false; + } + sentenceBuffer.append(phraseBuffer); + buffer.append(sentenceBuffer); + storedWordCounter = wordCounter; + break; + } + } + cursor.nextWord(); + } + if (storedWordCounter < 4) { + if (sentenceBuffer.isEmpty()) { + sentenceBuffer.append(phraseBuffer); + } + if (appendLineBreak) { + buffer.append("\n"); + } + buffer.append(sentenceBuffer); + } + return new Bookmark(book, modelId, startCursor, buffer.Cursor, buffer.Builder.toString(), isVisible); + } + + /* public Bookmark(Book book, String modelId, ZLTextWordCursor cursor, int maxLength, boolean isVisible) { this(book, modelId, cursor, createBookmarkText(cursor, maxLength), isVisible); } + */ - public Bookmark(Book book, String modelId, ZLTextPosition position, String text, boolean isVisible) { - super(position); + public Bookmark(Book book, String modelId, ZLTextPosition start, ZLTextPosition end, String text, boolean isVisible) { + super(start); myId = -1; myBookId = book.getId(); @@ -79,6 +202,7 @@ public final class Bookmark extends ZLTextFixedPosition { myCreationDate = new Date(); ModelId = modelId; IsVisible = isVisible; + myEnd = new ZLTextFixedPosition(end); } public long getId() { @@ -115,6 +239,14 @@ public final class Bookmark extends ZLTextFixedPosition { return myAccessCount; } + public ZLTextPosition getEnd() { + return myEnd; + } + + public int getLength() { + return myLength; + } + public void setText(String text) { if (!text.equals(myText)) { myText = text; @@ -140,92 +272,6 @@ public final class Bookmark extends ZLTextFixedPosition { } } - private static String createBookmarkText(ZLTextWordCursor cursor, int maxWords) { - cursor = new ZLTextWordCursor(cursor); - - final StringBuilder builder = new StringBuilder(); - final StringBuilder sentenceBuilder = new StringBuilder(); - final StringBuilder phraseBuilder = new StringBuilder(); - - int wordCounter = 0; - int sentenceCounter = 0; - int storedWordCounter = 0; - boolean lineIsNonEmpty = false; - boolean appendLineBreak = false; -mainLoop: - while (wordCounter < maxWords && sentenceCounter < 3) { - while (cursor.isEndOfParagraph()) { - if (!cursor.nextParagraph()) { - break mainLoop; - } - if ((builder.length() > 0) && cursor.getParagraphCursor().isEndOfSection()) { - break mainLoop; - } - if (phraseBuilder.length() > 0) { - sentenceBuilder.append(phraseBuilder); - phraseBuilder.delete(0, phraseBuilder.length()); - } - if (sentenceBuilder.length() > 0) { - if (appendLineBreak) { - builder.append("\n"); - } - builder.append(sentenceBuilder); - sentenceBuilder.delete(0, sentenceBuilder.length()); - ++sentenceCounter; - storedWordCounter = wordCounter; - } - lineIsNonEmpty = false; - if (builder.length() > 0) { - appendLineBreak = true; - } - } - final ZLTextElement element = cursor.getElement(); - if (element instanceof ZLTextWord) { - final ZLTextWord word = (ZLTextWord)element; - if (lineIsNonEmpty) { - phraseBuilder.append(" "); - } - phraseBuilder.append(word.Data, word.Offset, word.Length); - ++wordCounter; - lineIsNonEmpty = true; - switch (word.Data[word.Offset + word.Length - 1]) { - case ',': - case ':': - case ';': - case ')': - sentenceBuilder.append(phraseBuilder); - phraseBuilder.delete(0, phraseBuilder.length()); - break; - case '.': - case '!': - case '?': - ++sentenceCounter; - if (appendLineBreak) { - builder.append("\n"); - appendLineBreak = false; - } - sentenceBuilder.append(phraseBuilder); - phraseBuilder.delete(0, phraseBuilder.length()); - builder.append(sentenceBuilder); - sentenceBuilder.delete(0, sentenceBuilder.length()); - storedWordCounter = wordCounter; - break; - } - } - cursor.nextWord(); - } - if (storedWordCounter < 4) { - if (sentenceBuilder.length() == 0) { - sentenceBuilder.append(phraseBuilder); - } - if (appendLineBreak) { - builder.append("\n"); - } - builder.append(sentenceBuilder); - } - return builder.toString(); - } - void setId(long id) { myId = id; } diff --git a/src/org/geometerplus/fbreader/book/BooksDatabase.java b/src/org/geometerplus/fbreader/book/BooksDatabase.java index d53522aa2..2354d0224 100644 --- a/src/org/geometerplus/fbreader/book/BooksDatabase.java +++ b/src/org/geometerplus/fbreader/book/BooksDatabase.java @@ -86,8 +86,22 @@ public abstract class BooksDatabase { protected abstract void setLabel(long bookId, String label); protected abstract void removeLabel(long bookId, String label); - protected Bookmark createBookmark(long id, long bookId, String bookTitle, String text, Date creationDate, Date modificationDate, Date accessDate, int accessCounter, String modelId, int paragraphIndex, int wordIndex, int charIndex, boolean isVisible) { - return new Bookmark(id, bookId, bookTitle, text, creationDate, modificationDate, accessDate, accessCounter, modelId, paragraphIndex, wordIndex, charIndex, isVisible); + protected Bookmark createBookmark( + long id, long bookId, String bookTitle, String text, + Date creationDate, Date modificationDate, Date accessDate, int accessCounter, + String modelId, + int start_paragraphIndex, int start_wordIndex, int start_charIndex, + int end_paragraphIndex, int end_wordIndex, int end_charIndex, + boolean isVisible + ) { + return new Bookmark( + id, bookId, bookTitle, text, + creationDate, modificationDate, accessDate, accessCounter, + modelId, + start_paragraphIndex, start_wordIndex, start_charIndex, + end_paragraphIndex, end_wordIndex, end_charIndex, + isVisible + ); } protected abstract List loadBookmarks(BookmarkQuery query); diff --git a/src/org/geometerplus/fbreader/book/XMLSerializer.java b/src/org/geometerplus/fbreader/book/XMLSerializer.java index b21a27fb4..7f18bedc2 100644 --- a/src/org/geometerplus/fbreader/book/XMLSerializer.java +++ b/src/org/geometerplus/fbreader/book/XMLSerializer.java @@ -26,6 +26,8 @@ import java.text.ParseException; import org.geometerplus.zlibrary.core.constants.XMLNamespaces; import org.geometerplus.zlibrary.core.filesystem.ZLFile; +import org.geometerplus.zlibrary.text.view.ZLTextPosition; + import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; @@ -262,12 +264,26 @@ class XMLSerializer extends AbstractSerializer { "access-count", String.valueOf(bookmark.getAccessCount()) ); appendTag( - buffer, "position", true, + buffer, "start", true, "model", bookmark.ModelId, "paragraph", String.valueOf(bookmark.getParagraphIndex()), "element", String.valueOf(bookmark.getElementIndex()), "char", String.valueOf(bookmark.getCharIndex()) ); + final ZLTextPosition end = bookmark.getEnd(); + if (end != null) { + appendTag( + buffer, "end", true, + "paragraph", String.valueOf(end.getParagraphIndex()), + "element", String.valueOf(end.getElementIndex()), + "char", String.valueOf(end.getCharIndex()) + ); + } else { + appendTag( + buffer, "end", true, + "length", String.valueOf(bookmark.getLength()) + ); + } closeTag(buffer, "bookmark"); return buffer.toString(); } @@ -761,9 +777,12 @@ class XMLSerializer extends AbstractSerializer { private Date myAccessDate; private int myAccessCount; private String myModelId; - private int myParagraphIndex; - private int myElementIndex; - private int myCharIndex; + private int myStartParagraphIndex; + private int myStartElementIndex; + private int myStartCharIndex; + private int myEndParagraphIndex; + private int myEndElementIndex; + private int myEndCharIndex; private boolean myIsVisible; public Bookmark getBookmark() { @@ -783,9 +802,12 @@ class XMLSerializer extends AbstractSerializer { myAccessDate = null; myAccessCount = 0; myModelId = null; - myParagraphIndex = 0; - myElementIndex = 0; - myCharIndex = 0; + myStartParagraphIndex = 0; + myStartElementIndex = 0; + myStartCharIndex = 0; + myEndParagraphIndex = -1; + myEndElementIndex = -1; + myEndCharIndex = -1; myIsVisible = false; myState = State.READ_NOTHING; @@ -799,11 +821,13 @@ class XMLSerializer extends AbstractSerializer { myBookmark = new Bookmark( myId, myBookId, myBookTitle, myText.toString(), myCreationDate, myModificationDate, myAccessDate, myAccessCount, - myModelId, myParagraphIndex, myElementIndex, myCharIndex, myIsVisible + myModelId, + myStartParagraphIndex, myStartElementIndex, myStartCharIndex, + myEndParagraphIndex, myEndElementIndex, myEndCharIndex, + myIsVisible ); } - //appendTagWithContent(buffer, "text", bookmark.getText()); @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { switch (myState) { @@ -838,12 +862,27 @@ class XMLSerializer extends AbstractSerializer { } catch (Exception e) { throw new SAXException("XML parsing error", e); } - } else if ("position".equals(localName)) { + } else if ("start".equals(localName)) { try { myModelId = attributes.getValue("model"); - myParagraphIndex = Integer.parseInt(attributes.getValue("paragraph")); - myElementIndex = Integer.parseInt(attributes.getValue("element")); - myCharIndex = Integer.parseInt(attributes.getValue("char")); + myStartParagraphIndex = Integer.parseInt(attributes.getValue("paragraph")); + myStartElementIndex = Integer.parseInt(attributes.getValue("element")); + myStartCharIndex = Integer.parseInt(attributes.getValue("char")); + } catch (Exception e) { + throw new SAXException("XML parsing error", e); + } + } else if ("end".equals(localName)) { + try { + final String para = attributes.getValue("paragraph"); + if (para != null) { + myEndParagraphIndex = Integer.parseInt(para); + myEndElementIndex = Integer.parseInt(attributes.getValue("element")); + myEndCharIndex = Integer.parseInt(attributes.getValue("char")); + } else { + myEndParagraphIndex = Integer.parseInt(attributes.getValue("length")); + myEndElementIndex = -1; + myEndCharIndex = -1; + } } catch (Exception e) { throw new SAXException("XML parsing error", e); } diff --git a/src/org/geometerplus/fbreader/fbreader/FBReaderApp.java b/src/org/geometerplus/fbreader/fbreader/FBReaderApp.java index 5e411436e..ef0087c7b 100644 --- a/src/org/geometerplus/fbreader/fbreader/FBReaderApp.java +++ b/src/org/geometerplus/fbreader/fbreader/FBReaderApp.java @@ -478,7 +478,7 @@ public final class FBReaderApp extends ZLApplication { public void addInvisibleBookmark(ZLTextWordCursor cursor) { if (cursor != null && Model != null && Model.Book != null && getTextView() == BookTextView) { - updateInvisibleBookmarksList(new Bookmark( + updateInvisibleBookmarksList(Bookmark.createBookmark( Model.Book, getTextView().getModel().getId(), cursor, @@ -502,7 +502,7 @@ public final class FBReaderApp extends ZLApplication { return null; } - return new Bookmark( + return Bookmark.createBookmark( Model.Book, view.getModel().getId(), cursor,