1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-04 10:19:33 +02:00

bookmark serialization; used in BookmarksActivity

This commit is contained in:
Nikolay Pultsin 2013-01-11 03:46:57 +04:00
parent 4d4a495b7c
commit 024adf0509
5 changed files with 283 additions and 69 deletions

View file

@ -46,7 +46,7 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
private final BookCollectionShadow myCollection = new BookCollectionShadow(this); private final BookCollectionShadow myCollection = new BookCollectionShadow(this);
List<Bookmark> AllBooksBookmarks; private List<Bookmark> myAllBooksBookmarks;
private final List<Bookmark> myThisBookBookmarks = new LinkedList<Bookmark>(); private final List<Bookmark> myThisBookBookmarks = new LinkedList<Bookmark>();
private final List<Bookmark> mySearchResults = new LinkedList<Bookmark>(); private final List<Bookmark> mySearchResults = new LinkedList<Bookmark>();
@ -71,8 +71,6 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
Thread.setDefaultUncaughtExceptionHandler(new org.geometerplus.zlibrary.ui.android.library.UncaughtExceptionHandler(this)); Thread.setDefaultUncaughtExceptionHandler(new org.geometerplus.zlibrary.ui.android.library.UncaughtExceptionHandler(this));
myCollection.bindToService();
requestWindowFeature(Window.FEATURE_NO_TITLE); requestWindowFeature(Window.FEATURE_NO_TITLE);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
@ -81,14 +79,16 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
final TabHost host = getTabHost(); final TabHost host = getTabHost();
LayoutInflater.from(this).inflate(R.layout.bookmarks, host.getTabContentView(), true); LayoutInflater.from(this).inflate(R.layout.bookmarks, host.getTabContentView(), true);
}
AllBooksBookmarks = Library.Instance().allBookmarks(); private void init() {
Collections.sort(AllBooksBookmarks, new Bookmark.ByTimeComparator()); myAllBooksBookmarks = new ArrayList<Bookmark>(myCollection.allBookmarks());
Collections.sort(myAllBooksBookmarks, new Bookmark.ByTimeComparator());
final FBReaderApp fbreader = (FBReaderApp)FBReaderApp.Instance(); final FBReaderApp fbreader = (FBReaderApp)FBReaderApp.Instance();
if (fbreader.Model != null) { if (fbreader.Model != null) {
final long bookId = fbreader.Model.Book.getId(); final long bookId = fbreader.Model.Book.getId();
for (Bookmark bookmark : AllBooksBookmarks) { for (Bookmark bookmark : myAllBooksBookmarks) {
if (bookmark.getBookId() == bookId) { if (bookmark.getBookId() == bookId) {
myThisBookBookmarks.add(bookmark); myThisBookBookmarks.add(bookmark);
} }
@ -101,7 +101,7 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
} }
myAllBooksView = createTab("allBooks", R.id.all_books); myAllBooksView = createTab("allBooks", R.id.all_books);
new BookmarksAdapter(myAllBooksView, AllBooksBookmarks, false); new BookmarksAdapter(myAllBooksView, myAllBooksBookmarks, false);
findViewById(R.id.search_results).setVisibility(View.GONE); findViewById(R.id.search_results).setVisibility(View.GONE);
} }
@ -109,6 +109,15 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
myCollection.bindToService(new Runnable() {
public void run() {
if (myAllBooksBookmarks == null) {
init();
}
}
});
OrientationUtil.setOrientation(this, getIntent()); OrientationUtil.setOrientation(this, getIntent());
} }
@ -124,7 +133,7 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
final LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>(); final LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>();
pattern = pattern.toLowerCase(); pattern = pattern.toLowerCase();
for (Bookmark b : AllBooksBookmarks) { for (Bookmark b : myAllBooksBookmarks) {
if (ZLMiscUtil.matchesIgnoreCase(b.getText(), pattern)) { if (ZLMiscUtil.matchesIgnoreCase(b.getText(), pattern)) {
bookmarks.add(b); bookmarks.add(b);
} }
@ -138,12 +147,18 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
@Override @Override
public void onPause() { public void onPause() {
for (Bookmark bookmark : AllBooksBookmarks) { for (Bookmark bookmark : myAllBooksBookmarks) {
bookmark.save(); bookmark.save();
} }
super.onPause(); super.onPause();
} }
@Override
protected void onStop() {
myCollection.unbind();
super.onStop();
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
@ -212,7 +227,7 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
case DELETE_ITEM_ID: case DELETE_ITEM_ID:
bookmark.delete(); bookmark.delete();
myThisBookBookmarks.remove(bookmark); myThisBookBookmarks.remove(bookmark);
AllBooksBookmarks.remove(bookmark); myAllBooksBookmarks.remove(bookmark);
mySearchResults.remove(bookmark); mySearchResults.remove(bookmark);
invalidateAllViews(); invalidateAllViews();
return true; return true;
@ -225,7 +240,7 @@ public class BookmarksActivity extends TabActivity implements MenuItem.OnMenuIte
final Bookmark bookmark = fbreader.addBookmark(20, true); final Bookmark bookmark = fbreader.addBookmark(20, true);
if (bookmark != null) { if (bookmark != null) {
myThisBookBookmarks.add(0, bookmark); myThisBookBookmarks.add(0, bookmark);
AllBooksBookmarks.add(0, bookmark); myAllBooksBookmarks.add(0, bookmark);
invalidateAllViews(); invalidateAllViews();
} }
} }

View file

@ -799,9 +799,9 @@ public final class SQLiteBooksDatabase extends BooksDatabase {
statement.bindLong(1, bookmark.getBookId()); statement.bindLong(1, bookmark.getBookId());
statement.bindString(2, bookmark.getText()); statement.bindString(2, bookmark.getText());
SQLiteUtil.bindDate(statement, 3, bookmark.getTime(Bookmark.CREATION)); SQLiteUtil.bindDate(statement, 3, bookmark.getDate(Bookmark.DateType.Creation));
SQLiteUtil.bindDate(statement, 4, bookmark.getTime(Bookmark.MODIFICATION)); SQLiteUtil.bindDate(statement, 4, bookmark.getDate(Bookmark.DateType.Modification));
SQLiteUtil.bindDate(statement, 5, bookmark.getTime(Bookmark.ACCESS)); SQLiteUtil.bindDate(statement, 5, bookmark.getDate(Bookmark.DateType.Access));
statement.bindLong(6, bookmark.getAccessCount()); statement.bindLong(6, bookmark.getAccessCount());
SQLiteUtil.bindString(statement, 7, bookmark.ModelId); SQLiteUtil.bindString(statement, 7, bookmark.ModelId);
statement.bindLong(8, bookmark.ParagraphIndex); statement.bindLong(8, bookmark.ParagraphIndex);

View file

@ -31,12 +31,14 @@ import org.geometerplus.fbreader.library.*;
public class BookCollectionShadow implements IBookCollection, ServiceConnection { public class BookCollectionShadow implements IBookCollection, ServiceConnection {
private final Context myContext; private final Context myContext;
private volatile LibraryInterface myInterface; private volatile LibraryInterface myInterface;
private Runnable myOnBindAction;
public BookCollectionShadow(Context context) { public BookCollectionShadow(Context context) {
myContext = context; myContext = context;
} }
public void bindToService() { public void bindToService(Runnable onBindAction) {
myOnBindAction = onBindAction;
myContext.bindService( myContext.bindService(
new Intent(myContext, LibraryService.class), new Intent(myContext, LibraryService.class),
this, this,
@ -44,6 +46,10 @@ public class BookCollectionShadow implements IBookCollection, ServiceConnection
); );
} }
public void unbind() {
myContext.unbindService(this);
}
public synchronized Book getBookById(long id) { public synchronized Book getBookById(long id) {
if (myInterface == null) { if (myInterface == null) {
return null; return null;
@ -69,6 +75,9 @@ public class BookCollectionShadow implements IBookCollection, ServiceConnection
// method from ServiceConnection interface // method from ServiceConnection interface
public synchronized void onServiceConnected(ComponentName name, IBinder service) { public synchronized void onServiceConnected(ComponentName name, IBinder service) {
myInterface = LibraryInterface.Stub.asInterface(service); myInterface = LibraryInterface.Stub.asInterface(service);
if (myOnBindAction != null) {
myOnBindAction.run();
}
} }
// method from ServiceConnection interface // method from ServiceConnection interface

View file

@ -24,10 +24,12 @@ import java.util.*;
import org.geometerplus.zlibrary.text.view.*; import org.geometerplus.zlibrary.text.view.*;
public final class Bookmark extends ZLTextFixedPosition { public final class Bookmark extends ZLTextFixedPosition {
public final static int CREATION = 0; public enum DateType {
public final static int MODIFICATION = 1; Creation,
public final static int ACCESS = 2; Modification,
public final static int LATEST = 3; Access,
Latest
}
private long myId; private long myId;
private final long myBookId; private final long myBookId;
@ -99,16 +101,16 @@ public final class Bookmark extends ZLTextFixedPosition {
return myBookTitle; return myBookTitle;
} }
public Date getTime(int timeStamp) { public Date getDate(DateType type) {
switch (timeStamp) { switch (type) {
default: case Creation:
case CREATION:
return myCreationDate; return myCreationDate;
case MODIFICATION: case Modification:
return myModificationDate; return myModificationDate;
case ACCESS: case Access:
return myAccessDate; return myAccessDate;
case LATEST: default:
case Latest:
return myLatestDate; return myLatestDate;
} }
} }
@ -148,7 +150,7 @@ public final class Bookmark extends ZLTextFixedPosition {
public static class ByTimeComparator implements Comparator<Bookmark> { public static class ByTimeComparator implements Comparator<Bookmark> {
public int compare(Bookmark bm0, Bookmark bm1) { public int compare(Bookmark bm0, Bookmark bm1) {
return bm1.getTime(LATEST).compareTo(bm0.getTime(LATEST)); return bm1.getDate(DateType.Latest).compareTo(bm0.getDate(DateType.Latest));
} }
} }

View file

@ -19,7 +19,9 @@
package org.geometerplus.fbreader.library; package org.geometerplus.fbreader.library;
import java.util.ArrayList; import java.util.*;
import java.text.DateFormat;
import java.text.ParseException;
import org.geometerplus.zlibrary.core.constants.XMLNamespaces; import org.geometerplus.zlibrary.core.constants.XMLNamespaces;
import org.geometerplus.zlibrary.core.filesystem.ZLFile; import org.geometerplus.zlibrary.core.filesystem.ZLFile;
@ -30,26 +32,26 @@ class XMLSerializer extends AbstractSerializer {
@Override @Override
public String serialize(Book book) { public String serialize(Book book) {
final StringBuilder buffer = new StringBuilder(); final StringBuilder buffer = new StringBuilder();
appendTagWithAttributes( appendTag(
buffer, "entry", false, buffer, "entry", false,
"xmlns:dc", XMLNamespaces.DublinCore, "xmlns:dc", XMLNamespaces.DublinCore,
"xmlns:calibre", XMLNamespaces.CalibreMetadata "xmlns:calibre", XMLNamespaces.CalibreMetadata
); );
appendTagWithContent(buffer, "id", String.valueOf(book.getId())); appendTagWithContent(buffer, "id", book.getId());
appendTagWithContent(buffer, "title", book.getTitle()); appendTagWithContent(buffer, "title", book.getTitle());
appendTagWithContent(buffer, "dc:language", book.getLanguage()); appendTagWithContent(buffer, "dc:language", book.getLanguage());
appendTagWithContent(buffer, "dc:encoding", book.getEncodingNoDetection()); appendTagWithContent(buffer, "dc:encoding", book.getEncodingNoDetection());
for (Author author : book.authors()) { for (Author author : book.authors()) {
buffer.append("<author>\n"); appendTag(buffer, "author", false);
appendTagWithContent(buffer, "uri", author.SortKey); appendTagWithContent(buffer, "uri", author.SortKey);
appendTagWithContent(buffer, "name", author.DisplayName); appendTagWithContent(buffer, "name", author.DisplayName);
buffer.append("</author>\n"); closeTag(buffer, "author");
} }
for (Tag tag : book.tags()) { for (Tag tag : book.tags()) {
appendTagWithAttributes( appendTag(
buffer, "category", true, buffer, "category", true,
"term", tag.toString("/"), "term", tag.toString("/"),
"label", tag.Name "label", tag.Name
@ -60,13 +62,13 @@ class XMLSerializer extends AbstractSerializer {
if (seriesInfo != null) { if (seriesInfo != null) {
appendTagWithContent(buffer, "calibre:series", seriesInfo.Title); appendTagWithContent(buffer, "calibre:series", seriesInfo.Title);
if (seriesInfo.Index != null) { if (seriesInfo.Index != null) {
appendTagWithContent(buffer, "calibre:series_index", String.valueOf(seriesInfo.Index)); appendTagWithContent(buffer, "calibre:series_index", seriesInfo.Index);
} }
} }
// TODO: serialize description (?) // TODO: serialize description (?)
// TODO: serialize cover (?) // TODO: serialize cover (?)
appendTagWithAttributes( appendTag(
buffer, "link", true, buffer, "link", true,
"href", book.File.getUrl(), "href", book.File.getUrl(),
// TODO: real book mimetype // TODO: real book mimetype
@ -74,27 +76,81 @@ class XMLSerializer extends AbstractSerializer {
"rel", "http://opds-spec.org/acquisition" "rel", "http://opds-spec.org/acquisition"
); );
buffer.append("</entry>\n"); closeTag(buffer, "entry");
return buffer.toString(); return buffer.toString();
} }
@Override @Override
public Book deserializeBook(String xml) { public Book deserializeBook(String xml) {
final Deserializer deserializer = new Deserializer(); final BookDeserializer deserializer = new BookDeserializer();
deserializer.readQuietly(xml); deserializer.readQuietly(xml);
return deserializer.getBook(); return deserializer.getBook();
} }
@Override @Override
public String serialize(Bookmark bookmark) { public String serialize(Bookmark bookmark) {
// TODO: implement final StringBuilder buffer = new StringBuilder();
return null; appendTag(
buffer, "bookmark", false,
"id", String.valueOf(bookmark.getId()),
"visible", String.valueOf(bookmark.IsVisible)
);
appendTag(
buffer, "book", true,
"id", String.valueOf(bookmark.getBookId()),
"title", bookmark.getBookTitle()
);
appendTagWithContent(buffer, "text", bookmark.getText());
appendTag(
buffer, "history", true,
"date-creation", formatDate(bookmark.getDate(Bookmark.DateType.Creation)),
"date-modification", formatDate(bookmark.getDate(Bookmark.DateType.Modification)),
"date-access", formatDate(bookmark.getDate(Bookmark.DateType.Access)),
"access-count", String.valueOf(bookmark.getAccessCount())
);
appendTag(
buffer, "position", true,
"model", bookmark.ModelId,
"paragraph", String.valueOf(bookmark.getParagraphIndex()),
"element", String.valueOf(bookmark.getElementIndex()),
"char", String.valueOf(bookmark.getCharIndex())
);
closeTag(buffer, "bookmark");
return buffer.toString();
} }
@Override @Override
public Bookmark deserializeBookmark(String xml) { public Bookmark deserializeBookmark(String xml) {
// TODO: implement final BookmarkDeserializer deserializer = new BookmarkDeserializer();
return null; deserializer.readQuietly(xml);
return deserializer.getBookmark();
}
private static DateFormat ourDateFormatter = DateFormat.getDateInstance(DateFormat.FULL, Locale.ENGLISH);
private static String formatDate(Date date) {
return date != null ? ourDateFormatter.format(date) : null;
}
private static Date parseDate(String str) throws ParseException {
return str != null ? ourDateFormatter.parse(str) : null;
}
private static void appendTag(StringBuilder buffer, String tag, boolean close, String ... attrs) {
buffer.append('<').append(tag);
for (int i = 0; i < attrs.length - 1; i += 2) {
if (attrs[i + 1] != null) {
buffer.append(' ')
.append(escapeForXml(attrs[i])).append("=\"")
.append(escapeForXml(attrs[i + 1])).append('"');
}
}
if (close) {
buffer.append('/');
}
buffer.append(">\n");
}
private static void closeTag(StringBuilder buffer, String tag) {
buffer.append("</").append(tag).append(">");
} }
private static void appendTagWithContent(StringBuilder buffer, String tag, String content) { private static void appendTagWithContent(StringBuilder buffer, String tag, String content) {
@ -106,17 +162,10 @@ class XMLSerializer extends AbstractSerializer {
} }
} }
private static void appendTagWithAttributes(StringBuilder buffer, String tag, boolean close, String ... attrs) { private static void appendTagWithContent(StringBuilder buffer, String tag, Object content) {
buffer.append('<').append(tag); if (content != null) {
for (int i = 0; i < attrs.length - 1; i += 2) { appendTagWithContent(buffer, tag, String.valueOf(content));
buffer.append(' ')
.append(escapeForXml(attrs[i])).append("=\"")
.append(escapeForXml(attrs[i + 1])).append('"');
} }
if (close) {
buffer.append('/');
}
buffer.append(">\n");
} }
private static String escapeForXml(String data) { private static String escapeForXml(String data) {
@ -138,7 +187,15 @@ class XMLSerializer extends AbstractSerializer {
return data; return data;
} }
private static final class Deserializer extends ZLXMLReaderAdapter { private static void clear(StringBuilder buffer) {
buffer.delete(0, buffer.length());
}
private static String string(StringBuilder buffer) {
return buffer.length() != 0 ? buffer.toString() : null;
}
private static final class BookDeserializer extends ZLXMLReaderAdapter {
private static enum State { private static enum State {
READ_NOTHING, READ_NOTHING,
READ_ENTRY, READ_ENTRY,
@ -157,15 +214,15 @@ class XMLSerializer extends AbstractSerializer {
private long myId = -1; private long myId = -1;
private String myUrl; private String myUrl;
private StringBuilder myTitle = new StringBuilder(); private final StringBuilder myTitle = new StringBuilder();
private StringBuilder myLanguage = new StringBuilder(); private final StringBuilder myLanguage = new StringBuilder();
private StringBuilder myEncoding = new StringBuilder(); private final StringBuilder myEncoding = new StringBuilder();
private ArrayList<Author> myAuthors = new ArrayList<Author>(); private final ArrayList<Author> myAuthors = new ArrayList<Author>();
private ArrayList<Tag> myTags = new ArrayList<Tag>(); private final ArrayList<Tag> myTags = new ArrayList<Tag>();
private StringBuilder myAuthorSortKey = new StringBuilder(); private final StringBuilder myAuthorSortKey = new StringBuilder();
private StringBuilder myAuthorName = new StringBuilder(); private final StringBuilder myAuthorName = new StringBuilder();
private StringBuilder mySeriesTitle = new StringBuilder(); private final StringBuilder mySeriesTitle = new StringBuilder();
private StringBuilder mySeriesIndex = new StringBuilder(); private final StringBuilder mySeriesIndex = new StringBuilder();
private Book myBook; private Book myBook;
@ -173,14 +230,6 @@ class XMLSerializer extends AbstractSerializer {
return myState == State.READ_NOTHING ? myBook : null; return myState == State.READ_NOTHING ? myBook : null;
} }
private static void clear(StringBuilder buffer) {
buffer.delete(0, buffer.length());
}
private static String string(StringBuilder buffer) {
return buffer.length() != 0 ? buffer.toString() : null;
}
@Override @Override
public void startDocumentHandler() { public void startDocumentHandler() {
myBook = null; myBook = null;
@ -332,4 +381,143 @@ class XMLSerializer extends AbstractSerializer {
} }
} }
} }
private static final class BookmarkDeserializer extends ZLXMLReaderAdapter {
private static enum State {
READ_NOTHING,
READ_BOOKMARK,
READ_TEXT
}
private State myState = State.READ_NOTHING;
private Bookmark myBookmark;
private long myId = -1;
private long myBookId;
private String myBookTitle;
private final StringBuilder myText = new StringBuilder();
private Date myCreationDate;
private Date myModificationDate;
private Date myAccessDate;
private int myAccessCount;
private String myModelId;
private int myParagraphIndex;
private int myElementIndex;
private int myCharIndex;
private boolean myIsVisible;
public Bookmark getBookmark() {
return myState == State.READ_NOTHING ? myBookmark : null;
}
@Override
public void startDocumentHandler() {
myBookmark = null;
myId = -1;
myBookId = -1;
myBookTitle = null;
clear(myText);
myCreationDate = null;
myModificationDate = null;
myAccessDate = null;
myAccessCount = 0;
myModelId = null;
myParagraphIndex = 0;
myElementIndex = 0;
myCharIndex = 0;
myIsVisible = false;
myState = State.READ_NOTHING;
}
@Override
public void endDocumentHandler() {
if (myId == -1 || myBookId == -1) {
return;
}
myBookmark = new Bookmark(
myId, myBookId, myBookTitle, myText.toString(),
myCreationDate, myModificationDate, myAccessDate, myAccessCount,
myModelId, myParagraphIndex, myElementIndex, myCharIndex, myIsVisible
);
}
//appendTagWithContent(buffer, "text", bookmark.getText());
@Override
public boolean startElementHandler(String tag, ZLStringMap attributes) {
switch (myState) {
case READ_NOTHING:
if (!"bookmark".equals(tag)) {
return true;
}
try {
myId = Long.parseLong(attributes.getValue("id"));
myIsVisible = Boolean.parseBoolean(attributes.getValue("visible"));
myState = State.READ_BOOKMARK;
} catch (Exception e) {
return true;
}
break;
case READ_BOOKMARK:
if ("book".equals(tag)) {
try {
myBookId = Long.parseLong(attributes.getValue("id"));
myBookTitle = attributes.getValue("title");
} catch (Exception e) {
return true;
}
} else if ("text".equals(tag)) {
myState = State.READ_TEXT;
} else if ("history".equals(tag)) {
try {
myCreationDate = parseDate(attributes.getValue("date-creation"));
myModificationDate = parseDate(attributes.getValue("date-modification"));
myAccessDate = parseDate(attributes.getValue("date-access"));
myAccessCount = Integer.parseInt(attributes.getValue("access-count"));
} catch (Exception e) {
return true;
}
} else if ("position".equals(tag)) {
try {
myModelId = attributes.getValue("model");
myParagraphIndex = Integer.parseInt(attributes.getValue("paragraph"));
myElementIndex = Integer.parseInt(attributes.getValue("element"));
myCharIndex = Integer.parseInt(attributes.getValue("char"));
} catch (Exception e) {
return true;
}
} else {
return true;
}
break;
case READ_TEXT:
return true;
}
return false;
}
@Override
public boolean endElementHandler(String tag) {
switch (myState) {
case READ_NOTHING:
return true;
case READ_BOOKMARK:
if ("bookmark".equals(tag)) {
myState = State.READ_NOTHING;
}
break;
case READ_TEXT:
myState = State.READ_BOOKMARK;
}
return false;
}
@Override
public void characterDataHandler(char[] ch, int start, int length) {
if (myState == State.READ_TEXT) {
myText.append(ch, start, length);
}
}
}
} }