diff --git a/data/resources/application/en.xml b/data/resources/application/en.xml index 13762f08f..44193ed7f 100644 --- a/data/resources/application/en.xml +++ b/data/resources/application/en.xml @@ -20,6 +20,9 @@ + + + @@ -250,8 +253,9 @@ - - + + + diff --git a/data/resources/application/ru.xml b/data/resources/application/ru.xml index a9d3bafa0..379fb4b16 100644 --- a/data/resources/application/ru.xml +++ b/data/resources/application/ru.xml @@ -253,6 +253,7 @@ + diff --git a/platform/android/res/layout/bookmarks.xml b/platform/android/res/layout/bookmarks.xml new file mode 100644 index 000000000..484e75692 --- /dev/null +++ b/platform/android/res/layout/bookmarks.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/platform/android/src/org/geometerplus/android/fbreader/BookmarksActivity.java b/platform/android/src/org/geometerplus/android/fbreader/BookmarksActivity.java index 860326e46..e3f8bb1b5 100644 --- a/platform/android/src/org/geometerplus/android/fbreader/BookmarksActivity.java +++ b/platform/android/src/org/geometerplus/android/fbreader/BookmarksActivity.java @@ -19,69 +19,119 @@ package org.geometerplus.android.fbreader; +import java.util.*; + import android.os.Bundle; import android.view.*; import android.widget.*; import android.content.Context; -import android.app.ListActivity; +import android.app.TabActivity; import android.graphics.drawable.Drawable; import org.geometerplus.zlibrary.core.resources.ZLResource; +import org.geometerplus.zlibrary.text.view.ZLTextPosition; import org.geometerplus.zlibrary.text.view.impl.*; import org.geometerplus.zlibrary.ui.android.R; +import org.geometerplus.zlibrary.core.resources.ZLResource; import org.geometerplus.fbreader.fbreader.FBReader; import org.geometerplus.fbreader.library.*; -public class BookmarksActivity extends ListActivity { +public class BookmarksActivity extends TabActivity { private static final int OPEN_ITEM_ID = 0; private static final int EDIT_ITEM_ID = 1; private static final int DELETE_ITEM_ID = 2; - private BookmarkList myBookmarks; + private List myAllBooksBookmarks; + private final List myThisBookBookmarks = new LinkedList(); + private final List mySearchResults = new LinkedList(); + + private ListView myThisBookView; + private ListView myAllBooksView; + private ListView mySearchResultsView; + + private final ZLResource myResource = ZLResource.resource("bookmarksView"); + + private ListView createTab(String tag, int id) { + final TabHost host = getTabHost(); + final String label = myResource.getResource(tag).getValue(); + host.addTab(host.newTabSpec(tag).setIndicator(label).setContent(id)); + return (ListView)findViewById(id); + } @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); + requestWindowFeature(Window.FEATURE_NO_TITLE); - myBookmarks = new BookmarkList(((FBReader)FBReader.Instance()).Model.Book); - final BookmarksAdapter adapter = new BookmarksAdapter(); - final ListView listView = getListView(); - listView.setAdapter(adapter); - listView.setOnItemClickListener(adapter); - listView.setOnCreateContextMenuListener(adapter); + setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); + + final TabHost host = getTabHost(); + LayoutInflater.from(this).inflate(R.layout.bookmarks, host.getTabContentView(), true); + + myAllBooksBookmarks = Bookmark.bookmarks(); + Collections.sort(myAllBooksBookmarks, new Bookmark.ByTimeComparator()); + final long bookId = ((FBReader)FBReader.Instance()).Model.Book.getId(); + for (Bookmark bookmark : myAllBooksBookmarks) { + if (bookmark.getBookId() == bookId) { + myThisBookBookmarks.add(bookmark); + } + } + + myThisBookView = createTab("thisBook", R.id.this_book); + new BookmarksAdapter(myThisBookView, myThisBookBookmarks, true); + + myAllBooksView = createTab("allBooks", R.id.all_books); + new BookmarksAdapter(myAllBooksView, myAllBooksBookmarks, false); + + findViewById(R.id.search_results).setVisibility(View.GONE); } @Override public void onPause() { - myBookmarks.save(); + for (Bookmark bookmark : myAllBooksBookmarks) { + bookmark.save(); + } super.onPause(); } + private void invalidateAllViews() { + myThisBookView.invalidateViews(); + myThisBookView.requestLayout(); + myAllBooksView.invalidateViews(); + myAllBooksView.requestLayout(); + } + @Override public boolean onContextItemSelected(MenuItem item) { final int position = ((AdapterView.AdapterContextMenuInfo)item.getMenuInfo()).position; + final ListView view = (ListView)getTabHost().getCurrentView(); + final Bookmark bookmark = ((BookmarksAdapter)view.getAdapter()).getItem(position); switch (item.getItemId()) { case OPEN_ITEM_ID: - gotoBookmark(position - 1); + gotoBookmark(bookmark); return true; case EDIT_ITEM_ID: // TODO: implement return true; case DELETE_ITEM_ID: - myBookmarks.removeBookmark(position - 1); - getListView().invalidateViews(); - getListView().requestLayout(); + bookmark.delete(); + myThisBookBookmarks.remove(bookmark); + myAllBooksBookmarks.remove(bookmark); + invalidateAllViews(); return true; } return super.onContextItemSelected(item); } private void addBookmark() { - ZLTextWordCursor cursor = ((FBReader)FBReader.Instance()).BookTextView.getStartCursor(); - if (!cursor.isNull()) { + final FBReader fbreader = (FBReader)FBReader.Instance(); + ZLTextWordCursor cursor = fbreader.BookTextView.getStartCursor(); + + if (cursor.isNull()) { // TODO: implement + return; } final ZLTextPosition position = new ZLTextPosition(cursor); @@ -107,18 +157,44 @@ mainLoop: } while ((builder.length() == 0) && cursor.nextParagraph()); // TODO: text edit dialog - myBookmarks.addNewBookmark(builder.toString(), position); - getListView().invalidateViews(); - getListView().requestLayout(); + final Bookmark bookmark = new Bookmark(fbreader.Model.Book, builder.toString(), position); + myThisBookBookmarks.add(0, bookmark); + myAllBooksBookmarks.add(0, bookmark); + invalidateAllViews(); } - private void gotoBookmark(int index) { - myBookmarks.gotoBookmark(index, ((FBReader)FBReader.Instance()).BookTextView); - finish(); + private void gotoBookmark(Bookmark bookmark) { + bookmark.onOpen(); + final FBReader fbreader = (FBReader)FBReader.Instance(); + final long bookId = bookmark.getBookId(); + if (fbreader.Model.Book.getId() != bookId) { + final Book book = Book.getById(bookId); + if (book != null) { + finish(); + fbreader.openBook(book, bookmark.getPosition()); + } else { + Toast.makeText( + this, + ZLResource.resource("errorMessage").getResource("cannotOpenBook").getValue(), + Toast.LENGTH_SHORT + ).show(); + } + } else { + finish(); + fbreader.BookTextView.gotoPosition(bookmark.getPosition()); + } } private final class BookmarksAdapter extends BaseAdapter implements AdapterView.OnItemClickListener, View.OnCreateContextMenuListener { - BookmarksAdapter() { + private final List myBookmarks; + private final boolean myShowAddBookmarkButton; + + BookmarksAdapter(ListView listView, List bookmarks, boolean showAddBookmarkButton) { + myBookmarks = bookmarks; + myShowAddBookmarkButton = showAddBookmarkButton; + listView.setAdapter(this); + listView.setOnItemClickListener(this); + listView.setOnCreateContextMenuListener(this); } public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { @@ -135,12 +211,13 @@ mainLoop: public View getView(int position, View convertView, ViewGroup parent) { final View view = (convertView != null) ? convertView : LayoutInflater.from(parent.getContext()).inflate(R.layout.bookmark_item, parent, false); + final Bookmark bookmark = getItem(position); ((ImageView)view.findViewById(R.id.bookmark_item_icon)).setImageResource( - (position > 0) ? R.drawable.tree_icon_strut : R.drawable.tree_icon_plus + (bookmark != null) ? R.drawable.tree_icon_strut : R.drawable.tree_icon_plus ); ((TextView)view.findViewById(R.id.bookmark_item_text)).setText( - (position > 0) ? - getItem(position).getText() : + (bookmark != null) ? + bookmark.getText() : ZLResource.resource("bookmarksView").getResource("new").getValue() ); return view; @@ -159,18 +236,22 @@ mainLoop: } public final Bookmark getItem(int position) { - return (position > 0) ? myBookmarks.get(position - 1) : null; + if (myShowAddBookmarkButton) { + --position; + } + return (position >= 0) ? myBookmarks.get(position) : null; } public final int getCount() { - return myBookmarks.size() + 1; + return myShowAddBookmarkButton ? myBookmarks.size() + 1 : myBookmarks.size(); } public final void onItemClick(AdapterView parent, View view, int position, long id) { - if (position == 0) { - addBookmark(); + final Bookmark bookmark = getItem(position); + if (bookmark != null) { + gotoBookmark(bookmark); } else { - gotoBookmark(position - 1); + addBookmark(); } } } diff --git a/platform/android/src/org/geometerplus/android/fbreader/LibraryTabActivity.java b/platform/android/src/org/geometerplus/android/fbreader/LibraryTabActivity.java index 8b353120e..3b9e675d6 100644 --- a/platform/android/src/org/geometerplus/android/fbreader/LibraryTabActivity.java +++ b/platform/android/src/org/geometerplus/android/fbreader/LibraryTabActivity.java @@ -37,8 +37,8 @@ public class LibraryTabActivity extends TabActivity implements MenuItem.OnMenuIt static LibraryTabActivity Instance; final ZLStringOption mySelectedTabOption = new ZLStringOption("TabActivity", "SelectedTab", ""); - private ZLResource myResource = ZLResource.resource("libraryView"); - + private final ZLResource myResource = ZLResource.resource("libraryView"); + private ListView createTab(String tag, int id) { final TabHost host = getTabHost(); final String label = myResource.getResource(tag).getValue(); @@ -147,7 +147,7 @@ public class LibraryTabActivity extends TabActivity implements MenuItem.OnMenuIt } finish(); final FBReader fbreader = (FBReader)FBReader.Instance(); - fbreader.openBook(((BookTree)tree).Book); + fbreader.openBook(((BookTree)tree).Book, null); return true; } } diff --git a/platform/android/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java b/platform/android/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java index fa9a8e900..9702b4906 100644 --- a/platform/android/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java +++ b/platform/android/src/org/geometerplus/android/fbreader/SQLiteBooksDatabase.java @@ -30,7 +30,7 @@ import android.database.Cursor; import org.geometerplus.zlibrary.core.filesystem.ZLFile; import org.geometerplus.zlibrary.core.dialogs.ZLDialogManager; import org.geometerplus.zlibrary.core.options.ZLStringOption; -import org.geometerplus.zlibrary.text.view.impl.ZLTextPosition; +import org.geometerplus.zlibrary.text.view.ZLTextPosition; import org.geometerplus.zlibrary.ui.android.library.ZLAndroidApplication; import org.geometerplus.fbreader.library.*; @@ -110,25 +110,28 @@ final class SQLiteBooksDatabase extends BooksDatabase { return new Date(cursor.getLong(index)); } - private static final String BOOKS_TABLE = "Books"; - private static final String[] BOOKS_COLUMNS = { "book_id", "encoding", "language", "title" }; - private static final String FILE_NAME_CONDITION = "file_name = ?"; - protected long loadBook(Book book) { - final Cursor cursor = myDatabase.query( - BOOKS_TABLE, - BOOKS_COLUMNS, - FILE_NAME_CONDITION, new String[] { book.File.getPath() }, - null, null, null, null - ); - long id = -1; + protected Book loadBook(long bookId) { + Book book = null; + final Cursor cursor = myDatabase.rawQuery("SELECT file_name,title,encoding,language FROM Books WHERE book_id = " + bookId, null); if (cursor.moveToNext()) { - id = cursor.getLong(0); - book.setEncoding(cursor.getString(1)); - book.setLanguage(cursor.getString(2)); - book.setTitle(cursor.getString(3)); + book = createBook( + bookId, cursor.getString(0), cursor.getString(1), cursor.getString(2), cursor.getString(3) + ); } cursor.close(); - return id; + return book; + } + + protected Book loadBook(String fileName) { + Book book = null; + final Cursor cursor = myDatabase.rawQuery("SELECT book_id,title,encoding,language FROM Books WHERE file_name = ?", new String[] { fileName }); + if (cursor.moveToNext()) { + book = createBook( + cursor.getLong(0), fileName, cursor.getString(1), cursor.getString(2), cursor.getString(3) + ); + } + cursor.close(); + return book; } private boolean myTagCacheIsInitialized; @@ -625,39 +628,102 @@ final class SQLiteBooksDatabase extends BooksDatabase { return ids; } - private SQLiteStatement myDeleteBookmarksStatement; + protected List listBookmarks(long bookId) { + LinkedList list = new LinkedList(); + Cursor cursor = myDatabase.rawQuery( + "SELECT bookmark_id,book_id,bookmark_text,creation_time,modification_time,access_time,access_counter,paragraph,word,char FROM Bookmarks WHERE book_id = ?", new String[] { "" + bookId } + ); + while (cursor.moveToNext()) { + list.add(createBookmark( + cursor.getLong(0), + cursor.getLong(1), + cursor.getString(2), + getDate(cursor, 3), + getDate(cursor, 4), + getDate(cursor, 5), + (int)cursor.getLong(6), + (int)cursor.getLong(7), + (int)cursor.getLong(8), + (int)cursor.getLong(9) + )); + } + cursor.close(); + return list; + } + + protected List listAllBookmarks() { + LinkedList list = new LinkedList(); + Cursor cursor = myDatabase.rawQuery( + "SELECT bookmark_id,book_id,bookmark_text,creation_time,modification_time,access_time,access_counter,paragraph,word,char FROM Bookmarks", null + ); + while (cursor.moveToNext()) { + list.add(createBookmark( + cursor.getLong(0), + cursor.getLong(1), + cursor.getString(2), + getDate(cursor, 3), + getDate(cursor, 4), + getDate(cursor, 5), + (int)cursor.getLong(6), + (int)cursor.getLong(7), + (int)cursor.getLong(8), + (int)cursor.getLong(9) + )); + } + cursor.close(); + return list; + } + private SQLiteStatement myInsertBookmarkStatement; - protected void saveBookmarks(final long bookId, final List list) { - if (myDeleteBookmarksStatement == null) { - myDeleteBookmarksStatement = myDatabase.compileStatement( - "DELETE FROM Bookmarks WHERE book_id = ?" - ); - myInsertBookmarkStatement = myDatabase.compileStatement( - "INSERT INTO Bookmarks (book_id,bookmark_text,creation_time,modification_time,access_time,access_counter,paragraph,word,char) VALUES (?,?,?,?,?,?,?,?,?)" + private SQLiteStatement myUpdateBookmarkStatement; + protected long saveBookmark(Bookmark bookmark) { + SQLiteStatement statement; + if (bookmark.getId() == -1) { + if (myInsertBookmarkStatement == null) { + myInsertBookmarkStatement = myDatabase.compileStatement( + "INSERT INTO Bookmarks (book_id,bookmark_text,creation_time,modification_time,access_time,access_counter,paragraph,word,char) VALUES (?,?,?,?,?,?,?,?,?)" + ); + } + statement = myInsertBookmarkStatement; + } else { + if (myUpdateBookmarkStatement == null) { + myUpdateBookmarkStatement = myDatabase.compileStatement( + "UPDATE Bookmarks SET book_id = ?, bookmark_text = ?, creation_time =?, modification_time = ?,access_time = ?, access_counter = ?, paragraph = ?, word = ?, char = ? WHERE bookmark_id = ?" + ); + } + statement = myUpdateBookmarkStatement; + } + + statement.bindLong(1, bookmark.getBookId()); + statement.bindString(2, bookmark.getText()); + bindDate(statement, 3, bookmark.getTime(Bookmark.CREATION)); + bindDate(statement, 4, bookmark.getTime(Bookmark.MODIFICATION)); + bindDate(statement, 5, bookmark.getTime(Bookmark.ACCESS)); + statement.bindLong(6, bookmark.getAccessCount()); + final ZLTextPosition position = bookmark.getPosition(); + statement.bindLong(7, position.ParagraphIndex); + statement.bindLong(8, position.WordIndex); + statement.bindLong(9, position.CharIndex); + + if (statement == myInsertBookmarkStatement) { + return statement.executeInsert(); + } else { + final long id = bookmark.getId(); + statement.bindLong(10, id); + statement.execute(); + return id; + } + } + + private SQLiteStatement myDeleteBookmarkStatement; + protected void deleteBookmark(Bookmark bookmark) { + if (myDeleteBookmarkStatement == null) { + myDeleteBookmarkStatement = myDatabase.compileStatement( + "DELETE FROM Bookmarks WHERE bookmark_id = ?" ); } - executeAsATransaction(new Runnable() { - public void run() { - myDeleteBookmarksStatement.bindLong(1, bookId); - myDeleteBookmarksStatement.execute(); - if (list.isEmpty()) { - return; - } - myInsertBookmarkStatement.bindLong(1, bookId); - for (Bookmark bookmark : list) { - myInsertBookmarkStatement.bindString(2, bookmark.getText()); - bindDate(myInsertBookmarkStatement, 3, bookmark.getTime(Bookmark.CREATION)); - bindDate(myInsertBookmarkStatement, 4, bookmark.getTime(Bookmark.MODIFICATION)); - bindDate(myInsertBookmarkStatement, 5, bookmark.getTime(Bookmark.ACCESS)); - myInsertBookmarkStatement.bindLong(6, bookmark.getAccessCount()); - final ZLTextPosition position = bookmark.getPosition(); - myInsertBookmarkStatement.bindLong(7, position.ParagraphIndex); - myInsertBookmarkStatement.bindLong(8, position.WordIndex); - myInsertBookmarkStatement.bindLong(9, position.CharIndex); - myInsertBookmarkStatement.execute(); - } - } - }); + myDeleteBookmarkStatement.bindLong(1, bookmark.getId()); + myDeleteBookmarkStatement.execute(); } private void createTables() { @@ -772,6 +838,7 @@ final class SQLiteBooksDatabase extends BooksDatabase { private void updateTables5() { myDatabase.execSQL( "CREATE TABLE Bookmarks(" + + "bookmark_id INTEGER PRIMARY KEY," + "book_id INTEGER NOT NULL REFERENCES Books(book_id)," + "bookmark_text TEXT NOT NULL," + "creation_time INTEGER NOT NULL," + @@ -785,23 +852,4 @@ final class SQLiteBooksDatabase extends BooksDatabase { private void updateTables6() { } - - protected void listBookmarks(long bookId, List list) { - Cursor cursor = myDatabase.rawQuery( - "SELECT bookmark_text,creation_time,modification_time,access_time,access_counter,paragraph,word,char FROM Bookmarks WHERE book_id = ?", new String[] { "" + bookId } - ); - while (cursor.moveToNext()) { - list.add(createBookmark( - cursor.getString(0), - getDate(cursor, 1), - getDate(cursor, 2), - getDate(cursor, 3), - (int)cursor.getLong(4), - (int)cursor.getLong(5), - (int)cursor.getLong(6), - (int)cursor.getLong(7) - )); - } - cursor.close(); - } } diff --git a/src/org/geometerplus/fbreader/fbreader/BookTextView.java b/src/org/geometerplus/fbreader/fbreader/BookTextView.java index 8776e5406..00a145470 100644 --- a/src/org/geometerplus/fbreader/fbreader/BookTextView.java +++ b/src/org/geometerplus/fbreader/fbreader/BookTextView.java @@ -29,6 +29,7 @@ import org.geometerplus.zlibrary.core.options.*; import org.geometerplus.zlibrary.core.config.ZLConfig; import org.geometerplus.zlibrary.core.view.ZLPaintContext; import org.geometerplus.zlibrary.text.model.ZLTextModel; +import org.geometerplus.zlibrary.text.view.ZLTextPosition; import org.geometerplus.zlibrary.text.view.impl.*; public class BookTextView extends FBView { diff --git a/src/org/geometerplus/fbreader/fbreader/FBReader.java b/src/org/geometerplus/fbreader/fbreader/FBReader.java index 1c7344118..399956ead 100644 --- a/src/org/geometerplus/fbreader/fbreader/FBReader.java +++ b/src/org/geometerplus/fbreader/fbreader/FBReader.java @@ -33,6 +33,7 @@ import org.geometerplus.zlibrary.core.view.ZLViewWidget; import org.geometerplus.zlibrary.text.model.ZLTextModel; import org.geometerplus.zlibrary.text.view.ZLTextView; +import org.geometerplus.zlibrary.text.view.ZLTextPosition; import org.geometerplus.zlibrary.text.hyphenation.ZLTextHyphenator; import org.geometerplus.fbreader.bookmodel.BookModel; @@ -125,10 +126,10 @@ public final class FBReader extends ZLApplication { ); } - public void openBook(final Book book) { + public void openBook(final Book book, final ZLTextPosition position) { ZLDialogManager.Instance().wait("loadingBook", new Runnable() { public void run() { - openBookInternal(book); + openBookInternal(book, position); } }); } @@ -206,7 +207,7 @@ public final class FBReader extends ZLApplication { FootnoteView.clearCaches(); } - void openBookInternal(Book book) { + void openBookInternal(Book book, ZLTextPosition position) { clearTextCaches(); if (book != null) { @@ -222,6 +223,9 @@ public final class FBReader extends ZLApplication { ZLTextHyphenator.Instance().load(book.getLanguage()); BookTextView.setModel(Model.BookTextModel, fileName); BookTextView.setCaption(book.getTitle()); + if (position != null) { + BookTextView.gotoPosition(position); + } FootnoteView.setModel(null); FootnoteView.setCaption(book.getTitle()); Library.Instance().addBookToRecentList(book); @@ -243,13 +247,13 @@ main: if (f == null) { continue; } - book = Book.getBook(f); + book = Book.getByFile(f); if (book != null) { break; } if (f.isArchive()) { for (ZLFile child : f.children()) { - book = Book.getBook(child); + book = Book.getByFile(child); if (book != null) { break main; } @@ -257,7 +261,7 @@ main: } } if (book != null) { - openBookInternal(book); + openBookInternal(book, null); } } }); diff --git a/src/org/geometerplus/fbreader/library/Book.java b/src/org/geometerplus/fbreader/library/Book.java index adc848337..4683b4f0c 100644 --- a/src/org/geometerplus/fbreader/library/Book.java +++ b/src/org/geometerplus/fbreader/library/Book.java @@ -27,7 +27,32 @@ import org.geometerplus.zlibrary.core.filesystem.*; import org.geometerplus.fbreader.formats.*; public class Book { - public static Book getBook(ZLFile bookFile) { + public static Book getById(long bookId) { + final Book book = BooksDatabase.Instance().loadBook(bookId); + if (book == null) { + return null; + } + book.loadLists(); + + final ZLPhysicalFile physicalFile = book.File.getPhysicalFile(); + if (physicalFile == null) { + return book; + } + if (!physicalFile.exists()) { + return null; + } + + FileInfoSet fileInfos = new FileInfoSet(); + fileInfos.load(physicalFile); + if (fileInfos.check(physicalFile)) { + return book; + } + fileInfos.save(); + + return book.readMetaInfo() ? book : null; + } + + public static Book getByFile(ZLFile bookFile) { if (bookFile == null) { return null; } @@ -37,25 +62,22 @@ public class Book { return null; } - final Book book = new Book(bookFile, true); + Book book = BooksDatabase.Instance().loadBook(bookFile.getPath()); + if (book != null) { + book.loadLists(); + } FileInfoSet fileInfos = new FileInfoSet(); fileInfos.load(physicalFile); - if (fileInfos.check(physicalFile) && book.myIsSaved) { + if (fileInfos.check(physicalFile) && (book != null)) { return book; } fileInfos.save(); - final FormatPlugin plugin = PluginCollection.instance().getPlugin(bookFile); - if ((plugin == null) || !plugin.readMetaInfo(book)) { - return null; + if (book == null) { + book = new Book(bookFile); } - - String title = book.getTitle(); - if ((title == null) || (title.length() == 0)) { - book.setTitle(bookFile.getName(true)); - } - return book; + return book.readMetaInfo() ? book : null; } public final ZLFile File; @@ -80,20 +102,28 @@ public class Book { myIsSaved = true; } - Book(ZLFile file, boolean createFromDatabase) { + Book(ZLFile file) { + myId = -1; File = file; - if (createFromDatabase) { - final BooksDatabase database = BooksDatabase.Instance(); - myId = database.loadBook(this); - if (myId >= 0) { - myAuthors = database.loadAuthors(myId); - myTags = database.loadTags(myId); - mySeriesInfo = database.loadSeriesInfo(myId); - myIsSaved = true; - } - } else { - myId = -1; + } + + boolean readMetaInfo() { + final FormatPlugin plugin = PluginCollection.instance().getPlugin(File); + if ((plugin == null) || !plugin.readMetaInfo(this)) { + return false; } + if ((myTitle == null) || (myTitle.length() == 0)) { + setTitle(File.getName(true)); + } + return true; + } + + private void loadLists() { + final BooksDatabase database = BooksDatabase.Instance(); + myAuthors = database.loadAuthors(myId); + myTags = database.loadTags(myId); + mySeriesInfo = database.loadSeriesInfo(myId); + myIsSaved = true; } public List authors() { diff --git a/src/org/geometerplus/fbreader/library/Bookmark.java b/src/org/geometerplus/fbreader/library/Bookmark.java index 95205bc28..b9b5ecae5 100644 --- a/src/org/geometerplus/fbreader/library/Bookmark.java +++ b/src/org/geometerplus/fbreader/library/Bookmark.java @@ -19,35 +19,65 @@ package org.geometerplus.fbreader.library; -import java.util.Date; +import java.util.*; -import org.geometerplus.zlibrary.text.view.impl.ZLTextPosition; +import org.geometerplus.zlibrary.text.view.ZLTextPosition; public class Bookmark { public final static int CREATION = 0; public final static int MODIFICATION = 1; public final static int ACCESS = 2; + public final static int LATEST = 3; + public static List bookmarks() { + return BooksDatabase.Instance().listAllBookmarks(); + } + + private long myId; + private long myBookId; private String myText; private final Date myCreationDate; private Date myModificationDate; private Date myAccessDate; private int myAccessCount; + private Date myLatestDate; private final ZLTextPosition myPosition; - Bookmark(String text, Date creationDate, Date modificationDate, Date accessDate, int accessCount, int paragraphIndex, int wordIndex, int charIndex) { + private boolean myIsChanged; + + Bookmark(long id, long bookId, String text, Date creationDate, Date modificationDate, Date accessDate, int accessCount, int paragraphIndex, int wordIndex, int charIndex) { + myId = id; + myBookId = bookId; myText = text; myCreationDate = creationDate; myModificationDate = modificationDate; - myAccessDate = accessDate; + myLatestDate = (modificationDate != null) ? modificationDate : creationDate; + if (accessDate != null) { + myAccessDate = accessDate; + if (myLatestDate.compareTo(accessDate) < 0) { + myLatestDate = accessDate; + } + } myAccessCount = accessCount; myPosition = new ZLTextPosition(paragraphIndex, wordIndex, charIndex); + myIsChanged = false; } - public Bookmark(String text, ZLTextPosition position) { + public Bookmark(Book book, String text, ZLTextPosition position) { + myId = -1; + myBookId = book.getId(); myText = text; myCreationDate = new Date(); myPosition = position; + myIsChanged = true; + } + + public long getId() { + return myId; + } + + public long getBookId() { + return myBookId; } public String getText() { @@ -67,6 +97,8 @@ public class Bookmark { return myModificationDate; case ACCESS: return myAccessDate; + case LATEST: + return myLatestDate; } } @@ -74,17 +106,44 @@ public class Bookmark { return myAccessCount; } - boolean setText(String text) { + public void setText(String text) { if (!text.equals(myText)) { myText = text; myModificationDate = new Date(); - return true; + myLatestDate = myModificationDate; + myIsChanged = true; } - return false; } - void onAccess() { + public void onOpen() { myAccessDate = new Date(); ++myAccessCount; + myLatestDate = myAccessDate; + myIsChanged = true; + } + + public void save() { + if (myIsChanged) { + myId = BooksDatabase.Instance().saveBookmark(this); + myIsChanged = false; + } + } + + public void delete() { + if (myId != -1) { + BooksDatabase.Instance().deleteBookmark(this); + } + } + + public static class ByTimeComparator implements Comparator { + public int compare(Bookmark bm0, Bookmark bm1) { + return bm1.getTime(LATEST).compareTo(bm0.getTime(LATEST)); + } + } + + public static class ByPositionComparator implements Comparator { + public int compare(Bookmark bm0, Bookmark bm1) { + return bm0.getPosition().compareTo(bm1.getPosition()); + } } } diff --git a/src/org/geometerplus/fbreader/library/BookmarkList.java b/src/org/geometerplus/fbreader/library/BookmarkList.java deleted file mode 100644 index 37cb2afe0..000000000 --- a/src/org/geometerplus/fbreader/library/BookmarkList.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2009 Geometer Plus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -package org.geometerplus.fbreader.library; - -import java.util.LinkedList; - -import org.geometerplus.zlibrary.text.view.impl.ZLTextPosition; -import org.geometerplus.zlibrary.text.view.impl.ZLTextViewImpl; - -public class BookmarkList extends LinkedList { - private final Book myBook; - private boolean myIsChanged; - - public BookmarkList(Book book) { - myBook = book; - BooksDatabase.Instance().listBookmarks(book.getId(), this); - } - - public void addNewBookmark(String text, ZLTextPosition position) { - add(0, new Bookmark(text, position)); - myIsChanged = true; - } - - public void removeBookmark(int index) { - remove(index); - myIsChanged = true; - } - - public void setBookmarkText(int index, String text) { - if (get(index).setText(text)) { - myIsChanged = true; - } - } - - public void gotoBookmark(int index, ZLTextViewImpl view) { - myIsChanged = true; - final Bookmark bookmark = get(index); - bookmark.onAccess(); - view.gotoPosition(bookmark.getPosition()); - } - - public void save() { - if (!myIsChanged) { - return; - } - BooksDatabase.Instance().saveBookmarks(myBook.getId(), this); - myIsChanged = false; - } -} diff --git a/src/org/geometerplus/fbreader/library/BooksDatabase.java b/src/org/geometerplus/fbreader/library/BooksDatabase.java index 9a3be2bb1..1ba5b2db4 100644 --- a/src/org/geometerplus/fbreader/library/BooksDatabase.java +++ b/src/org/geometerplus/fbreader/library/BooksDatabase.java @@ -49,7 +49,8 @@ public abstract class BooksDatabase { protected abstract Map listBooks(); protected abstract void executeAsATransaction(Runnable actions); - protected abstract long loadBook(Book book); + protected abstract Book loadBook(long bookId); + protected abstract Book loadBook(String fileName); protected abstract List loadAuthors(long bookId); protected abstract List loadTags(long bookId); protected abstract SeriesInfo loadSeriesInfo(long bookId); @@ -74,10 +75,12 @@ public abstract class BooksDatabase { protected abstract List listRecentBookIds(); protected abstract void saveRecentBookIds(final List ids); - protected Bookmark createBookmark(String text, Date creationDate, Date modificationDate, Date accessDate, int accessCounter, int paragraphIndex, int wordIndex, int charIndex) { - return new Bookmark(text, creationDate, modificationDate, accessDate, accessCounter, paragraphIndex, wordIndex, charIndex); + protected Bookmark createBookmark(long id, long bookId, String text, Date creationDate, Date modificationDate, Date accessDate, int accessCounter, int paragraphIndex, int wordIndex, int charIndex) { + return new Bookmark(id, bookId, text, creationDate, modificationDate, accessDate, accessCounter, paragraphIndex, wordIndex, charIndex); } - protected abstract void listBookmarks(long bookId, List list); - protected abstract void saveBookmarks(long bookId, List list); + protected abstract List listBookmarks(long bookId); + protected abstract List listAllBookmarks(); + protected abstract long saveBookmark(Bookmark bookmark); + protected abstract void deleteBookmark(Bookmark bookmark); } diff --git a/src/org/geometerplus/fbreader/library/Library.java b/src/org/geometerplus/fbreader/library/Library.java index 1b8b76298..9053e53c6 100644 --- a/src/org/geometerplus/fbreader/library/Library.java +++ b/src/org/geometerplus/fbreader/library/Library.java @@ -25,8 +25,6 @@ import java.util.*; import org.geometerplus.zlibrary.core.filesystem.*; import org.geometerplus.zlibrary.core.library.ZLibrary; -import org.geometerplus.fbreader.formats.*; - public final class Library { private static Library ourInstance; @@ -76,18 +74,11 @@ public final class Library { Book book = saved.get(bookFile.getPath()); if (book == null) { doReadMetaInfo = true; - book = new Book(bookFile, false); + book = new Book(bookFile); } - if (doReadMetaInfo) { - final FormatPlugin plugin = PluginCollection.instance().getPlugin(book.File); - if ((plugin == null) || !plugin.readMetaInfo(book)) { - return null; - } - String title = book.getTitle(); - if ((title == null) || (title.length() == 0)) { - book.setTitle(bookFile.getName(true)); - } + if (doReadMetaInfo && !book.readMetaInfo()) { + return null; } return book; } diff --git a/src/org/geometerplus/zlibrary/core/html/own/ZLOwnHtmlParser.java b/src/org/geometerplus/zlibrary/core/html/own/ZLOwnHtmlParser.java index 28b0d72e0..2a0b60036 100644 --- a/src/org/geometerplus/zlibrary/core/html/own/ZLOwnHtmlParser.java +++ b/src/org/geometerplus/zlibrary/core/html/own/ZLOwnHtmlParser.java @@ -95,7 +95,7 @@ final class ZLOwnHtmlParser { if (index > 0) { int startIndex; for (startIndex = description.indexOf("=", index) + 1; - !CharacterUtil.isLetter(description.charAt(startIndex)); + !Character.isLetter(description.charAt(startIndex)); startIndex++) { } if (startIndex > 0) { diff --git a/src/org/geometerplus/zlibrary/core/util/CharacterUtil.java b/src/org/geometerplus/zlibrary/core/util/ZLCharacterUtil.java similarity index 70% rename from src/org/geometerplus/zlibrary/core/util/CharacterUtil.java rename to src/org/geometerplus/zlibrary/core/util/ZLCharacterUtil.java index ea9a35b06..b19f77468 100644 --- a/src/org/geometerplus/zlibrary/core/util/CharacterUtil.java +++ b/src/org/geometerplus/zlibrary/core/util/ZLCharacterUtil.java @@ -19,7 +19,7 @@ package org.geometerplus.zlibrary.core.util; -public abstract class CharacterUtil { +public abstract class ZLCharacterUtil { public static boolean isLetter(char ch) { return (('a' <= ch) && (ch <= 'z')) || @@ -37,27 +37,4 @@ public abstract class CharacterUtil { // cyrillic YO & yo (ch == 0x401) || (ch == 0x451); } - - public static char toLowerCase(char ch) { - if (ch < 'A') return ch; - if (ch <= 'Z') return (char)(ch + 'a' - 'A'); - - // latin1 - if (ch < 0xC0) return ch; - if (ch == 0xD7) return ch; - if (ch <= 0xDE) return (char)(ch + 0x20); - - // extended latin1 - if (ch < 0x100) return ch; - if (ch <= 0x178) return ((ch & 0x01) == 0x01) ? ch : (char)(ch + 1); - - // cyrillic - if (ch < 0x410) return ch; - if (ch <= 0x42F) return (char)(ch + 0x20); - - // cyrillic yo - if (ch == 0x401) return 0x451; - - return ch; - } } diff --git a/src/org/geometerplus/zlibrary/text/hyphenation/ZLTextHyphenator.java b/src/org/geometerplus/zlibrary/text/hyphenation/ZLTextHyphenator.java index 31112fdfc..20771aeb6 100644 --- a/src/org/geometerplus/zlibrary/text/hyphenation/ZLTextHyphenator.java +++ b/src/org/geometerplus/zlibrary/text/hyphenation/ZLTextHyphenator.java @@ -55,9 +55,9 @@ public abstract class ZLTextHyphenator { pattern[0] = ' '; for (int i = 0, j = word.Offset; i < len; ++i, ++j) { char symbol = data[j]; - if (CharacterUtil.isLetter(symbol)) { + if (ZLCharacterUtil.isLetter(symbol)) { isLetter[i] = true; - pattern[i + 1] = CharacterUtil.toLowerCase(symbol); + pattern[i + 1] = Character.toLowerCase(symbol); } else { pattern[i + 1] = ' '; } diff --git a/src/org/geometerplus/zlibrary/text/view/impl/ZLTextPosition.java b/src/org/geometerplus/zlibrary/text/view/ZLTextPosition.java similarity index 76% rename from src/org/geometerplus/zlibrary/text/view/impl/ZLTextPosition.java rename to src/org/geometerplus/zlibrary/text/view/ZLTextPosition.java index 889a4329b..99067f4d2 100644 --- a/src/org/geometerplus/zlibrary/text/view/impl/ZLTextPosition.java +++ b/src/org/geometerplus/zlibrary/text/view/ZLTextPosition.java @@ -17,9 +17,11 @@ * 02110-1301, USA. */ -package org.geometerplus.zlibrary.text.view.impl; +package org.geometerplus.zlibrary.text.view; -public final class ZLTextPosition { +import org.geometerplus.zlibrary.text.view.impl.ZLTextWordCursor; + +public final class ZLTextPosition implements Comparable { public int ParagraphIndex; public int WordIndex; public int CharIndex; @@ -47,5 +49,15 @@ public final class ZLTextPosition { (ParagraphIndex == cursor.getParagraphCursor().Index) && (WordIndex == cursor.getWordIndex()) && (CharIndex == cursor.getCharIndex()); - } + } + + public int compareTo(ZLTextPosition position) { + if (ParagraphIndex != position.ParagraphIndex) { + return ParagraphIndex - position.ParagraphIndex; + } + if (WordIndex != position.WordIndex) { + return WordIndex - position.WordIndex; + } + return CharIndex - position.CharIndex; + } } diff --git a/src/org/geometerplus/zlibrary/text/view/ZLTextView.java b/src/org/geometerplus/zlibrary/text/view/ZLTextView.java index 1338ebc32..c29d75286 100644 --- a/src/org/geometerplus/zlibrary/text/view/ZLTextView.java +++ b/src/org/geometerplus/zlibrary/text/view/ZLTextView.java @@ -39,6 +39,8 @@ public abstract class ZLTextView extends ZLView { public abstract void setModel(ZLTextModel model); + public abstract void gotoPosition(ZLTextPosition position); + public abstract void scrollPage(boolean forward, int scrollingMode, int value); public abstract int search(String text, boolean ignoreCase, boolean wholeText, boolean backward, boolean thisSectionOnly);