From 454bd46593de5a2c398eb214c8401ba1753412ca Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Sat, 9 Feb 2013 15:14:54 +0400 Subject: [PATCH] series trees on-the-fly --- assets/resources/application/en.xml | 1 + .../libraryService/BookCollectionShadow.java | 43 ++++++++-- .../libraryService/LibraryInterface.aidl | 3 + .../libraryService/LibraryService.java | 14 +++- .../fbreader/book/BookCollection.java | 32 +++++++- .../fbreader/book/IBookCollection.java | 22 +++-- .../fbreader/library/AuthorTree.java | 10 +++ .../fbreader/library/Library.java | 16 +--- .../fbreader/library/LibraryTree.java | 10 --- .../fbreader/library/SeriesListTree.java | 82 +++++++++++++++++++ .../fbreader/library/SeriesTree.java | 49 ++++++++--- 11 files changed, 229 insertions(+), 53 deletions(-) create mode 100644 src/org/geometerplus/fbreader/library/SeriesListTree.java diff --git a/assets/resources/application/en.xml b/assets/resources/application/en.xml index ffd99dd8a..b7d224981 100644 --- a/assets/resources/application/en.xml +++ b/assets/resources/application/en.xml @@ -801,6 +801,7 @@ + diff --git a/src/org/geometerplus/android/fbreader/libraryService/BookCollectionShadow.java b/src/org/geometerplus/android/fbreader/libraryService/BookCollectionShadow.java index a8ad239d0..9e1dbea33 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/BookCollectionShadow.java +++ b/src/org/geometerplus/android/fbreader/libraryService/BookCollectionShadow.java @@ -147,7 +147,29 @@ public class BookCollectionShadow extends AbstractBookCollection implements Serv } } - public synchronized List books(String pattern) { + public synchronized List booksForSeries(String series) { + if (myInterface == null) { + return Collections.emptyList(); + } + try { + return SerializerUtil.deserializeBookList(myInterface.booksForSeries(series)); + } catch (RemoteException e) { + return Collections.emptyList(); + } + } + + public synchronized List booksForTitlePrefix(String prefix) { + if (myInterface == null) { + return Collections.emptyList(); + } + try { + return SerializerUtil.deserializeBookList(myInterface.booksForTitlePrefix(prefix)); + } catch (RemoteException e) { + return Collections.emptyList(); + } + } + + public synchronized List booksForPattern(String pattern) { if (myInterface == null) { return Collections.emptyList(); } @@ -245,16 +267,25 @@ public class BookCollectionShadow extends AbstractBookCollection implements Serv } } + public synchronized boolean hasSeries() { + if (myInterface != null) { + try { + return myInterface.hasSeries(); + } catch (RemoteException e) { + } + } + return false; + } + public synchronized List series() { if (myInterface == null) { return Collections.emptyList(); } - //try { - // TODO: implement + try { + return myInterface.series(); + } catch (RemoteException e) { return Collections.emptyList(); - //} catch (RemoteException e) { - // return Collections.emptyList(); - //} + } } public synchronized boolean saveBook(Book book, boolean force) { diff --git a/src/org/geometerplus/android/fbreader/libraryService/LibraryInterface.aidl b/src/org/geometerplus/android/fbreader/libraryService/LibraryInterface.aidl index 01510d32f..a3977d494 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/LibraryInterface.aidl +++ b/src/org/geometerplus/android/fbreader/libraryService/LibraryInterface.aidl @@ -12,6 +12,8 @@ interface LibraryInterface { List books(); List booksForAuthor(in String author); List booksForTag(in String tag); + List booksForSeries(in String series); + List booksForTitlePrefix(in String prefix); List booksForPattern(in String pattern); List recentBooks(); List favorites(); @@ -20,6 +22,7 @@ interface LibraryInterface { String getRecentBook(in int index); List authors(); + boolean hasSeries(); List series(); List tags(); diff --git a/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java b/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java index 21eaf4180..ec5972bf5 100644 --- a/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java +++ b/src/org/geometerplus/android/fbreader/libraryService/LibraryService.java @@ -127,8 +127,16 @@ public class LibraryService extends Service { return SerializerUtil.serializeBookList(myCollection.books(Util.stringToTag(tag))); } + public List booksForSeries(String series) { + return SerializerUtil.serializeBookList(myCollection.booksForSeries(series)); + } + + public List booksForTitlePrefix(String prefix) { + return SerializerUtil.serializeBookList(myCollection.booksForTitlePrefix(prefix)); + } + public List booksForPattern(String pattern) { - return SerializerUtil.serializeBookList(myCollection.books(pattern)); + return SerializerUtil.serializeBookList(myCollection.booksForPattern(pattern)); } public List recentBooks() { @@ -160,6 +168,10 @@ public class LibraryService extends Service { return strings; } + public boolean hasSeries() { + return myCollection.hasSeries(); + } + public List series() { return myCollection.series(); } diff --git a/src/org/geometerplus/fbreader/book/BookCollection.java b/src/org/geometerplus/fbreader/book/BookCollection.java index 3d9e507fa..78ff0e2e8 100644 --- a/src/org/geometerplus/fbreader/book/BookCollection.java +++ b/src/org/geometerplus/fbreader/book/BookCollection.java @@ -222,7 +222,26 @@ public class BookCollection extends AbstractBookCollection { return filtered; } - public List books(String pattern) { + public List booksForSeries(String series) { + final LinkedList filtered = new LinkedList(); + for (Book b : books()) { + final SeriesInfo info = b.getSeriesInfo(); + if (info != null && series.equals(info.Title)) { + filtered.add(b); + } + } + return filtered; + } + + public List booksForTitlePrefix(String prefix) { + final LinkedList filtered = new LinkedList(); + for (Book b : books()) { + // TODO: implement + } + return filtered; + } + + public List booksForPattern(String pattern) { if (pattern == null || pattern.length() == 0) { return Collections.emptyList(); } @@ -289,6 +308,17 @@ public class BookCollection extends AbstractBookCollection { return new ArrayList(tags); } + public boolean hasSeries() { + synchronized (myBooksByFile) { + for (Book book : myBooksByFile.values()) { + if (book.getSeriesInfo() != null) { + return true; + } + } + } + return false; + } + public List series() { final Set series = new TreeSet(); synchronized (myBooksByFile) { diff --git a/src/org/geometerplus/fbreader/book/IBookCollection.java b/src/org/geometerplus/fbreader/book/IBookCollection.java index 782040f7a..b4b57479d 100644 --- a/src/org/geometerplus/fbreader/book/IBookCollection.java +++ b/src/org/geometerplus/fbreader/book/IBookCollection.java @@ -46,26 +46,30 @@ public interface IBookCollection { List books(); List books(Author author); List books(Tag tag); - List books(String pattern); - List recentBooks(); + List booksForSeries(String series); + List booksForTitlePrefix(String prefix); + List booksForPattern(String pattern); + List favorites(); + boolean hasFavorites(); + boolean isFavorite(Book book); + void setBookFavorite(Book book, boolean favorite); + + List recentBooks(); + Book getRecentBook(int index); + void addBookToRecentList(Book book); + Book getBookByFile(ZLFile file); Book getBookById(long id); - Book getRecentBook(int index); List authors(); List tags(); + boolean hasSeries(); List series(); boolean saveBook(Book book, boolean force); void removeBook(Book book, boolean deleteFromDisk); - void addBookToRecentList(Book book); - - boolean hasFavorites(); - boolean isFavorite(Book book); - void setBookFavorite(Book book, boolean favorite); - ZLTextPosition getStoredPosition(long bookId); void storePosition(long bookId, ZLTextPosition position); diff --git a/src/org/geometerplus/fbreader/library/AuthorTree.java b/src/org/geometerplus/fbreader/library/AuthorTree.java index ae3787b72..7cfffba6c 100644 --- a/src/org/geometerplus/fbreader/library/AuthorTree.java +++ b/src/org/geometerplus/fbreader/library/AuthorTree.java @@ -97,6 +97,16 @@ public class AuthorTree extends LibraryTree { } } + private SeriesTree getSeriesSubTree(String series) { + final SeriesTree temp = new SeriesTree(Collection, series); + int position = Collections.binarySearch(subTrees(), temp); + if (position >= 0) { + return (SeriesTree)subTrees().get(position); + } else { + return new SeriesTree(this, series, - position - 1); + } + } + private boolean createBookSubTree(Book book) { final SeriesInfo seriesInfo = book.getSeriesInfo(); if (seriesInfo != null) { diff --git a/src/org/geometerplus/fbreader/library/Library.java b/src/org/geometerplus/fbreader/library/Library.java index b25ae3c29..fa920fb96 100644 --- a/src/org/geometerplus/fbreader/library/Library.java +++ b/src/org/geometerplus/fbreader/library/Library.java @@ -110,6 +110,7 @@ public final class Library { new RecentBooksTree(myRootTree); new AuthorListTree(myRootTree); new FirstLevelTree(myRootTree, LibraryTree.ROOT_BY_TITLE); + new SeriesListTree(myRootTree); new TagListTree(myRootTree); new FileFirstLevelTree(myRootTree); } @@ -230,20 +231,6 @@ public final class Library { } myBooks.put(book.File, book); - final SeriesInfo seriesInfo = book.getSeriesInfo(); - - if (seriesInfo != null) { - FirstLevelTree seriesRoot = getFirstLevelTree(LibraryTree.ROOT_BY_SERIES); - if (seriesRoot == null) { - seriesRoot = new FirstLevelTree( - myRootTree, - myRootTree.indexOf(getFirstLevelTree(LibraryTree.ROOT_BY_TITLE)) + 1, - LibraryTree.ROOT_BY_SERIES - ); - } - seriesRoot.getSeriesSubTree(seriesInfo.Title).createBookInSeriesSubTree(book); - } - if (myDoGroupTitlesByFirstLetter) { final String letter = TitleTree.firstTitleLetter(book); if (letter != null) { @@ -277,7 +264,6 @@ public final class Library { myBooks.remove(book.File); removeFromTree(LibraryTree.ROOT_FOUND, book); removeFromTree(LibraryTree.ROOT_BY_TITLE, book); - removeFromTree(LibraryTree.ROOT_BY_SERIES, book); addBookToLibrary(book); fireModelChangedEvent(ChangeListener.Code.BookAdded); } diff --git a/src/org/geometerplus/fbreader/library/LibraryTree.java b/src/org/geometerplus/fbreader/library/LibraryTree.java index 4108348a3..ceb60fbaf 100644 --- a/src/org/geometerplus/fbreader/library/LibraryTree.java +++ b/src/org/geometerplus/fbreader/library/LibraryTree.java @@ -95,16 +95,6 @@ public abstract class LibraryTree extends FBTree { } } - SeriesTree getSeriesSubTree(String series) { - final SeriesTree temp = new SeriesTree(Collection, series); - int position = Collections.binarySearch(subTrees(), temp); - if (position >= 0) { - return (SeriesTree)subTrees().get(position); - } else { - return new SeriesTree(this, series, - position - 1); - } - } - public boolean removeBook(Book book) { final LinkedList toRemove = new LinkedList(); for (FBTree tree : this) { diff --git a/src/org/geometerplus/fbreader/library/SeriesListTree.java b/src/org/geometerplus/fbreader/library/SeriesListTree.java new file mode 100644 index 000000000..cc267f8bc --- /dev/null +++ b/src/org/geometerplus/fbreader/library/SeriesListTree.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009-2013 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.Collections; +import java.util.List; + +import org.geometerplus.fbreader.book.*; + +public class SeriesListTree extends FirstLevelTree { + SeriesListTree(RootTree root) { + super(root, ROOT_BY_SERIES); + } + + @Override + public Status getOpeningStatus() { + if (!Collection.hasSeries()) { + return Status.CANNOT_OPEN; + } + return Status.ALWAYS_RELOAD_BEFORE_OPENING; + } + + @Override + public String getOpeningStatusMessage() { + return getOpeningStatus() == Status.CANNOT_OPEN + ? "noSeries" : super.getOpeningStatusMessage(); + } + + @Override + public void waitForOpening() { + clear(); + for (String s : Collection.series()) { + createSeriesSubTree(s); + } + } + + @Override + public boolean onBookEvent(BookEvent event, Book book) { + switch (event) { + case Added: + { + final SeriesInfo info = book.getSeriesInfo(); + return info != null && createSeriesSubTree(info.Title); + } + case Removed: + // TODO: implement + return false; + default: + case Updated: + // TODO: implement + return false; + } + } + + private boolean createSeriesSubTree(String series) { + final SeriesTree temp = new SeriesTree(Collection, series); + int position = Collections.binarySearch(subTrees(), temp); + if (position >= 0) { + return false; + } else { + new SeriesTree(this, series, - position - 1); + return true; + } + } +} diff --git a/src/org/geometerplus/fbreader/library/SeriesTree.java b/src/org/geometerplus/fbreader/library/SeriesTree.java index 3b7bf3995..f19b02e84 100644 --- a/src/org/geometerplus/fbreader/library/SeriesTree.java +++ b/src/org/geometerplus/fbreader/library/SeriesTree.java @@ -46,17 +46,6 @@ public final class SeriesTree extends LibraryTree { return "@SeriesTree " + getName(); } - boolean createBookInSeriesSubTree(Book book) { - final BookInSeriesTree temp = new BookInSeriesTree(Collection, book); - int position = Collections.binarySearch(subTrees(), temp); - if (position >= 0) { - return false; - } else { - new BookInSeriesTree(this, book, - position - 1); - return true; - } - } - @Override public boolean containsBook(Book book) { if (book == null) { @@ -70,4 +59,42 @@ public final class SeriesTree extends LibraryTree { protected String getSortKey() { return " Series:" + super.getSortKey(); } + + @Override + public Status getOpeningStatus() { + return Status.ALWAYS_RELOAD_BEFORE_OPENING; + } + + @Override + public void waitForOpening() { + clear(); + for (Book book : Collection.booksForSeries(Series)) { + createBookInSeriesSubTree(book); + } + } + + @Override + public boolean onBookEvent(BookEvent event, Book book) { + switch (event) { + case Added: + return containsBook(book) && createBookInSeriesSubTree(book); + case Removed: + // TODO: implement + case Updated: + // TODO: implement + default: + return super.onBookEvent(event, book); + } + } + + boolean createBookInSeriesSubTree(Book book) { + final BookInSeriesTree temp = new BookInSeriesTree(Collection, book); + int position = Collections.binarySearch(subTrees(), temp); + if (position >= 0) { + return false; + } else { + new BookInSeriesTree(this, book, - position - 1); + return true; + } + } }