1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-04 10:19:33 +02:00

labels work as other book properties

This commit is contained in:
Nikolay Pultsin 2013-04-21 21:49:41 +02:00
parent 87eb3a9726
commit 6696447327
13 changed files with 148 additions and 170 deletions

View file

@ -202,7 +202,7 @@ public class LibraryActivity extends TreeActivity<LibraryTree> implements MenuIt
if (book.File.getPhysicalFile() != null) { if (book.File.getPhysicalFile() != null) {
menu.add(0, SHARE_BOOK_ITEM_ID, 0, resource.getResource("shareBook").getValue()); menu.add(0, SHARE_BOOK_ITEM_ID, 0, resource.getResource("shareBook").getValue());
} }
if (myRootTree.Collection.labels(book).contains(Book.FAVORITE_LABEL)) { if (book.labels().contains(Book.FAVORITE_LABEL)) {
menu.add(0, REMOVE_FROM_FAVORITES_ITEM_ID, 0, resource.getResource("removeFromFavorites").getValue()); menu.add(0, REMOVE_FROM_FAVORITES_ITEM_ID, 0, resource.getResource("removeFromFavorites").getValue());
} else { } else {
menu.add(0, ADD_TO_FAVORITES_ITEM_ID, 0, resource.getResource("addToFavorites").getValue()); menu.add(0, ADD_TO_FAVORITES_ITEM_ID, 0, resource.getResource("addToFavorites").getValue());
@ -234,10 +234,12 @@ public class LibraryActivity extends TreeActivity<LibraryTree> implements MenuIt
FBUtil.shareBook(this, book); FBUtil.shareBook(this, book);
return true; return true;
case ADD_TO_FAVORITES_ITEM_ID: case ADD_TO_FAVORITES_ITEM_ID:
myRootTree.Collection.setLabel(book, Book.FAVORITE_LABEL); book.addLabel(Book.FAVORITE_LABEL);
myRootTree.Collection.saveBook(book, false);
return true; return true;
case REMOVE_FROM_FAVORITES_ITEM_ID: case REMOVE_FROM_FAVORITES_ITEM_ID:
myRootTree.Collection.removeLabel(book, Book.FAVORITE_LABEL); book.removeLabel(Book.FAVORITE_LABEL);
myRootTree.Collection.saveBook(book, false);
if (getCurrentTree().onBookEvent(BookEvent.Updated, book)) { if (getCurrentTree().onBookEvent(BookEvent.Updated, book)) {
getListAdapter().replaceAll(getCurrentTree().subTrees()); getListAdapter().replaceAll(getCurrentTree().subTrees());
getListView().invalidateViews(); getListView().invalidateViews();

View file

@ -166,17 +166,6 @@ public class BookCollectionShadow extends AbstractBookCollection implements Serv
} }
} }
public synchronized List<Book> booksForLabel(String label) {
if (myInterface == null) {
return Collections.emptyList();
}
try {
return SerializerUtil.deserializeBookList(myInterface.booksForLabel(label));
} catch (RemoteException e) {
return Collections.emptyList();
}
}
public synchronized Book getRecentBook(int index) { public synchronized Book getRecentBook(int index) {
if (myInterface == null) { if (myInterface == null) {
return null; return null;
@ -335,34 +324,6 @@ public class BookCollectionShadow extends AbstractBookCollection implements Serv
return Collections.emptyList(); return Collections.emptyList();
} }
public synchronized List<String> labels(Book book) {
if (myInterface != null) {
try {
return myInterface.labelsForBook(SerializerUtil.serialize(book));
} catch (RemoteException e) {
}
}
return Collections.emptyList();
}
public synchronized void setLabel(Book book, String label) {
if (myInterface != null) {
try {
myInterface.setLabel(SerializerUtil.serialize(book), label);
} catch (RemoteException e) {
}
}
}
public synchronized void removeLabel(Book book, String label) {
if (myInterface != null) {
try {
myInterface.removeLabel(SerializerUtil.serialize(book), label);
} catch (RemoteException e) {
}
}
}
public synchronized ZLTextPosition getStoredPosition(long bookId) { public synchronized ZLTextPosition getStoredPosition(long bookId) {
if (myInterface == null) { if (myInterface == null) {
return null; return null;

View file

@ -15,7 +15,7 @@ interface LibraryInterface {
int size(); int size();
List<String> books(in String query); List<String> books(in String query);
boolean hasBooks(in String query); boolean hasBooks(in String query);
List<String> booksForLabel(in String label);
List<String> recentBooks(); List<String> recentBooks();
String getBookByFile(in String file); String getBookByFile(in String file);
@ -27,14 +27,10 @@ interface LibraryInterface {
boolean hasSeries(); boolean hasSeries();
List<String> series(); List<String> series();
List<String> tags(); List<String> tags();
List<String> labels();
List<String> titles(in String query); List<String> titles(in String query);
List<String> firstTitleLetters(); List<String> firstTitleLetters();
List<String> labels();
List<String> labelsForBook(in String book);
void setLabel(in String book, in String label);
void removeLabel(in String book, in String label);
boolean saveBook(in String book, in boolean force); boolean saveBook(in String book, in boolean force);
void removeBook(in String book, in boolean deleteFromDisk); void removeBook(in String book, in boolean deleteFromDisk);
void addBookToRecentList(in String book); void addBookToRecentList(in String book);

View file

@ -150,10 +150,6 @@ public class LibraryService extends Service {
return SerializerUtil.serializeBookList(myCollection.recentBooks()); return SerializerUtil.serializeBookList(myCollection.recentBooks());
} }
public List<String> booksForLabel(String label) {
return SerializerUtil.serializeBookList(myCollection.booksForLabel(label));
}
public String getRecentBook(int index) { public String getRecentBook(int index) {
return SerializerUtil.serialize(myCollection.getRecentBook(index)); return SerializerUtil.serialize(myCollection.getRecentBook(index));
} }
@ -220,18 +216,6 @@ public class LibraryService extends Service {
return myCollection.labels(); return myCollection.labels();
} }
public List<String> labelsForBook(String book) {
return myCollection.labels(SerializerUtil.deserializeBook(book));
}
public void setLabel(String book, String label) {
myCollection.setLabel(SerializerUtil.deserializeBook(book), label);
}
public void removeLabel(String book, String label) {
myCollection.removeLabel(SerializerUtil.deserializeBook(book), label);
}
public TextPosition getStoredPosition(long bookId) { public TextPosition getStoredPosition(long bookId) {
final ZLTextPosition position = myCollection.getStoredPosition(bookId); final ZLTextPosition position = myCollection.getStoredPosition(bookId);
if (position == null) { if (position == null) {

View file

@ -468,6 +468,22 @@ final class SQLiteBooksDatabase extends BooksDatabase {
return list; return list;
} }
@Override
protected List<String> listLabels(long bookId) {
final Cursor cursor = myDatabase.rawQuery(
"SELECT Labels.name FROM Labels" +
" INNER JOIN BookLabel ON BookLabel.label_id=Labels.label_id" +
" WHERE BookLabel.book_id=?",
new String[] { String.valueOf(bookId) }
);
final LinkedList<String> names = new LinkedList<String>();
while (cursor.moveToNext()) {
names.add(cursor.getString(0));
}
cursor.close();
return names;
}
private SQLiteStatement myDeleteBookUidsStatement; private SQLiteStatement myDeleteBookUidsStatement;
protected void deleteAllBookUids(long bookId) { protected void deleteAllBookUids(long bookId) {
if (myDeleteBookUidsStatement == null) { if (myDeleteBookUidsStatement == null) {
@ -736,38 +752,6 @@ final class SQLiteBooksDatabase extends BooksDatabase {
return ids; return ids;
} }
@Override
protected List<String> labels() {
final Cursor cursor = myDatabase.rawQuery(
"SELECT Labels.name FROM Labels" +
" INNER JOIN BookLabel ON BookLabel.label_id=Labels.label_id" +
" GROUP BY Labels.name",
null
);
final LinkedList<String> names = new LinkedList<String>();
while (cursor.moveToNext()) {
names.add(cursor.getString(0));
}
cursor.close();
return names;
}
@Override
protected List<String> labels(long bookId) {
final Cursor cursor = myDatabase.rawQuery(
"SELECT Labels.name FROM Labels" +
" INNER JOIN BookLabel ON BookLabel.label_id=Labels.label_id" +
" WHERE BookLabel.book_id=?",
new String[] { String.valueOf(bookId) }
);
final LinkedList<String> names = new LinkedList<String>();
while (cursor.moveToNext()) {
names.add(cursor.getString(0));
}
cursor.close();
return names;
}
private SQLiteStatement mySetLabelStatement; private SQLiteStatement mySetLabelStatement;
@Override @Override
protected void setLabel(long bookId, String label) { protected void setLabel(long bookId, String label) {
@ -797,21 +781,6 @@ final class SQLiteBooksDatabase extends BooksDatabase {
myRemoveLabelStatement.execute(); myRemoveLabelStatement.execute();
} }
@Override
protected List<Long> loadBooksForLabelIds(String label) {
final Cursor cursor = myDatabase.rawQuery(
"SELECT BookLabel.book_id FROM BookLabel" +
" INNER JOIN Labels ON BookLabel.label_id=Labels.label_id" +
" WHERE Labels.name=?", new String[] { label }
);
final LinkedList<Long> ids = new LinkedList<Long>();
while (cursor.moveToNext()) {
ids.add(cursor.getLong(0));
}
cursor.close();
return ids;
}
@Override @Override
protected List<Bookmark> loadInvisibleBookmarks(long bookId) { protected List<Bookmark> loadInvisibleBookmarks(long bookId) {
LinkedList<Bookmark> list = new LinkedList<Bookmark>(); LinkedList<Bookmark> list = new LinkedList<Bookmark>();

View file

@ -46,6 +46,7 @@ public class Book extends TitledEntity {
private volatile String myLanguage; private volatile String myLanguage;
private volatile List<Author> myAuthors; private volatile List<Author> myAuthors;
private volatile List<Tag> myTags; private volatile List<Tag> myTags;
private volatile List<String> myLabels;
private volatile SeriesInfo mySeriesInfo; private volatile SeriesInfo mySeriesInfo;
private volatile List<UID> myUids; private volatile List<UID> myUids;
@ -81,6 +82,7 @@ public class Book extends TitledEntity {
myLanguage = book.myLanguage; myLanguage = book.myLanguage;
myAuthors = book.myAuthors != null ? new ArrayList<Author>(book.myAuthors) : null; myAuthors = book.myAuthors != null ? new ArrayList<Author>(book.myAuthors) : null;
myTags = book.myTags != null ? new ArrayList<Tag>(book.myTags) : null; myTags = book.myTags != null ? new ArrayList<Tag>(book.myTags) : null;
myLabels = book.myLabels != null ? new ArrayList<String>(book.myLabels) : null;
mySeriesInfo = book.mySeriesInfo; mySeriesInfo = book.mySeriesInfo;
} }
@ -114,6 +116,7 @@ public class Book extends TitledEntity {
setTitle(null); setTitle(null);
myAuthors = null; myAuthors = null;
myTags = null; myTags = null;
myLabels = null;
mySeriesInfo = null; mySeriesInfo = null;
myUids = null; myUids = null;
@ -140,6 +143,7 @@ public class Book extends TitledEntity {
void loadLists(BooksDatabase database) { void loadLists(BooksDatabase database) {
myAuthors = database.listAuthors(myId); myAuthors = database.listAuthors(myId);
myTags = database.listTags(myId); myTags = database.listTags(myId);
myLabels = database.listLabels(myId);
mySeriesInfo = database.getSeriesInfo(myId); mySeriesInfo = database.getSeriesInfo(myId);
myUids = database.listUids(myId); myUids = database.listUids(myId);
myIsSaved = true; myIsSaved = true;
@ -324,6 +328,33 @@ public class Book extends TitledEntity {
addTag(Tag.getTag(null, tagName)); addTag(Tag.getTag(null, tagName));
} }
public List<String> labels() {
return myLabels != null ? Collections.unmodifiableList(myLabels) : Collections.<String>emptyList();
}
void addLabelWithNoCheck(String label) {
if (myLabels == null) {
myLabels = new ArrayList<String>();
}
myLabels.add(label);
}
public void addLabel(String label) {
if (myLabels == null) {
myLabels = new ArrayList<String>();
}
if (!myLabels.contains(label)) {
myLabels.add(label);
myIsSaved = false;
}
}
public void removeLabel(String label) {
if (myLabels != null && myLabels.remove(label)) {
myIsSaved = false;
}
}
public List<UID> uids() { public List<UID> uids() {
return myUids != null ? Collections.unmodifiableList(myUids) : Collections.<UID>emptyList(); return myUids != null ? Collections.unmodifiableList(myUids) : Collections.<UID>emptyList();
} }
@ -414,6 +445,17 @@ public class Book extends TitledEntity {
for (Tag tag : tags()) { for (Tag tag : tags()) {
database.saveBookTagInfo(myId, tag); database.saveBookTagInfo(myId, tag);
} }
final List<String> labelsInDb = database.listLabels(myId);
for (String label : labelsInDb) {
if (myLabels == null || !myLabels.contains(label)) {
database.removeLabel(myId, label);
}
}
if (myLabels != null) {
for (String label : myLabels) {
database.setLabel(myId, label);
}
}
database.saveBookSeriesInfo(myId, mySeriesInfo); database.saveBookSeriesInfo(myId, mySeriesInfo);
database.deleteAllBookUids(myId); database.deleteAllBookUids(myId);
for (UID uid : uids()) { for (UID uid : uids()) {

View file

@ -264,10 +264,6 @@ public class BookCollection extends AbstractBookCollection {
return books(myDatabase.loadRecentBookIds()); return books(myDatabase.loadRecentBookIds());
} }
public List<Book> booksForLabel(String label) {
return books(myDatabase.loadBooksForLabelIds(label));
}
private List<Book> books(List<Long> ids) { private List<Book> books(List<Long> ids) {
final List<Book> bookList = new ArrayList<Book>(ids.size()); final List<Book> bookList = new ArrayList<Book>(ids.size());
for (long id : ids) { for (long id : ids) {
@ -313,6 +309,16 @@ public class BookCollection extends AbstractBookCollection {
return new ArrayList<Tag>(tags); return new ArrayList<Tag>(tags);
} }
public List<String> labels() {
final Set<String> labels = new HashSet<String>();
synchronized (myBooksByFile) {
for (Book book : myBooksByFile.values()) {
labels.addAll(book.labels());
}
}
return new ArrayList<String>(labels);
}
public boolean hasSeries() { public boolean hasSeries() {
synchronized (myBooksByFile) { synchronized (myBooksByFile) {
for (Book book : myBooksByFile.values()) { for (Book book : myBooksByFile.values()) {
@ -366,27 +372,6 @@ public class BookCollection extends AbstractBookCollection {
myDatabase.saveRecentBookIds(ids); myDatabase.saveRecentBookIds(ids);
} }
public List<String> labels() {
return myDatabase.labels();
}
public List<String> labels(Book book) {
if (book == null) {
return Collections.<String>emptyList();
}
return myDatabase.labels(book.getId());
}
public void setLabel(Book book, String label) {
myDatabase.setLabel(book.getId(), label);
fireBookEvent(BookEvent.Updated, book);
}
public void removeLabel(Book book, String label) {
myDatabase.removeLabel(book.getId(), label);
fireBookEvent(BookEvent.Updated, book);
}
private void setStatus(Status status) { private void setStatus(Status status) {
myStatus = status; myStatus = status;
fireBuildEvent(status); fireBuildEvent(status);

View file

@ -53,6 +53,7 @@ public abstract class BooksDatabase {
protected abstract List<Author> listAuthors(long bookId); protected abstract List<Author> listAuthors(long bookId);
protected abstract List<Tag> listTags(long bookId); protected abstract List<Tag> listTags(long bookId);
protected abstract List<String> listLabels(long bookId);
protected abstract SeriesInfo getSeriesInfo(long bookId); protected abstract SeriesInfo getSeriesInfo(long bookId);
protected abstract List<UID> listUids(long bookId); protected abstract List<UID> listUids(long bookId);
@ -81,9 +82,6 @@ public abstract class BooksDatabase {
protected abstract List<Long> loadRecentBookIds(); protected abstract List<Long> loadRecentBookIds();
protected abstract void saveRecentBookIds(final List<Long> ids); protected abstract void saveRecentBookIds(final List<Long> ids);
protected abstract List<Long> loadBooksForLabelIds(String label);
protected abstract List<String> labels();
protected abstract List<String> labels(long bookId);
protected abstract void setLabel(long bookId, String label); protected abstract void setLabel(long bookId, String label);
protected abstract void removeLabel(long bookId, String label); protected abstract void removeLabel(long bookId, String label);

View file

@ -58,6 +58,18 @@ public abstract class Filter {
} }
} }
public final static class ByLabel extends Filter {
public final String Label;
public ByLabel(String label) {
Label = label;
}
public boolean matches(Book book) {
return book.labels().contains(Label);
}
}
public final static class ByPattern extends Filter { public final static class ByPattern extends Filter {
public final String Pattern; public final String Pattern;

View file

@ -55,13 +55,6 @@ public interface IBookCollection {
boolean hasBooks(Query query); boolean hasBooks(Query query);
List<String> titles(Query query); List<String> titles(Query query);
List<Book> booksForLabel(String label);
List<String> labels();
List<String> labels(Book book);
void setLabel(Book book, String label);
void removeLabel(Book book, String label);
List<Book> recentBooks(); List<Book> recentBooks();
Book getRecentBook(int index); Book getRecentBook(int index);
void addBookToRecentList(Book book); void addBookToRecentList(Book book);
@ -70,6 +63,7 @@ public interface IBookCollection {
Book getBookById(long id); Book getBookById(long id);
Book getBookByUid(UID uid); Book getBookByUid(UID uid);
List<String> labels();
List<Author> authors(); List<Author> authors();
boolean hasSeries(); boolean hasSeries();
List<String> series(); List<String> series();

View file

@ -81,6 +81,11 @@ class XMLSerializer extends AbstractSerializer {
params[index++] = name; params[index++] = name;
} }
appendTag(buffer, "filter", true, params); appendTag(buffer, "filter", true, params);
} else if (filter instanceof Filter.ByLabel) {
appendTag(buffer, "filter", true,
"type", "label",
"name", ((Filter.ByLabel)filter).Label
);
} else if (filter instanceof Filter.BySeries) { } else if (filter instanceof Filter.BySeries) {
appendTag(buffer, "filter", true, appendTag(buffer, "filter", true,
"type", "series", "type", "series",
@ -156,6 +161,13 @@ class XMLSerializer extends AbstractSerializer {
); );
} }
for (String label : book.labels()) {
appendTag(
buffer, "label", true,
"name", label
);
}
final SeriesInfo seriesInfo = book.getSeriesInfo(); final SeriesInfo seriesInfo = book.getSeriesInfo();
if (seriesInfo != null) { if (seriesInfo != null) {
appendTagWithContent(buffer, "calibre:series", seriesInfo.Series.getTitle()); appendTagWithContent(buffer, "calibre:series", seriesInfo.Series.getTitle());
@ -333,6 +345,7 @@ class XMLSerializer extends AbstractSerializer {
private final ArrayList<UID> myUidList = new ArrayList<UID>(); private final ArrayList<UID> myUidList = new ArrayList<UID>();
private final ArrayList<Author> myAuthors = new ArrayList<Author>(); private final ArrayList<Author> myAuthors = new ArrayList<Author>();
private final ArrayList<Tag> myTags = new ArrayList<Tag>(); private final ArrayList<Tag> myTags = new ArrayList<Tag>();
private final ArrayList<String> myLabels = new ArrayList<String>();
private final StringBuilder myAuthorSortKey = new StringBuilder(); private final StringBuilder myAuthorSortKey = new StringBuilder();
private final StringBuilder myAuthorName = new StringBuilder(); private final StringBuilder myAuthorName = new StringBuilder();
private final StringBuilder mySeriesTitle = new StringBuilder(); private final StringBuilder mySeriesTitle = new StringBuilder();
@ -359,6 +372,7 @@ class XMLSerializer extends AbstractSerializer {
myUidList.clear(); myUidList.clear();
myAuthors.clear(); myAuthors.clear();
myTags.clear(); myTags.clear();
myLabels.clear();
myState = State.READ_NOTHING; myState = State.READ_NOTHING;
} }
@ -381,6 +395,9 @@ class XMLSerializer extends AbstractSerializer {
for (Tag tag : myTags) { for (Tag tag : myTags) {
myBook.addTagWithNoCheck(tag); myBook.addTagWithNoCheck(tag);
} }
for (String label : myLabels) {
myBook.addLabelWithNoCheck(label);
}
for (UID uid : myUidList) { for (UID uid : myUidList) {
myBook.addUid(uid); myBook.addUid(uid);
} }
@ -417,6 +434,11 @@ class XMLSerializer extends AbstractSerializer {
if (term != null) { if (term != null) {
myTags.add(Tag.getTag(term.split("/"))); myTags.add(Tag.getTag(term.split("/")));
} }
} else if ("label".equals(localName)) {
final String name = attributes.getValue("name");
if (name != null) {
myLabels.add(name);
}
} else if ("series".equals(localName) && XMLNamespaces.CalibreMetadata.equals(uri)) { } else if ("series".equals(localName) && XMLNamespaces.CalibreMetadata.equals(uri)) {
myState = State.READ_SERIES_TITLE; myState = State.READ_SERIES_TITLE;
} else if ("series_index".equals(localName) && XMLNamespaces.CalibreMetadata.equals(uri)) { } else if ("series_index".equals(localName) && XMLNamespaces.CalibreMetadata.equals(uri)) {
@ -573,6 +595,8 @@ class XMLSerializer extends AbstractSerializer {
names.add(n); names.add(n);
} }
myFilter = new Filter.ByTag(Tag.getTag(names.toArray(new String[names.size()]))); myFilter = new Filter.ByTag(Tag.getTag(names.toArray(new String[names.size()])));
} else if ("label".equals(type)) {
myFilter = new Filter.ByLabel(attributes.getValue("name"));
} else if ("series".equals(type)) { } else if ("series".equals(type)) {
myFilter = new Filter.BySeries(new Series( myFilter = new Filter.BySeries(new Series(
attributes.getValue("title") attributes.getValue("title")

View file

@ -19,11 +19,41 @@
package org.geometerplus.fbreader.library; package org.geometerplus.fbreader.library;
import org.geometerplus.zlibrary.core.resources.ZLResource;
import org.geometerplus.fbreader.book.*; import org.geometerplus.fbreader.book.*;
public class FavoritesTree extends FirstLevelTree { public class FavoritesTree extends FilteredTree {
private final ZLResource myResource;
FavoritesTree(RootTree root) { FavoritesTree(RootTree root) {
super(root, ROOT_FAVORITES); super(root, new Filter.ByLabel(Book.FAVORITE_LABEL), -1);
myResource = resource().getResource(ROOT_FAVORITES);
}
@Override
public String getName() {
return myResource.getValue();
}
@Override
public String getTreeTitle() {
return getSummary();
}
@Override
public String getSummary() {
return myResource.getResource("summary").getValue();
}
@Override
protected String getStringId() {
return ROOT_FAVORITES;
}
@Override
public boolean isSelectable() {
return false;
} }
@Override @Override
@ -41,26 +71,7 @@ public class FavoritesTree extends FirstLevelTree {
} }
@Override @Override
public void waitForOpening() { protected boolean createSubTree(Book book) {
clear(); return createBookWithAuthorsSubTree(book);
for (Book book : Collection.booksForLabel(Book.FAVORITE_LABEL)) {
createBookWithAuthorsSubTree(book);
}
}
public boolean onBookEvent(BookEvent event, Book book) {
switch (event) {
case Added:
return Collection.labels(book).contains(Book.FAVORITE_LABEL) && createBookWithAuthorsSubTree(book);
case Updated:
{
boolean changed = removeBook(book);
changed |= Collection.labels(book).contains(Book.FAVORITE_LABEL) && createBookWithAuthorsSubTree(book);
return changed;
}
case Removed:
default:
return super.onBookEvent(event, book);
}
} }
} }

View file

@ -49,7 +49,7 @@ abstract class FilteredTree extends LibraryTree {
} }
@Override @Override
public final Status getOpeningStatus() { public Status getOpeningStatus() {
return Status.ALWAYS_RELOAD_BEFORE_OPENING; return Status.ALWAYS_RELOAD_BEFORE_OPENING;
} }