diff --git a/TODO.network b/TODO.network index 8bf20aee0..09ff9e795 100644 --- a/TODO.network +++ b/TODO.network @@ -15,6 +15,7 @@ DONE Возможность открывать локальные файлы и DONE На этой странице есть ссылка на epub-файл "для ПК". http://www.zone4iphone.ru/index.php?p_id=7&b_id=18413 Проверить скачивание книги браузером и возможность чтения из папки, куда файл был скачан. ** добавлять в библиотеку (сделать таблицу добавленных вручную книг) + ** сделать новый диалог удаления файлов (удаление файла / удаление из библиотеки) ------------------------------ diff --git a/src/org/geometerplus/android/fbreader/LibraryTabActivity.java b/src/org/geometerplus/android/fbreader/LibraryTabActivity.java index 5174c5b27..b7bb56d0b 100644 --- a/src/org/geometerplus/android/fbreader/LibraryTabActivity.java +++ b/src/org/geometerplus/android/fbreader/LibraryTabActivity.java @@ -173,7 +173,8 @@ public class LibraryTabActivity extends TabActivity implements MenuItem.OnMenuIt menu.setHeaderTitle(tree.getName()); final ZLResource resource = ZLResource.resource("libraryView"); menu.add(0, OPEN_BOOK_ITEM_ID, 0, resource.getResource("openBook").getValue()); - if (Library.Instance().canDeleteBook(((BookTree)tree).Book)) { + if ((Library.Instance().getRemoveBookMode(((BookTree)tree).Book) + & Library.REMOVE_FROM_DISK) != 0) { menu.add(0, DELETE_BOOK_ITEM_ID, 0, resource.getResource("deleteBook").getValue()); } } @@ -263,9 +264,11 @@ public class LibraryTabActivity extends TabActivity implements MenuItem.OnMenuIt private class BookDeleter implements DialogInterface.OnClickListener { private final Book myBook; + private final int myMode; - BookDeleter(Book book) { + BookDeleter(Book book, int removeMode) { myBook = book; + myMode = removeMode; } private void invalidateView(View v) { @@ -276,7 +279,7 @@ public class LibraryTabActivity extends TabActivity implements MenuItem.OnMenuIt } public void onClick(DialogInterface dialog, int which) { - Library.Instance().deleteBook(myBook); + Library.Instance().removeBook(myBook, myMode); invalidateView(findViewById(R.id.by_author)); invalidateView(findViewById(R.id.by_tag)); @@ -293,7 +296,7 @@ public class LibraryTabActivity extends TabActivity implements MenuItem.OnMenuIt .setTitle(book.getTitle()) .setMessage(boxResource.getResource("message").getValue()) .setIcon(0) - .setPositiveButton(buttonResource.getResource("yes").getValue(), new BookDeleter(book)) + .setPositiveButton(buttonResource.getResource("yes").getValue(), new BookDeleter(book, Library.REMOVE_FROM_DISK)) .setNegativeButton(buttonResource.getResource("no").getValue(), null) .create().show(); } diff --git a/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java b/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java index 3fe1192f7..80850a67a 100644 --- a/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java +++ b/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java @@ -58,7 +58,8 @@ final class SQLiteBooksDatabase extends BooksDatabase { private void migrate() { final int version = myDatabase.getVersion(); - if (version >= 8) { + final int currentVersion = 9; + if (version >= currentVersion) { return; } ZLDialogManager.Instance().wait((version == 0) ? "creatingBooksDatabase" : "updatingBooksDatabase", new Runnable() { @@ -82,12 +83,14 @@ final class SQLiteBooksDatabase extends BooksDatabase { updateTables6(); case 7: updateTables7(); + case 8: + updateTables8(); } myDatabase.setTransactionSuccessful(); myDatabase.endTransaction(); myDatabase.execSQL("VACUUM"); - myDatabase.setVersion(8); + myDatabase.setVersion(currentVersion); } }); } @@ -768,6 +771,42 @@ final class SQLiteBooksDatabase extends BooksDatabase { myStorePositionStatement.execute(); } + private SQLiteStatement myInsertIntoBookListStatement; + protected boolean insertIntoBookList(long bookId) { + if (myInsertIntoBookListStatement == null) { + myInsertIntoBookListStatement = myDatabase.compileStatement( + "INSERT OR IGNORE INTO BookList(book_id) VALUES (?)" + ); + } + myInsertIntoBookListStatement.bindLong(1, bookId); + myInsertIntoBookListStatement.execute(); + return true; + } + + private SQLiteStatement myDeleteFromBookListStatement; + protected boolean deleteFromBookList(long bookId) { + if (myDeleteFromBookListStatement == null) { + myDeleteFromBookListStatement = myDatabase.compileStatement( + "DELETE FROM BookList WHERE book_id = ?" + ); + } + myDeleteFromBookListStatement.bindLong(1, bookId); + myDeleteFromBookListStatement.execute(); + return true; + } + + private SQLiteStatement myCheckBookListStatement; + protected boolean checkBookList(long bookId) { + if (myCheckBookListStatement == null) { + myCheckBookListStatement = myDatabase.compileStatement( + "SELECT COUNT(*) FROM BookList WHERE book_id = ?" + ); + } + myCheckBookListStatement.bindLong(1, bookId); + return myCheckBookListStatement.simpleQueryForLong() > 0; + } + + private void createTables() { myDatabase.execSQL( "CREATE TABLE Books(" + @@ -1014,4 +1053,10 @@ final class SQLiteBooksDatabase extends BooksDatabase { myDatabase.execSQL("DELETE FROM BookTag WHERE book_id=" + id); } } + + private void updateTables8() { + myDatabase.execSQL( + "CREATE TABLE IF NOT EXISTS BookList ( " + + "book_id INTEGER UNIQUE NOT NULL REFERENCES Books (book_id))"); + } } diff --git a/src/org/geometerplus/fbreader/fbreader/FBReader.java b/src/org/geometerplus/fbreader/fbreader/FBReader.java index 204886877..f051b9b7f 100644 --- a/src/org/geometerplus/fbreader/fbreader/FBReader.java +++ b/src/org/geometerplus/fbreader/fbreader/FBReader.java @@ -234,6 +234,7 @@ public final class FBReader extends ZLApplication { } Book book = Book.getByFile(file); if (book != null) { + book.insertIntoBookList(); return book; } if (file.isArchive()) { diff --git a/src/org/geometerplus/fbreader/library/Book.java b/src/org/geometerplus/fbreader/library/Book.java index 3d5d41009..098fc45bd 100644 --- a/src/org/geometerplus/fbreader/library/Book.java +++ b/src/org/geometerplus/fbreader/library/Book.java @@ -73,7 +73,7 @@ public class Book { book.loadLists(); } - if (fileInfos.check(physicalFile) && (book != null)) { + if (book != null && fileInfos.check(physicalFile)) { return book; } fileInfos.save(); @@ -346,6 +346,12 @@ public class Book { } } + public void insertIntoBookList() { + if (myId != -1) { + BooksDatabase.Instance().insertIntoBookList(myId); + } + } + @Override public int hashCode() { return (int)myId; diff --git a/src/org/geometerplus/fbreader/library/BooksDatabase.java b/src/org/geometerplus/fbreader/library/BooksDatabase.java index ad3264d3e..e65a43036 100644 --- a/src/org/geometerplus/fbreader/library/BooksDatabase.java +++ b/src/org/geometerplus/fbreader/library/BooksDatabase.java @@ -95,4 +95,8 @@ public abstract class BooksDatabase { protected abstract ZLTextPosition getStoredPosition(long bookId); protected abstract void storePosition(long bookId, ZLTextPosition position); + + protected abstract boolean insertIntoBookList(long bookId); + protected abstract boolean deleteFromBookList(long bookId); + protected abstract boolean checkBookList(long bookId); } diff --git a/src/org/geometerplus/fbreader/library/Library.java b/src/org/geometerplus/fbreader/library/Library.java index d338f555e..f0b3b1449 100644 --- a/src/org/geometerplus/fbreader/library/Library.java +++ b/src/org/geometerplus/fbreader/library/Library.java @@ -38,6 +38,7 @@ public final class Library { } private final LinkedList myBooks = new LinkedList(); + private final HashSet myExternalBooks = new HashSet(); private final LibraryTree myLibraryByAuthor = new RootTree(); private final LibraryTree myLibraryByTag = new RootTree(); private final LibraryTree myRecentBooks = new RootTree(); @@ -52,6 +53,7 @@ public final class Library { myDoRebuild = true; myBooks.clear(); + myExternalBooks.clear(); myLibraryByAuthor.clear(); myLibraryByTag.clear(); myRecentBooks.clear(); @@ -70,7 +72,7 @@ public final class Library { } private static Book getBook(ZLFile bookFile, FileInfoSet fileInfos, Map saved, boolean doReadMetaInfo) { - Book book = saved.get(fileInfos.getId(bookFile)); + Book book = saved.remove(fileInfos.getId(bookFile)); if (book == null) { doReadMetaInfo = true; book = new Book(bookFile); @@ -98,6 +100,33 @@ public final class Library { } } + private void collectExternalBooks(FileInfoSet fileInfos, Map savedBooks) { + final HashSet myUpdatedFiles = new HashSet(); + final HashSet files = new HashSet(savedBooks.keySet()); + for (Long fileId: files) { + final ZLFile bookFile = fileInfos.getFile(fileId); + if (bookFile == null) { + continue; + } + final ZLPhysicalFile physicalFile = bookFile.getPhysicalFile(); + if (!physicalFile.exists()) { + continue; + } + boolean reloadMetaInfo = false; + if (myUpdatedFiles.contains(physicalFile)) { + reloadMetaInfo = true; + } else if (!fileInfos.check(physicalFile)) { + reloadMetaInfo = true; + myUpdatedFiles.add(physicalFile); + } + final Book book = getBook(bookFile, fileInfos, savedBooks, reloadMetaInfo); + if (book != null) { + myBooks.add(book); + myExternalBooks.add(book); + } + } + } + private List collectPhysicalFiles() { final Queue dirQueue = new LinkedList(); final HashSet dirSet = new HashSet(); @@ -147,6 +176,8 @@ public final class Library { //android.os.Debug.stopMethodTracing(); //System.err.println("books have been synchronized " + (System.currentTimeMillis() - start)); + collectExternalBooks(fileInfos, savedBooks); + //android.os.Debug.startMethodTracing("/sdcard/ll4"); fileInfos.save(); //android.os.Debug.stopMethodTracing(); @@ -315,7 +346,18 @@ public final class Library { db.saveRecentBookIds(ids); } - public boolean canDeleteBook(Book book) { + public static final int REMOVE_DONT_REMOVE = 0x00; + public static final int REMOVE_FROM_LIBRARY = 0x01; + public static final int REMOVE_FROM_DISK = 0x02; + public static final int REMOVE_FROM_LIBRARY_AND_DISK = REMOVE_FROM_LIBRARY | REMOVE_FROM_DISK; + + public int getRemoveBookMode(Book book) { + synchronize(); + return (myExternalBooks.contains(book) ? REMOVE_FROM_LIBRARY : REMOVE_DONT_REMOVE) + | (canDeleteBookFile(book) ? REMOVE_FROM_DISK : REMOVE_DONT_REMOVE); + } + + private boolean canDeleteBookFile(Book book) { ZLFile file = book.File; if (file.getPhysicalFile() == null) { return false; @@ -329,7 +371,10 @@ public final class Library { return true; } - public void deleteBook(Book book) { + public void removeBook(Book book, int removeMode) { + if (removeMode == REMOVE_DONT_REMOVE) { + return; + } synchronize(); myBooks.remove(book); myLibraryByAuthor.removeBook(book); @@ -341,6 +386,10 @@ public final class Library { db.saveRecentBookIds(ids); } mySearchResult.removeBook(book); - book.File.getPhysicalFile().delete(); + + BooksDatabase.Instance().deleteFromBookList(book.getId()); + if ((removeMode & REMOVE_FROM_DISK) != 0) { + book.File.getPhysicalFile().delete(); + } } }