1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-05 02:39:23 +02:00

Merge branch 'master' into library-service

Conflicts:
	src/org/geometerplus/fbreader/library/Library.java
This commit is contained in:
Nikolay Pultsin 2013-02-09 14:28:32 +04:00
commit 83e5045a09
14 changed files with 231 additions and 59 deletions

View file

@ -134,6 +134,19 @@ public class BookCollectionShadow extends AbstractBookCollection implements Serv
}
}
public synchronized List<Book> books(Tag tag) {
if (myInterface == null) {
return Collections.emptyList();
}
try {
return SerializerUtil.deserializeBookList(
myInterface.booksForTag(Util.tagToString(tag))
);
} catch (RemoteException e) {
return Collections.emptyList();
}
}
public synchronized List<Book> books(String pattern) {
if (myInterface == null) {
return Collections.emptyList();
@ -220,12 +233,16 @@ public class BookCollectionShadow extends AbstractBookCollection implements Serv
if (myInterface == null) {
return Collections.emptyList();
}
//try {
// TODO: implement
try {
final List<String> strings = myInterface.tags();
final List<Tag> tags = new ArrayList<Tag>(strings.size());
for (String s : strings) {
tags.add(Util.stringToTag(s));
}
return tags;
} catch (RemoteException e) {
return Collections.emptyList();
//} catch (RemoteException e) {
// return Collections.emptyList();
//}
}
}
public synchronized List<String> series() {

View file

@ -11,6 +11,7 @@ interface LibraryInterface {
int size();
List<String> books();
List<String> booksForAuthor(in String author);
List<String> booksForTag(in String tag);
List<String> booksForPattern(in String pattern);
List<String> recentBooks();
List<String> favorites();
@ -19,6 +20,8 @@ interface LibraryInterface {
String getRecentBook(in int index);
List<String> authors();
List<String> series();
List<String> tags();
boolean saveBook(in String book, in boolean force);
void removeBook(in String book, in boolean deleteFromDisk);

View file

@ -128,6 +128,10 @@ public class LibraryService extends Service {
return SerializerUtil.serializeBookList(myCollection.books(Util.stringToAuthor(author)));
}
public List<String> booksForTag(String tag) {
return SerializerUtil.serializeBookList(myCollection.books(Util.stringToTag(tag)));
}
public List<String> booksForPattern(String pattern) {
return SerializerUtil.serializeBookList(myCollection.books(pattern));
}
@ -161,6 +165,19 @@ public class LibraryService extends Service {
return strings;
}
public List<String> series() {
return myCollection.series();
}
public List<String> tags() {
final List<Tag> tags = myCollection.tags();
final List<String> strings = new ArrayList<String>(tags.size());
for (Tag t : tags) {
strings.add(Util.tagToString(t));
}
return strings;
}
public boolean saveBook(String book, boolean force) {
return myCollection.saveBook(SerializerUtil.deserializeBook(book), force);
}

View file

@ -20,6 +20,7 @@
package org.geometerplus.android.fbreader.libraryService;
import org.geometerplus.fbreader.book.Author;
import org.geometerplus.fbreader.book.Tag;
abstract class Util {
static String authorToString(Author author) {
@ -34,4 +35,17 @@ abstract class Util {
return Author.NULL;
}
}
static String tagToString(Tag tag) {
return tag.toString("\000");
}
static Tag stringToTag(String string) {
final String[] splitted = string.split("\000");
if (splitted.length > 0) {
return Tag.getTag(splitted);
} else {
return Tag.NULL;
}
}
}

View file

@ -210,6 +210,18 @@ public class BookCollection extends AbstractBookCollection {
return filtered;
}
public List<Book> books(Tag tag) {
final boolean isNull = Tag.NULL.equals(tag);
final LinkedList<Book> filtered = new LinkedList<Book>();
for (Book b : books()) {
final List<Tag> bookTags = b.tags();
if (isNull && bookTags.isEmpty() || bookTags.contains(tag)) {
filtered.add(b);
}
}
return filtered;
}
public List<Book> books(String pattern) {
if (pattern == null || pattern.length() == 0) {
return Collections.emptyList();
@ -262,7 +274,12 @@ public class BookCollection extends AbstractBookCollection {
final Set<Tag> tags = new TreeSet<Tag>();
synchronized (myBooksByFile) {
for (Book book : myBooksByFile.values()) {
tags.addAll(book.tags());
final List<Tag> bookTags = book.tags();
if (bookTags.isEmpty()) {
tags.add(Tag.NULL);
} else {
tags.addAll(book.tags());
}
}
}
return new ArrayList<Tag>(tags);

View file

@ -45,6 +45,7 @@ public interface IBookCollection {
int size();
List<Book> books();
List<Book> books(Author author);
List<Book> books(Tag tag);
List<Book> books(String pattern);
List<Book> recentBooks();
List<Book> favorites();

View file

@ -22,6 +22,8 @@ package org.geometerplus.fbreader.book;
import java.util.HashMap;
public final class Tag {
public static final Tag NULL = new Tag(null, "");
private static final HashMap<Tag,Tag> ourTagSet = new HashMap<Tag,Tag>();
public static Tag getTag(Tag parent, String name) {

View file

@ -45,14 +45,13 @@ public class AuthorListTree extends FirstLevelTree {
@Override
public boolean onBookEvent(BookEvent event, Book book) {
switch (event) {
default:
case Added:
{
final List<Author> bookAuthors = book.authors();
boolean changed = false;
if (bookAuthors.isEmpty()) {
changed &= createAuthorSubTree(Author.NULL);
} else for (Author a : Collection.authors()) {
} else for (Author a : bookAuthors) {
changed &= createAuthorSubTree(a);
}
return changed;
@ -60,6 +59,7 @@ public class AuthorListTree extends FirstLevelTree {
case Removed:
// TODO: implement
return false;
default:
case Updated:
// TODO: implement
return false;

View file

@ -39,10 +39,8 @@ public class AuthorTree extends LibraryTree {
@Override
public String getName() {
return
Author != Author.NULL ?
Author.DisplayName :
Library.resource().getResource("unknownAuthor").getValue();
return Author.NULL.equals(Author)
? Library.resource().getResource("unknownAuthor").getValue() : Author.DisplayName;
}
@Override
@ -52,7 +50,7 @@ public class AuthorTree extends LibraryTree {
@Override
protected String getSortKey() {
if (Author == null) {
if (Author.NULL.equals(Author)) {
return null;
}
return new StringBuilder()
@ -90,12 +88,16 @@ public class AuthorTree extends LibraryTree {
switch (event) {
case Added:
return containsBook(book) && createBookSubTree(book);
case Removed:
// TODO: implement
case Updated:
// TODO: implement
default:
return super.onBookEvent(event, book);
}
}
boolean createBookSubTree(Book book) {
private boolean createBookSubTree(Book book) {
final SeriesInfo seriesInfo = book.getSeriesInfo();
if (seriesInfo != null) {
return getSeriesSubTree(seriesInfo.Title).createBookInSeriesSubTree(book);

View file

@ -53,7 +53,7 @@ public class FavoritesTree extends FirstLevelTree {
new BookWithAuthorsTree(this, book);
return true;
} if (event == BookEvent.Updated && !Collection.isFavorite(book)) {
return removeBook(book, false);
return removeBook(book);
} else {
return super.onBookEvent(event, book);
}

View file

@ -96,7 +96,7 @@ public final class Library {
new RecentBooksTree(myRootTree);
new AuthorListTree(myRootTree);
new FirstLevelTree(myRootTree, LibraryTree.ROOT_BY_TITLE);
new FirstLevelTree(myRootTree, LibraryTree.ROOT_BY_TAG);
new TagListTree(myRootTree);
new FileFirstLevelTree(myRootTree);
}
@ -166,16 +166,6 @@ public final class Library {
return parentTree != null ? (LibraryTree)parentTree.getSubTree(key.Id) : null;
}
private final List<?> myNullList = Collections.singletonList(null);
private LibraryTree getTagTree(Tag tag) {
if (tag == null || tag.Parent == null) {
return getFirstLevelTree(LibraryTree.ROOT_BY_TAG).getTagSubTree(tag);
} else {
return getTagTree(tag.Parent).getTagSubTree(tag);
}
}
private synchronized void addBookToLibrary(Book book) {
synchronized (myBooks) {
final Book existing = myBooks.get(book.getId());
@ -205,24 +195,16 @@ public final class Library {
if (letter != null) {
final TitleTree tree =
getFirstLevelTree(LibraryTree.ROOT_BY_TITLE).getTitleSubTree(letter);
tree.getBookWithAuthorsSubTree(book);
tree.createBookWithAuthorsSubTree(book);
}
} else {
getFirstLevelTree(LibraryTree.ROOT_BY_TITLE).getBookWithAuthorsSubTree(book);
}
List<Tag> tags = book.tags();
if (tags.isEmpty()) {
tags = (List<Tag>)myNullList;
}
for (Tag t : tags) {
getTagTree(t).getBookWithAuthorsSubTree(book);
getFirstLevelTree(LibraryTree.ROOT_BY_TITLE).createBookWithAuthorsSubTree(book);
}
synchronized (this) {
final SearchResultsTree found = (SearchResultsTree)getFirstLevelTree(LibraryTree.ROOT_FOUND);
if (found != null && book.matches(found.getPattern())) {
found.getBookWithAuthorsSubTree(book);
found.createBookWithAuthorsSubTree(book);
}
}
}
@ -230,7 +212,7 @@ public final class Library {
private void removeFromTree(String rootId, Book book) {
final FirstLevelTree tree = getFirstLevelTree(rootId);
if (tree != null) {
tree.removeBook(book, false);
tree.removeBook(book);
}
}
@ -244,7 +226,6 @@ public final class Library {
removeFromTree(LibraryTree.ROOT_FOUND, book);
removeFromTree(LibraryTree.ROOT_BY_TITLE, book);
removeFromTree(LibraryTree.ROOT_BY_SERIES, book);
removeFromTree(LibraryTree.ROOT_BY_TAG, book);
addBookToLibrary(book);
fireModelChangedEvent(ChangeListener.Code.BookAdded);
}
@ -292,7 +273,7 @@ public final class Library {
newSearchResults = new SearchResultsTree(myRootTree, LibraryTree.ROOT_FOUND, pattern);
fireModelChangedEvent(ChangeListener.Code.Found);
}
newSearchResults.getBookWithAuthorsSubTree(book);
newSearchResults.createBookWithAuthorsSubTree(book);
fireModelChangedEvent(ChangeListener.Code.BookAdded);
}
}
@ -320,6 +301,5 @@ public final class Library {
return;
}
Collection.removeBook(book, (removeMode & REMOVE_FROM_DISK) != 0);
myRootTree.removeBook(book, true);
}
}

View file

@ -63,13 +63,14 @@ public abstract class LibraryTree extends FBTree {
return true;
}
TagTree getTagSubTree(Tag tag) {
boolean createTagSubTree(Tag tag) {
final TagTree temp = new TagTree(Collection, tag);
int position = Collections.binarySearch(subTrees(), temp);
if (position >= 0) {
return (TagTree)subTrees().get(position);
return false;
} else {
return new TagTree(this, tag, - position - 1);
new TagTree(this, tag, - position - 1);
return true;
}
}
@ -83,13 +84,14 @@ public abstract class LibraryTree extends FBTree {
}
}
BookWithAuthorsTree getBookWithAuthorsSubTree(Book book) {
boolean createBookWithAuthorsSubTree(Book book) {
final BookWithAuthorsTree temp = new BookWithAuthorsTree(Collection, book);
int position = Collections.binarySearch(subTrees(), temp);
if (position >= 0) {
return (BookWithAuthorsTree)subTrees().get(position);
return false;
} else {
return new BookWithAuthorsTree(this, book, - position - 1);
new BookWithAuthorsTree(this, book, - position - 1);
return true;
}
}
@ -103,7 +105,7 @@ public abstract class LibraryTree extends FBTree {
}
}
public boolean removeBook(Book book, boolean recursively) {
public boolean removeBook(Book book) {
final LinkedList<FBTree> toRemove = new LinkedList<FBTree>();
for (FBTree tree : this) {
if (tree instanceof BookTree && ((BookTree)tree).Book.equals(book)) {
@ -112,12 +114,6 @@ public abstract class LibraryTree extends FBTree {
}
for (FBTree tree : toRemove) {
tree.removeSelf();
FBTree parent = tree.Parent;
if (recursively) {
for (; parent != null && !parent.hasChildren(); parent = parent.Parent) {
parent.removeSelf();
}
}
}
return !toRemove.isEmpty();
}
@ -128,7 +124,7 @@ public abstract class LibraryTree extends FBTree {
case Added:
return false;
case Removed:
return removeBook(book, true);
return removeBook(book);
case Updated:
{
boolean changed = false;

View file

@ -0,0 +1,72 @@
/*
* Copyright (C) 2009-2013 Geometer Plus <contact@geometerplus.com>
*
* 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 TagListTree extends FirstLevelTree {
TagListTree(RootTree root) {
super(root, ROOT_BY_TAG);
}
@Override
public Status getOpeningStatus() {
return Status.ALWAYS_RELOAD_BEFORE_OPENING;
}
@Override
public void waitForOpening() {
clear();
for (Tag t : Collection.tags()) {
if (t.Parent == null) {
createTagSubTree(t);
}
}
}
@Override
public boolean onBookEvent(BookEvent event, Book book) {
switch (event) {
case Added:
{
final List<Tag> bookTags = book.tags();
boolean changed = false;
if (bookTags.isEmpty()) {
changed &= createTagSubTree(Tag.NULL);
} else for (Tag t : bookTags) {
if (t.Parent == null) {
changed &= createTagSubTree(t);
}
}
return changed;
}
case Removed:
// TODO: implement
return false;
default:
case Updated:
// TODO: implement
return false;
}
}
}

View file

@ -19,6 +19,8 @@
package org.geometerplus.fbreader.library;
import java.util.List;
import org.geometerplus.fbreader.book.*;
public final class TagTree extends LibraryTree {
@ -36,8 +38,8 @@ public final class TagTree extends LibraryTree {
@Override
public String getName() {
return Tag != null
? Tag.Name : Library.resource().getResource("booksWithNoTags").getValue();
return Tag.NULL.equals(Tag)
? Library.resource().getResource("booksWithNoTags").getValue() : Tag.Name;
}
@Override
@ -46,7 +48,7 @@ public final class TagTree extends LibraryTree {
}
protected String getSortKey() {
return Tag != null ? Tag.Name : null;
return Tag.NULL.equals(Tag) ? null : Tag.Name;
}
@Override
@ -54,7 +56,7 @@ public final class TagTree extends LibraryTree {
if (book == null) {
return false;
}
if (Tag == null) {
if (Tag.NULL.equals(Tag)) {
return book.tags().isEmpty();
}
for (Tag t : book.tags()) {
@ -66,4 +68,53 @@ public final class TagTree extends LibraryTree {
}
return false;
}
@Override
public Status getOpeningStatus() {
return Status.ALWAYS_RELOAD_BEFORE_OPENING;
}
@Override
public void waitForOpening() {
clear();
if (!Tag.NULL.equals(Tag)) {
for (Tag t : Collection.tags()) {
if (Tag.equals(t.Parent)) {
createTagSubTree(t);
}
}
}
for (Book book : Collection.books(Tag)) {
createBookWithAuthorsSubTree(book);
}
}
@Override
public boolean onBookEvent(BookEvent event, Book book) {
switch (event) {
case Added:
{
boolean changed = false;
final List<Tag> bookTags = book.tags();
if (bookTags.isEmpty()) {
changed &= Tag.NULL.equals(Tag) && createBookWithAuthorsSubTree(book);
} else {
for (Tag t : bookTags) {
if (Tag.equals(t)) {
changed &= createBookWithAuthorsSubTree(book);
} else if (Tag.equals(t.Parent)) {
changed &= createTagSubTree(t);
}
}
}
return changed;
}
case Removed:
// TODO: implement
case Updated:
// TODO: implement
default:
return super.onBookEvent(event, book);
}
}
}