diff --git a/src/org/geometerplus/android/fbreader/library/BaseActivity.java b/src/org/geometerplus/android/fbreader/library/BaseActivity.java index 6f61eff3d..a019d950d 100644 --- a/src/org/geometerplus/android/fbreader/library/BaseActivity.java +++ b/src/org/geometerplus/android/fbreader/library/BaseActivity.java @@ -55,12 +55,6 @@ abstract class BaseActivity extends ListActivity { static final String TREE_PATH_KEY = "TreePath"; static final String PARAMETER_KEY = "Parameter"; - static final String PATH_FAVORITES = "favorites"; - static final String PATH_SEARCH_RESULTS = "searchResults"; - static final String PATH_RECENT = "recent"; - static final String PATH_BY_AUTHOR = "byAuthor"; - static final String PATH_BY_TITLE = "byTitle"; - static final String PATH_BY_TAG = "byTag"; static final String PATH_FILE_TREE = "fileTree"; static BooksDatabase DatabaseInstance; diff --git a/src/org/geometerplus/android/fbreader/library/FileItem.java b/src/org/geometerplus/android/fbreader/library/FileItem.java index 36117c829..33c416ae4 100644 --- a/src/org/geometerplus/android/fbreader/library/FileItem.java +++ b/src/org/geometerplus/android/fbreader/library/FileItem.java @@ -68,6 +68,11 @@ class FileItem extends FBTree { return myName != null ? myName : myFile.getShortName(); } + @Override + protected String getStringId() { + return myFile.getPath(); + } + @Override public String getSummary() { if (mySummary != null) { diff --git a/src/org/geometerplus/android/fbreader/library/LibraryTopLevelActivity.java b/src/org/geometerplus/android/fbreader/library/LibraryTopLevelActivity.java index caea984f6..6cfbe778d 100644 --- a/src/org/geometerplus/android/fbreader/library/LibraryTopLevelActivity.java +++ b/src/org/geometerplus/android/fbreader/library/LibraryTopLevelActivity.java @@ -29,6 +29,7 @@ import android.view.Window; import org.geometerplus.zlibrary.ui.android.R; import org.geometerplus.fbreader.tree.FBTree; +import org.geometerplus.fbreader.library.Library; import org.geometerplus.android.util.UIUtil; @@ -43,9 +44,10 @@ public class LibraryTopLevelActivity extends LibraryBaseActivity { final ListAdapter adapter = new ListAdapter(this, new LinkedList()); adapter.add(new TopLevelTree( - myResource.getResource(PATH_FAVORITES), + Library.ROOT_FAVORITES, + myResource.getResource(Library.ROOT_FAVORITES), R.drawable.ic_list_library_favorites, - new OpenTreeRunnable(LibraryInstance, new StartTreeActivityRunnable(PATH_FAVORITES, null) { + new OpenTreeRunnable(LibraryInstance, new StartTreeActivityRunnable(Library.ROOT_FAVORITES, null) { public void run() { if (LibraryInstance.favorites().hasChildren()) { super.run(); @@ -55,11 +57,12 @@ public class LibraryTopLevelActivity extends LibraryBaseActivity { } }) )); - addTopLevelTree(PATH_RECENT, R.drawable.ic_list_library_recent); - addTopLevelTree(PATH_BY_AUTHOR, R.drawable.ic_list_library_authors); - addTopLevelTree(PATH_BY_TITLE, R.drawable.ic_list_library_books); - addTopLevelTree(PATH_BY_TAG, R.drawable.ic_list_library_tags); + addTopLevelTree(Library.ROOT_RECENT, R.drawable.ic_list_library_recent); + addTopLevelTree(Library.ROOT_BY_AUTHOR, R.drawable.ic_list_library_authors); + addTopLevelTree(Library.ROOT_BY_TITLE, R.drawable.ic_list_library_books); + addTopLevelTree(Library.ROOT_BY_TAG, R.drawable.ic_list_library_tags); adapter.add(new TopLevelTree( + PATH_FILE_TREE, myResource.getResource(PATH_FILE_TREE), R.drawable.ic_list_library_folder, new Runnable() { @@ -78,6 +81,7 @@ public class LibraryTopLevelActivity extends LibraryBaseActivity { private void addTopLevelTree(String key, int imageId) { getListAdapter().add(new TopLevelTree( + key, myResource.getResource(key), imageId, new OpenTreeRunnable(LibraryInstance, key) @@ -95,10 +99,11 @@ public class LibraryTopLevelActivity extends LibraryBaseActivity { adapter.remove(mySearchResultsItem); final String pattern = intent.getStringExtra(SearchManager.QUERY); mySearchResultsItem = new TopLevelTree( - myResource.getResource(PATH_SEARCH_RESULTS), + Library.ROOT_SEARCH_RESULTS, + myResource.getResource(Library.ROOT_SEARCH_RESULTS), pattern, R.drawable.ic_list_library_books, - new OpenTreeRunnable(LibraryInstance, PATH_SEARCH_RESULTS, pattern) + new OpenTreeRunnable(LibraryInstance, Library.ROOT_SEARCH_RESULTS, pattern) ); adapter.add(0, mySearchResultsItem); getListView().invalidateViews(); diff --git a/src/org/geometerplus/android/fbreader/library/LibraryTreeActivity.java b/src/org/geometerplus/android/fbreader/library/LibraryTreeActivity.java index b82b396fe..a2414379c 100644 --- a/src/org/geometerplus/android/fbreader/library/LibraryTreeActivity.java +++ b/src/org/geometerplus/android/fbreader/library/LibraryTreeActivity.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.os.Bundle; import org.geometerplus.fbreader.tree.FBTree; +import org.geometerplus.fbreader.library.Library; public class LibraryTreeActivity extends LibraryBaseActivity { @Override @@ -62,17 +63,17 @@ public class LibraryTreeActivity extends LibraryBaseActivity { setTitle(title); FBTree tree = null; - if (PATH_RECENT.equals(myTreePath[0])) { + if (Library.ROOT_RECENT.equals(myTreePath[0])) { tree = LibraryInstance.recentBooks(); - } else if (PATH_SEARCH_RESULTS.equals(myTreePath[0])) { + } else if (Library.ROOT_SEARCH_RESULTS.equals(myTreePath[0])) { tree = LibraryInstance.searchResults(); - } else if (PATH_BY_AUTHOR.equals(myTreePath[0])) { + } else if (Library.ROOT_BY_AUTHOR.equals(myTreePath[0])) { tree = LibraryInstance.byAuthor(); - } else if (PATH_BY_TITLE.equals(myTreePath[0])) { + } else if (Library.ROOT_BY_TITLE.equals(myTreePath[0])) { tree = LibraryInstance.byTitle(); - } else if (PATH_BY_TAG.equals(myTreePath[0])) { + } else if (Library.ROOT_BY_TAG.equals(myTreePath[0])) { tree = LibraryInstance.byTag(); - } else if (PATH_FAVORITES.equals(myTreePath[0])) { + } else if (Library.ROOT_FAVORITES.equals(myTreePath[0])) { tree = LibraryInstance.favorites(); } diff --git a/src/org/geometerplus/android/fbreader/library/TopLevelTree.java b/src/org/geometerplus/android/fbreader/library/TopLevelTree.java index cba8f282f..4a91da91f 100644 --- a/src/org/geometerplus/android/fbreader/library/TopLevelTree.java +++ b/src/org/geometerplus/android/fbreader/library/TopLevelTree.java @@ -26,20 +26,22 @@ import org.geometerplus.fbreader.tree.FBTree; import org.geometerplus.android.fbreader.tree.ZLAndroidTree; class TopLevelTree extends FBTree implements ZLAndroidTree { + private final String myId; private final ZLResource myResource; private final String myParameter; private final int myCoverResourceId; private final Runnable myAction; - public TopLevelTree(ZLResource resource, String parameter, int coverResourceId, Runnable action) { + public TopLevelTree(String id, ZLResource resource, String parameter, int coverResourceId, Runnable action) { + myId = id; myResource = resource; myParameter = parameter; myCoverResourceId = coverResourceId; myAction = action; } - public TopLevelTree(ZLResource resource, int coverResourceId, Runnable action) { - this(resource, null, coverResourceId, action); + public TopLevelTree(String id, ZLResource resource, int coverResourceId, Runnable action) { + this(id, resource, null, coverResourceId, action); } @Override @@ -47,6 +49,11 @@ class TopLevelTree extends FBTree implements ZLAndroidTree { return myResource.getValue(); } + @Override + protected String getStringId() { + return myId; + } + @Override public String getSummary() { final String summary = myResource.getResource("summary").getValue(); diff --git a/src/org/geometerplus/fbreader/library/AuthorTree.java b/src/org/geometerplus/fbreader/library/AuthorTree.java index cfe8470e3..1a56e4794 100644 --- a/src/org/geometerplus/fbreader/library/AuthorTree.java +++ b/src/org/geometerplus/fbreader/library/AuthorTree.java @@ -41,6 +41,11 @@ public class AuthorTree extends LibraryTree { ZLResource.resource("library").getResource("unknownAuthor").getValue(); } + @Override + protected String getStringId() { + return getName(); + } + protected String getSortKey() { return (Author != null) ? Author.SortKey : null; } diff --git a/src/org/geometerplus/fbreader/library/BookTree.java b/src/org/geometerplus/fbreader/library/BookTree.java index 0dfe39e8b..28803d303 100644 --- a/src/org/geometerplus/fbreader/library/BookTree.java +++ b/src/org/geometerplus/fbreader/library/BookTree.java @@ -36,6 +36,11 @@ public class BookTree extends LibraryTree { return Book.getTitle(); } + @Override + protected String getStringId() { + return getName(); + } + @Override public String getSummary() { if (!myShowAuthors) { diff --git a/src/org/geometerplus/fbreader/library/Library.java b/src/org/geometerplus/fbreader/library/Library.java index 6c1cd5dd8..840401ccb 100644 --- a/src/org/geometerplus/fbreader/library/Library.java +++ b/src/org/geometerplus/fbreader/library/Library.java @@ -35,14 +35,16 @@ public final class Library { public static final int STATE_NOT_INITIALIZED = 0; public static final int STATE_FULLY_INITIALIZED = 1; - private final LinkedList myBooks = new LinkedList(); - private final HashSet myExternalBooks = new HashSet(); - private final LibraryTree myLibraryByAuthor = new RootTree(); - private final LibraryTree myLibraryByTitle = new RootTree(); - private final LibraryTree myLibraryByTag = new RootTree(); - private final LibraryTree myRecentBooks = new RootTree(); - private final LibraryTree myFavorites = new RootTree(); - private LibraryTree mySearchResult = new RootTree(); + public static final String ROOT_FAVORITES = "favorites"; + public static final String ROOT_SEARCH_RESULTS = "searchResults"; + public static final String ROOT_RECENT = "recent"; + public static final String ROOT_BY_AUTHOR = "byAuthor"; + public static final String ROOT_BY_TITLE = "byTitle"; + public static final String ROOT_BY_TAG = "byTag"; + + private final List myBooks = new LinkedList(); + private final Set myExternalBooks = new HashSet(); + private final Map myRootTrees = new HashMap(); private volatile int myState = STATE_NOT_INITIALIZED; private volatile boolean myInterrupted = false; @@ -50,6 +52,15 @@ public final class Library { public Library() { } + private LibraryTree getRootTree(String id) { + LibraryTree root = myRootTrees.get(id); + if (root == null) { + root = new RootTree(id); + myRootTrees.put(id, root); + } + return root; + } + public boolean hasState(int state) { return myState >= state || myInterrupted; } @@ -228,7 +239,7 @@ public final class Library { if (tagTree == null) { LibraryTree parent = ((tag != null) && (tag.Parent != null)) ? - getTagTree(tag.Parent, tagTreeMap) : myLibraryByTag; + getTagTree(tag.Parent, tagTreeMap) : getRootTree(ROOT_BY_TAG); tagTree = parent.createTagSubTree(tag); tagTreeMap.put(tag, tagTree); } @@ -253,7 +264,7 @@ public final class Library { for (Author a : authors) { AuthorTree authorTree = authorTreeMap.get(a); if (authorTree == null) { - authorTree = myLibraryByAuthor.createAuthorSubTree(a); + authorTree = getRootTree(ROOT_BY_AUTHOR).createAuthorSubTree(a); authorTreeMap.put(a, authorTree); } if (seriesInfo == null) { @@ -307,14 +318,14 @@ public final class Library { Character c = title.charAt(0); TitleTree tree = letterTrees.get(c); if (tree == null) { - tree = myLibraryByTitle.createTitleSubTree(c.toString()); + tree = getRootTree(ROOT_BY_TITLE).createTitleSubTree(c.toString()); letterTrees.put(c, tree); } tree.createBookSubTree(book, true); } } else { for (Book book : myBooks) { - myLibraryByTitle.createBookSubTree(book, true); + getRootTree(ROOT_BY_TITLE).createBookSubTree(book, true); } } @@ -322,21 +333,21 @@ public final class Library { for (long id : db.loadRecentBookIds()) { Book book = bookById.get(id); if (book != null) { - myRecentBooks.createBookSubTree(book, true); + getRootTree(ROOT_RECENT).createBookSubTree(book, true); } } for (long id : db.loadFavoritesIds()) { Book book = bookById.get(id); if (book != null) { - myFavorites.createBookSubTree(book, true); + getRootTree(ROOT_FAVORITES).createBookSubTree(book, true); } } - myFavorites.sortAllChildren(); - myLibraryByAuthor.sortAllChildren(); - myLibraryByTitle.sortAllChildren(); - myLibraryByTag.sortAllChildren(); + getRootTree(ROOT_FAVORITES).sortAllChildren(); + getRootTree(ROOT_BY_AUTHOR).sortAllChildren(); + getRootTree(ROOT_BY_TITLE).sortAllChildren(); + getRootTree(ROOT_BY_TAG).sortAllChildren(); db.executeAsATransaction(new Runnable() { public void run() { @@ -363,22 +374,22 @@ public final class Library { public LibraryTree byAuthor() { waitForState(STATE_FULLY_INITIALIZED); - return myLibraryByAuthor; + return getRootTree(ROOT_BY_AUTHOR); } public LibraryTree byTitle() { waitForState(STATE_FULLY_INITIALIZED); - return myLibraryByTitle; + return getRootTree(ROOT_BY_TITLE); } public LibraryTree byTag() { waitForState(STATE_FULLY_INITIALIZED); - return myLibraryByTag; + return getRootTree(ROOT_BY_TAG); } public LibraryTree recentBooks() { waitForState(STATE_FULLY_INITIALIZED); - return myRecentBooks; + return getRootTree(ROOT_RECENT); } public static Book getRecentBook() { @@ -393,16 +404,16 @@ public final class Library { public LibraryTree favorites() { waitForState(STATE_FULLY_INITIALIZED); - return myFavorites; + return getRootTree(ROOT_FAVORITES); } public LibraryTree searchResults() { - return mySearchResult; + return getRootTree(ROOT_SEARCH_RESULTS); } public LibraryTree searchBooks(String pattern) { waitForState(STATE_FULLY_INITIALIZED); - final RootTree newSearchResults = new RootTree(); + final RootTree newSearchResults = new RootTree(ROOT_SEARCH_RESULTS); if (pattern != null) { pattern = pattern.toLowerCase(); for (Book book : myBooks) { @@ -412,7 +423,7 @@ public final class Library { } newSearchResults.sortAllChildren(); if (newSearchResults.hasChildren()) { - mySearchResult = newSearchResults; + myRootTrees.put(ROOT_SEARCH_RESULTS, newSearchResults); } } return newSearchResults; @@ -432,21 +443,22 @@ public final class Library { public boolean isBookInFavorites(Book book) { waitForState(STATE_FULLY_INITIALIZED); - return myFavorites.containsBook(book); + return getRootTree(ROOT_FAVORITES).containsBook(book); } public void addBookToFavorites(Book book) { waitForState(STATE_FULLY_INITIALIZED); - if (!myFavorites.containsBook(book)) { - myFavorites.createBookSubTree(book, true); - myFavorites.sortAllChildren(); + final LibraryTree rootFavorites = getRootTree(ROOT_FAVORITES); + if (!rootFavorites.containsBook(book)) { + rootFavorites.createBookSubTree(book, true); + rootFavorites.sortAllChildren(); BooksDatabase.Instance().addToFavorites(book.getId()); } } public void removeBookFromFavorites(Book book) { waitForState(STATE_FULLY_INITIALIZED); - if (myFavorites.removeBook(book)) { + if (getRootTree(ROOT_FAVORITES).removeBook(book)) { BooksDatabase.Instance().removeFromFavorites(book.getId()); } } @@ -482,16 +494,15 @@ public final class Library { } waitForState(STATE_FULLY_INITIALIZED); myBooks.remove(book); - myLibraryByAuthor.removeBook(book); - myLibraryByTag.removeBook(book); - if (myRecentBooks.removeBook(book)) { + if (getRootTree(ROOT_RECENT).removeBook(book)) { final BooksDatabase db = BooksDatabase.Instance(); final List ids = db.loadRecentBookIds(); ids.remove(book.getId()); db.saveRecentBookIds(ids); } - mySearchResult.removeBook(book); - myFavorites.removeBook(book); + for (LibraryTree root : myRootTrees.values()) { + root.removeBook(book); + } BooksDatabase.Instance().deleteFromBookList(book.getId()); if ((removeMode & REMOVE_FROM_DISK) != 0) { diff --git a/src/org/geometerplus/fbreader/library/RootTree.java b/src/org/geometerplus/fbreader/library/RootTree.java index 08c15d5d6..92062ceb9 100644 --- a/src/org/geometerplus/fbreader/library/RootTree.java +++ b/src/org/geometerplus/fbreader/library/RootTree.java @@ -20,7 +20,19 @@ package org.geometerplus.fbreader.library; final class RootTree extends LibraryTree { + private final String myId; + + RootTree(String id) { + myId = id; + } + + @Override public String getName() { return null; } + + @Override + protected String getStringId() { + return myId; + } } diff --git a/src/org/geometerplus/fbreader/library/SeriesTree.java b/src/org/geometerplus/fbreader/library/SeriesTree.java index a529927d3..8b37f1e0c 100644 --- a/src/org/geometerplus/fbreader/library/SeriesTree.java +++ b/src/org/geometerplus/fbreader/library/SeriesTree.java @@ -32,6 +32,11 @@ public final class SeriesTree extends LibraryTree { return Series; } + @Override + protected String getStringId() { + return getName(); + } + BookTree createBookInSeriesSubTree(Book book) { return new BookInSeriesTree(this, book); } diff --git a/src/org/geometerplus/fbreader/library/TagTree.java b/src/org/geometerplus/fbreader/library/TagTree.java index 2c46482e0..5eebf1f51 100644 --- a/src/org/geometerplus/fbreader/library/TagTree.java +++ b/src/org/geometerplus/fbreader/library/TagTree.java @@ -37,6 +37,11 @@ public final class TagTree extends LibraryTree { ZLResource.resource("library").getResource("booksWithNoTags").getValue(); } + @Override + protected String getStringId() { + return getName(); + } + protected String getSortKey() { return (Tag != null) ? Tag.Name : null; } diff --git a/src/org/geometerplus/fbreader/library/TitleTree.java b/src/org/geometerplus/fbreader/library/TitleTree.java index 17105a3c5..8bfffe62d 100644 --- a/src/org/geometerplus/fbreader/library/TitleTree.java +++ b/src/org/geometerplus/fbreader/library/TitleTree.java @@ -31,4 +31,9 @@ public final class TitleTree extends LibraryTree { public String getName() { return Title; } + + @Override + protected String getStringId() { + return getName(); + } } diff --git a/src/org/geometerplus/fbreader/network/NetworkTree.java b/src/org/geometerplus/fbreader/network/NetworkTree.java index 074a0a4ae..c19de95d7 100644 --- a/src/org/geometerplus/fbreader/network/NetworkTree.java +++ b/src/org/geometerplus/fbreader/network/NetworkTree.java @@ -27,7 +27,6 @@ import org.geometerplus.zlibrary.core.util.MimeType; import org.geometerplus.fbreader.tree.FBTree; public abstract class NetworkTree extends FBTree { - private Key myKey; private Map myUserData; protected NetworkTree() { @@ -103,25 +102,6 @@ public abstract class NetworkTree extends FBTree { return myUserData != null ? myUserData.get(key) : null; } - /** - * Returns unique identifier which can be used in NetworkView methods - * @return unique Key instance - */ - public final Key getUniqueKey() { - if (myKey == null) { - final Key parentKey = Parent instanceof NetworkTree ? - ((NetworkTree)Parent).getUniqueKey() : null; - myKey = createKey(parentKey, getStringId()); - } - return myKey; - } - - /** - * Returns id used as a part of unique key above. This string must be not null - * and be unique for all children of same tree - */ - protected abstract String getStringId(); - public void removeItems(Set items) { if (items.isEmpty() || subTrees().isEmpty()) { return; diff --git a/src/org/geometerplus/fbreader/tree/FBTree.java b/src/org/geometerplus/fbreader/tree/FBTree.java index 08e6ef1bd..16529d4b8 100644 --- a/src/org/geometerplus/fbreader/tree/FBTree.java +++ b/src/org/geometerplus/fbreader/tree/FBTree.java @@ -64,17 +64,31 @@ public abstract class FBTree extends ZLTree implements Comparable