From 3d3e770d9f0bee88b69a40a686ca6ba558da4277 Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Tue, 13 Jan 2015 15:09:39 +0100 Subject: [PATCH] BookHistory table + new style recent books request --- .../libraryService/LibraryService.java | 2 +- .../libraryService/SQLiteBooksDatabase.java | 119 ++++++++++++------ .../fbreader/book/AbstractBookCollection.java | 5 - src/org/geometerplus/fbreader/book/Book.java | 16 ++- .../fbreader/book/BookCollection.java | 23 +--- .../fbreader/book/BooksDatabase.java | 10 +- .../fbreader/book/IBookCollection.java | 5 - .../fbreader/library/RecentBooksTree.java | 2 +- 8 files changed, 109 insertions(+), 73 deletions(-) diff --git a/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java b/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java index 7e3e7d80c..52b182e53 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java +++ b/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java @@ -181,7 +181,7 @@ public class LibraryService extends Service { } public List recentBooks() { - return SerializerUtil.serializeBookList(myCollection.recentBooks()); + return recentlyOpenedBooks(12); } public List recentlyOpenedBooks(int count) { diff --git a/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java b/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java index 8c0d8551f..7c0f49742 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java +++ b/src/org/geometerplus/android/fbreader/libraryService/SQLiteBooksDatabase.java @@ -29,7 +29,6 @@ import android.database.Cursor; import org.geometerplus.zlibrary.core.options.Config; import org.geometerplus.zlibrary.core.filesystem.ZLFile; -import org.geometerplus.zlibrary.core.options.ZLStringOption; import org.geometerplus.zlibrary.core.options.ZLIntegerOption; import org.geometerplus.zlibrary.core.util.RationalNumber; import org.geometerplus.zlibrary.core.util.ZLColor; @@ -76,7 +75,7 @@ final class SQLiteBooksDatabase extends BooksDatabase { private void migrate() { final int version = myDatabase.getVersion(); - final int currentVersion = 29; + final int currentVersion = 30; if (version >= currentVersion) { return; } @@ -142,6 +141,8 @@ final class SQLiteBooksDatabase extends BooksDatabase { updateTables27(); case 28: updateTables28(); + case 29: + updateTables29(); } myDatabase.setTransactionSuccessful(); myDatabase.setVersion(currentVersion); @@ -725,30 +726,43 @@ final class SQLiteBooksDatabase extends BooksDatabase { return infos; } - protected void saveRecentBookIds(final List ids) { + @Override + protected void addBookHistoryEvent(long bookId, int event) { final SQLiteStatement statement = get( - "INSERT OR IGNORE INTO RecentBooks (book_id) VALUES (?)" + "INSERT INTO BookHistory (book_id,timestamp,event) VALUES (?,?,?)" ); - executeAsTransaction(new Runnable() { - public void run() { - myDatabase.delete("RecentBooks", null, null); - for (long id : ids) { - statement.bindLong(1, id); - statement.execute(); - } - } - }); + synchronized (statement) { + statement.bindLong(1, bookId); + statement.bindLong(2, System.currentTimeMillis()); + statement.bindLong(3, event); + statement.executeInsert(); + } } @Override - protected List loadRecentBookIds() { + protected void removeBookHistoryEvents(long bookId, int event) { + final SQLiteStatement statement = get( + "DELETE FROM BookHistory WHERE book_id=? and event=?" + ); + synchronized (statement) { + statement.bindLong(1, bookId); + statement.bindLong(2, event); + statement.executeInsert(); + } + } + + @Override + protected List loadRecentBookIds(int event, int limit) { + System.err.println("REQUESTED: " + event + " LIMIT " + limit); final Cursor cursor = myDatabase.rawQuery( - "SELECT book_id FROM RecentBooks ORDER BY book_index", null + "SELECT book_id FROM BookHistory WHERE event=? GROUP BY book_id ORDER BY timestamp DESC LIMIT ?", + new String[] { String.valueOf(event), String.valueOf(limit) } ); final LinkedList ids = new LinkedList(); while (cursor.moveToNext()) { ids.add(cursor.getLong(0)); } + System.err.println("RESULT: " + ids); cursor.close(); return ids; } @@ -1054,6 +1068,7 @@ final class SQLiteBooksDatabase extends BooksDatabase { @Override protected void deleteBook(long bookId) { myDatabase.beginTransaction(); + myDatabase.execSQL("DELETE FROM BookHistory WHERE book_id=" + bookId); myDatabase.execSQL("DELETE FROM BookHash WHERE book_id=" + bookId); myDatabase.execSQL("DELETE FROM BookAuthor WHERE book_id=" + bookId); myDatabase.execSQL("DELETE FROM BookLabel WHERE book_id=" + bookId); @@ -1063,7 +1078,6 @@ final class SQLiteBooksDatabase extends BooksDatabase { myDatabase.execSQL("DELETE FROM BookTag WHERE book_id=" + bookId); myDatabase.execSQL("DELETE FROM BookUid WHERE book_id=" + bookId); myDatabase.execSQL("DELETE FROM Bookmarks WHERE book_id=" + bookId); - myDatabase.execSQL("DELETE FROM RecentBooks WHERE book_id=" + bookId); myDatabase.execSQL("DELETE FROM VisitedHyperlinks WHERE book_id=" + bookId); myDatabase.execSQL("DELETE FROM Books WHERE book_id=" + bookId); myDatabase.setTransactionSuccessful(); @@ -1165,26 +1179,6 @@ final class SQLiteBooksDatabase extends BooksDatabase { "CREATE TABLE IF NOT EXISTS RecentBooks(" + "book_index INTEGER PRIMARY KEY," + "book_id INTEGER REFERENCES Books(book_id))"); - final ArrayList ids = new ArrayList(); - - final SQLiteStatement statement = myDatabase.compileStatement( - "SELECT book_id FROM Books WHERE file_name = ?" - ); - - for (int i = 0; i < 20; ++i) { - final ZLStringOption option = new ZLStringOption("LastOpenedBooks", "Book" + i, ""); - final String fileName = option.getValue(); - option.setValue(""); - try { - statement.bindString(1, fileName); - final long bookId = statement.simpleQueryForLong(); - if (bookId != -1) { - ids.add(bookId); - } - } catch (SQLException e) { - } - } - saveRecentBookIds(ids); } private void updateTables5() { @@ -1477,12 +1471,12 @@ final class SQLiteBooksDatabase extends BooksDatabase { } private void updateTables26() { - myDatabase.execSQL("DROP TABLE IF EXISTS BookSynchronizationInfo"); myDatabase.execSQL( "CREATE TABLE IF NOT EXISTS BookHash(" + "book_id INTEGER PRIMARY KEY REFERENCES Books(book_id)," + "timestamp INTEGER NOT NULL," + - "hash TEXT(40) NOT NULL)"); + "hash TEXT(40) NOT NULL)" + ); } private void updateTables27() { @@ -1493,6 +1487,55 @@ final class SQLiteBooksDatabase extends BooksDatabase { myDatabase.execSQL("ALTER TABLE HighlightingStyle ADD COLUMN fg_color INTEGER NOT NULL DEFAULT -1"); } + private void updateTables29() { + myDatabase.execSQL("DROP TABLE IF EXISTS BookHistory"); + myDatabase.execSQL( + "CREATE TABLE IF NOT EXISTS BookHistory(" + + "book_id INTEGER REFERENCES Books(book_id)," + + "timestamp INTEGER NOT NULL," + + "event INTEGER NOT NULL)" + ); + + Cursor cursor = myDatabase.rawQuery( + "SELECT book_id FROM RecentBooks ORDER BY book_index", null + ); + SQLiteStatement insert = myDatabase.compileStatement( + "INSERT INTO BookHistory(book_id,timestamp,event) VALUES (?,?,?)" + ); + insert.bindLong(3, HistoryEvent.Opened); + int count = -1; + while (cursor.moveToNext()) { + insert.bindLong(1, cursor.getLong(0)); + insert.bindLong(2, count); + insert.executeInsert(); + --count; + } + cursor.close(); + + cursor = myDatabase.rawQuery( + "SELECT book_id FROM Books ORDER BY book_id DESC", null + ); + insert = myDatabase.compileStatement( + "INSERT INTO BookHistory(book_id,timestamp,event) VALUES (?,?,?)" + ); + insert.bindLong(3, HistoryEvent.Added); + while (cursor.moveToNext()) { + insert.bindLong(1, cursor.getLong(0)); + insert.bindLong(2, count); + insert.executeInsert(); + --count; + } + cursor.close(); + + cursor = myDatabase.rawQuery( + "SELECT book_id,timestamp,event FROM BookHistory", null + ); + while (cursor.moveToNext()) { + System.err.println("HISTORY RECORD: " + cursor.getLong(0) + " : " + cursor.getLong(1) + " : " + cursor.getLong(2)); + } + cursor.close(); + } + private SQLiteStatement get(String sql) { SQLiteStatement statement = myStatements.get(sql); if (statement == null) { diff --git a/src/org/geometerplus/fbreader/book/AbstractBookCollection.java b/src/org/geometerplus/fbreader/book/AbstractBookCollection.java index cb7a8e5e9..e6cb93f14 100644 --- a/src/org/geometerplus/fbreader/book/AbstractBookCollection.java +++ b/src/org/geometerplus/fbreader/book/AbstractBookCollection.java @@ -59,9 +59,4 @@ public abstract class AbstractBookCollection implements IBookCollection { public final Book getBookByFile(String path) { return getBookByFile(ZLFile.createFileByPath(path)); } - - // deprecated methods - public final List recentBooks() { - return recentlyOpenedBooks(12); - } } diff --git a/src/org/geometerplus/fbreader/book/Book.java b/src/org/geometerplus/fbreader/book/Book.java index 93157ddda..eb24b49a3 100644 --- a/src/org/geometerplus/fbreader/book/Book.java +++ b/src/org/geometerplus/fbreader/book/Book.java @@ -506,6 +506,7 @@ public class Book extends TitledEntity { return false; } + final boolean[] result = new boolean[] { true }; database.executeAsTransaction(new Runnable() { public void run() { if (myId >= 0) { @@ -513,11 +514,16 @@ public class Book extends TitledEntity { database.updateBookInfo(myId, fileInfos.getId(File), myEncoding, myLanguage, getTitle()); } else { myId = database.insertBookInfo(File, myEncoding, myLanguage, getTitle()); - if (myId != -1 && myVisitedHyperlinks != null) { + if (myId == -1) { + result[0] = false; + return; + } + if (myVisitedHyperlinks != null) { for (String linkId : myVisitedHyperlinks) { database.addVisitedHyperlink(myId, linkId); } } + database.addBookHistoryEvent(myId, BooksDatabase.HistoryEvent.Added); } long index = 0; @@ -551,8 +557,12 @@ public class Book extends TitledEntity { } }); - myIsSaved = true; - return true; + if (result[0]) { + myIsSaved = true; + return true; + } else { + return false; + } } private Set myVisitedHyperlinks; diff --git a/src/org/geometerplus/fbreader/book/BookCollection.java b/src/org/geometerplus/fbreader/book/BookCollection.java index 2d888f4b4..e82ecef24 100644 --- a/src/org/geometerplus/fbreader/book/BookCollection.java +++ b/src/org/geometerplus/fbreader/book/BookCollection.java @@ -233,10 +233,6 @@ public class BookCollection extends AbstractBookCollection { myDuplicateResolver.removeFile(book.File); myBooksById.remove(book.getId()); - final List ids = myDatabase.loadRecentBookIds(); - if (ids.remove(book.getId())) { - myDatabase.saveRecentBookIds(ids); - } if (deleteFromDisk) { book.File.getPhysicalFile().delete(); } @@ -302,13 +298,11 @@ public class BookCollection extends AbstractBookCollection { } public List recentlyAddedBooks(int count) { - // TODO: implement - return books(myDatabase.loadRecentBookIds()); + return books(myDatabase.loadRecentBookIds(BooksDatabase.HistoryEvent.Added, count)); } public List recentlyOpenedBooks(int count) { - // TODO: implement - return books(myDatabase.loadRecentBookIds()); + return books(myDatabase.loadRecentBookIds(BooksDatabase.HistoryEvent.Opened, count)); } private List books(List ids) { @@ -404,24 +398,17 @@ public class BookCollection extends AbstractBookCollection { } public Book getRecentBook(int index) { - final List recentIds = myDatabase.loadRecentBookIds(); + final List recentIds = myDatabase.loadRecentBookIds(BooksDatabase.HistoryEvent.Opened, index + 1); return recentIds.size() > index ? getBookById(recentIds.get(index)) : null; } public void addToRecentlyOpened(Book book) { - final List ids = myDatabase.loadRecentBookIds(); - final Long bookId = book.getId(); - ids.remove(bookId); - ids.add(0, bookId); - if (ids.size() > 12) { - ids.remove(12); - } - myDatabase.saveRecentBookIds(ids); + myDatabase.addBookHistoryEvent(book.getId(), BooksDatabase.HistoryEvent.Opened); fireBookEvent(BookEvent.Opened, book); } public void removeFromRecentlyOpened(Book book) { - // TODO: implement + myDatabase.removeBookHistoryEvents(book.getId(), BooksDatabase.HistoryEvent.Opened); } private void setStatus(Status status) { diff --git a/src/org/geometerplus/fbreader/book/BooksDatabase.java b/src/org/geometerplus/fbreader/book/BooksDatabase.java index a71755135..d96a434ea 100644 --- a/src/org/geometerplus/fbreader/book/BooksDatabase.java +++ b/src/org/geometerplus/fbreader/book/BooksDatabase.java @@ -29,6 +29,11 @@ import org.geometerplus.zlibrary.text.view.ZLTextFixedPosition; import org.geometerplus.zlibrary.text.view.ZLTextPosition; public abstract class BooksDatabase { + protected interface HistoryEvent { + int Added = 0; + int Opened = 1; + } + public static final class NotAvailable extends Exception { } @@ -89,8 +94,9 @@ public abstract class BooksDatabase { protected abstract void removeFileInfo(long fileId); protected abstract void saveFileInfo(FileInfo fileInfo); - protected abstract List loadRecentBookIds(); - protected abstract void saveRecentBookIds(final List ids); + protected abstract void addBookHistoryEvent(long bookId, int event); + protected abstract void removeBookHistoryEvents(long bookId, int event); + protected abstract List loadRecentBookIds(int event, int limit); protected abstract void setLabel(long bookId, String label); protected abstract void removeLabel(long bookId, String label); diff --git a/src/org/geometerplus/fbreader/book/IBookCollection.java b/src/org/geometerplus/fbreader/book/IBookCollection.java index b708b1e84..f223232a1 100644 --- a/src/org/geometerplus/fbreader/book/IBookCollection.java +++ b/src/org/geometerplus/fbreader/book/IBookCollection.java @@ -100,9 +100,4 @@ public interface IBookCollection { void saveHighlightingStyle(HighlightingStyle style); void rescan(String path); - - // deprecated methods, kept for compatibility - - // shortcut to recentlyOpenedBooks(12) - List recentBooks(); } diff --git a/src/org/geometerplus/fbreader/library/RecentBooksTree.java b/src/org/geometerplus/fbreader/library/RecentBooksTree.java index 35912ae9e..b340fe4a3 100644 --- a/src/org/geometerplus/fbreader/library/RecentBooksTree.java +++ b/src/org/geometerplus/fbreader/library/RecentBooksTree.java @@ -34,7 +34,7 @@ public class RecentBooksTree extends FirstLevelTree { @Override public void waitForOpening() { clear(); - for (Book book : Collection.recentBooks()) { + for (Book book : Collection.recentlyOpenedBooks(12)) { new BookWithAuthorsTree(this, book); } }