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

introduced AbstractBook (base class)

This commit is contained in:
Nikolay Pultsin 2015-05-23 03:14:29 +01:00
parent 79a3d88952
commit 879ac50fa4
12 changed files with 677 additions and 640 deletions

View file

@ -49,6 +49,7 @@ JavaClass AndroidUtil::Class_JavaEncodingCollection("org/geometerplus/zlibrary/c
JavaClass AndroidUtil::Class_NativeFormatPlugin("org/geometerplus/fbreader/formats/NativeFormatPlugin");
JavaClass AndroidUtil::Class_PluginCollection("org/geometerplus/fbreader/formats/PluginCollection");
JavaClass AndroidUtil::Class_Paths("org/geometerplus/fbreader/Paths");
JavaClass AndroidUtil::Class_AbstractBook("org/geometerplus/fbreader/book/AbstractBook");
JavaClass AndroidUtil::Class_Book("org/geometerplus/fbreader/book/Book");
JavaClass AndroidUtil::Class_Tag("org/geometerplus/fbreader/book/Tag");
JavaClass AndroidUtil::Class_BookModel("org/geometerplus/fbreader/bookmodel/BookModel");
@ -186,17 +187,17 @@ bool AndroidUtil::init(JavaVM* jvm) {
StaticMethod_Paths_tempDirectory = new StaticObjectMethod(Class_Paths, "tempDirectory", Class_java_lang_String, "()");
Field_Book_File = new ObjectField(Class_Book, "File", Class_ZLFile);
Method_Book_getTitle = new StringMethod(Class_Book, "getTitle", "()");
Method_Book_getLanguage = new StringMethod(Class_Book, "getLanguage", "()");
Method_Book_getEncodingNoDetection = new StringMethod(Class_Book, "getEncodingNoDetection", "()");
Method_Book_setTitle = new VoidMethod(Class_Book, "setTitle", "(Ljava/lang/String;)");
Method_Book_setSeriesInfo = new VoidMethod(Class_Book, "setSeriesInfo", "(Ljava/lang/String;Ljava/lang/String;)");
Method_Book_setLanguage = new VoidMethod(Class_Book, "setLanguage", "(Ljava/lang/String;)");
Method_Book_setEncoding = new VoidMethod(Class_Book, "setEncoding", "(Ljava/lang/String;)");
Method_Book_addAuthor = new VoidMethod(Class_Book, "addAuthor", "(Ljava/lang/String;Ljava/lang/String;)");
Method_Book_addTag = new VoidMethod(Class_Book, "addTag", "(Lorg/geometerplus/fbreader/book/Tag;)");
Method_Book_addUid = new VoidMethod(Class_Book, "addUid", "(Ljava/lang/String;Ljava/lang/String;)");
Field_Book_File = new ObjectField(Class_AbstractBook, "File", Class_ZLFile);
Method_Book_getTitle = new StringMethod(Class_AbstractBook, "getTitle", "()");
Method_Book_getLanguage = new StringMethod(Class_AbstractBook, "getLanguage", "()");
Method_Book_getEncodingNoDetection = new StringMethod(Class_AbstractBook, "getEncodingNoDetection", "()");
Method_Book_setTitle = new VoidMethod(Class_AbstractBook, "setTitle", "(Ljava/lang/String;)");
Method_Book_setSeriesInfo = new VoidMethod(Class_AbstractBook, "setSeriesInfo", "(Ljava/lang/String;Ljava/lang/String;)");
Method_Book_setLanguage = new VoidMethod(Class_AbstractBook, "setLanguage", "(Ljava/lang/String;)");
Method_Book_setEncoding = new VoidMethod(Class_AbstractBook, "setEncoding", "(Ljava/lang/String;)");
Method_Book_addAuthor = new VoidMethod(Class_AbstractBook, "addAuthor", "(Ljava/lang/String;Ljava/lang/String;)");
Method_Book_addTag = new VoidMethod(Class_AbstractBook, "addTag", "(Lorg/geometerplus/fbreader/book/Tag;)");
Method_Book_addUid = new VoidMethod(Class_AbstractBook, "addUid", "(Ljava/lang/String;Ljava/lang/String;)");
StaticMethod_Tag_getTag = new StaticObjectMethod(Class_Tag, "getTag", Class_Tag, "(Lorg/geometerplus/fbreader/book/Tag;Ljava/lang/String;)");

View file

@ -86,6 +86,7 @@ public:
static JavaClass Class_EncodingConverter;
static JavaClass Class_JavaEncodingCollection;
static JavaClass Class_Paths;
static JavaClass Class_AbstractBook;
static JavaClass Class_Book;
static JavaClass Class_Tag;
static JavaClass Class_BookModel;

View file

@ -0,0 +1,633 @@
/*
* Copyright (C) 2007-2015 FBReader.ORG Limited <contact@fbreader.org>
*
* 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.book;
import java.math.BigDecimal;
import java.util.*;
import org.geometerplus.zlibrary.core.filesystem.*;
import org.geometerplus.zlibrary.core.util.MiscUtil;
import org.geometerplus.zlibrary.core.util.RationalNumber;
import org.geometerplus.fbreader.bookmodel.BookReadingException;
import org.geometerplus.fbreader.formats.PluginCollection;
import org.geometerplus.fbreader.formats.FormatPlugin;
import org.geometerplus.fbreader.sort.TitledEntity;
public class AbstractBook extends TitledEntity<AbstractBook> {
public static final String FAVORITE_LABEL = "favorite";
public static final String READ_LABEL = "read";
public static final String SYNCHRONISED_LABEL = "sync-success";
public static final String SYNC_FAILURE_LABEL = "sync-failure";
public static final String SYNC_DELETED_LABEL = "sync-deleted";
public static final String SYNC_TOSYNC_LABEL = "sync-tosync";
public final ZLFile File;
private volatile long myId;
private volatile String myEncoding;
private volatile String myLanguage;
private volatile List<Author> myAuthors;
private volatile List<Tag> myTags;
private volatile List<String> myLabels;
private volatile SeriesInfo mySeriesInfo;
private volatile List<UID> myUids;
private volatile RationalNumber myProgress;
public volatile boolean HasBookmark;
private volatile boolean myIsSaved;
AbstractBook(long id, ZLFile file, String title, String encoding, String language) {
super(title);
if (file == null) {
throw new IllegalArgumentException("Creating book with no file");
}
myId = id;
File = file;
myEncoding = encoding;
myLanguage = language;
myIsSaved = true;
}
AbstractBook(ZLFile file, FormatPlugin plugin) throws BookReadingException {
super(null);
if (file == null) {
throw new IllegalArgumentException("Creating book with no file");
}
myId = -1;
File = plugin.realBookFile(file);
readMetainfo(plugin);
myIsSaved = false;
}
boolean hasSameMetainfoAs(AbstractBook other) {
return
MiscUtil.equals(getTitle(), other.getTitle()) &&
MiscUtil.equals(myEncoding, other.myEncoding) &&
MiscUtil.equals(myLanguage, other.myLanguage) &&
MiscUtil.equals(myAuthors, other.myAuthors) &&
MiscUtil.listsEquals(myTags, other.myTags) &&
MiscUtil.equals(mySeriesInfo, other.mySeriesInfo) &&
MiscUtil.equals(myUids, other.myUids);
}
void merge(AbstractBook other, AbstractBook base) {
if (!MiscUtil.equals(getTitle(), other.getTitle()) &&
MiscUtil.equals(getTitle(), base.getTitle())) {
setTitle(other.getTitle());
}
if (!MiscUtil.equals(myEncoding, other.myEncoding) &&
MiscUtil.equals(myEncoding, base.myEncoding)) {
setEncoding(other.myEncoding);
}
if (!MiscUtil.equals(myLanguage, other.myLanguage) &&
MiscUtil.equals(myLanguage, base.myLanguage)) {
setLanguage(other.myLanguage);
}
if (!MiscUtil.listsEquals(myTags, other.myTags) &&
MiscUtil.listsEquals(myTags, base.myTags)) {
myTags = other.myTags != null ? new ArrayList<Tag>(other.myTags) : null;
myIsSaved = false;
}
if (!MiscUtil.equals(mySeriesInfo, other.mySeriesInfo) &&
MiscUtil.equals(mySeriesInfo, base.mySeriesInfo)) {
mySeriesInfo = other.mySeriesInfo;
myIsSaved = false;
}
if (!MiscUtil.listsEquals(myUids, other.myUids) &&
MiscUtil.listsEquals(myUids, base.myUids)) {
myUids = other.myUids != null ? new ArrayList<UID>(other.myUids) : null;
myIsSaved = false;
}
}
public void updateFrom(AbstractBook book) {
if (book == null || myId != book.myId) {
return;
}
setTitle(book.getTitle());
setEncoding(book.myEncoding);
setLanguage(book.myLanguage);
if (!MiscUtil.equals(myAuthors, book.myAuthors)) {
myAuthors = book.myAuthors != null ? new ArrayList<Author>(book.myAuthors) : null;
myIsSaved = false;
}
if (!MiscUtil.equals(myTags, book.myTags)) {
myTags = book.myTags != null ? new ArrayList<Tag>(book.myTags) : null;
myIsSaved = false;
}
if (!MiscUtil.listsEquals(myLabels, book.myLabels)) {
myLabels = book.myLabels != null ? new ArrayList<String>(book.myLabels) : null;
myIsSaved = false;
}
if (!MiscUtil.equals(mySeriesInfo, book.mySeriesInfo)) {
mySeriesInfo = book.mySeriesInfo;
myIsSaved = false;
}
if (!MiscUtil.listsEquals(myUids, book.myUids)) {
myUids = book.myUids != null ? new ArrayList<UID>(book.myUids) : null;
myIsSaved = false;
}
setProgress(book.myProgress);
if (HasBookmark != book.HasBookmark) {
HasBookmark = book.HasBookmark;
myIsSaved = false;
}
}
public void reloadInfoFromFile() {
try {
readMetainfo(getPlugin());
} catch (BookReadingException e) {
// ignore
}
}
public FormatPlugin getPlugin() throws BookReadingException {
final FormatPlugin plugin = PluginCollection.Instance().getPlugin(File);
if (plugin == null) {
throw new BookReadingException("pluginNotFound", File);
}
return plugin;
}
void readMetainfo() throws BookReadingException {
readMetainfo(getPlugin());
}
void readMetainfo(FormatPlugin plugin) throws BookReadingException {
myEncoding = null;
myLanguage = null;
setTitle(null);
myAuthors = null;
myTags = null;
mySeriesInfo = null;
myUids = null;
myIsSaved = false;
plugin.readMetainfo(this);
if (myUids == null || myUids.isEmpty()) {
plugin.readUids(this);
}
if (isTitleEmpty()) {
final String fileName = File.getShortName();
final int index = fileName.lastIndexOf('.');
setTitle(index > 0 ? fileName.substring(0, index) : fileName);
}
}
void loadLists(BooksDatabase database) {
myAuthors = database.listAuthors(myId);
myTags = database.listTags(myId);
myLabels = database.listLabels(myId);
mySeriesInfo = database.getSeriesInfo(myId);
myUids = database.listUids(myId);
myProgress = database.getProgress(myId);
HasBookmark = database.hasVisibleBookmark(myId);
myIsSaved = true;
if (myUids == null || myUids.isEmpty()) {
try {
getPlugin().readUids(this);
save(database, false);
} catch (BookReadingException e) {
}
}
}
public List<Author> authors() {
return (myAuthors != null) ? Collections.unmodifiableList(myAuthors) : Collections.<Author>emptyList();
}
void addAuthorWithNoCheck(Author author) {
if (myAuthors == null) {
myAuthors = new ArrayList<Author>();
}
myAuthors.add(author);
}
public void removeAllAuthors() {
if (myAuthors != null) {
myAuthors = null;
myIsSaved = false;
}
}
public void addAuthor(Author author) {
if (author == null) {
return;
}
if (myAuthors == null) {
myAuthors = new ArrayList<Author>();
myAuthors.add(author);
myIsSaved = false;
} else if (!myAuthors.contains(author)) {
myAuthors.add(author);
myIsSaved = false;
}
}
public void addAuthor(String name) {
addAuthor(name, "");
}
public void addAuthor(String name, String sortKey) {
if (name == null) {
return;
}
String strippedName = name.trim();
if (strippedName.length() == 0) {
return;
}
String strippedKey = sortKey != null ? sortKey.trim() : "";
if (strippedKey.length() == 0) {
int index = strippedName.lastIndexOf(' ');
if (index == -1) {
strippedKey = strippedName;
} else {
strippedKey = strippedName.substring(index + 1);
while ((index >= 0) && (strippedName.charAt(index) == ' ')) {
--index;
}
strippedName = strippedName.substring(0, index + 1) + ' ' + strippedKey;
}
}
addAuthor(new Author(strippedName, strippedKey));
}
public long getId() {
return myId;
}
@Override
public void setTitle(String title) {
if (title == null) {
return;
}
title = title.trim();
if (title.length() == 0) {
return;
}
if (!getTitle().equals(title)) {
super.setTitle(title);
myIsSaved = false;
}
}
public SeriesInfo getSeriesInfo() {
return mySeriesInfo;
}
void setSeriesInfoWithNoCheck(String name, String index) {
mySeriesInfo = SeriesInfo.createSeriesInfo(name, index);
}
public void setSeriesInfo(String name, String index) {
setSeriesInfo(name, SeriesInfo.createIndex(index));
}
public void setSeriesInfo(String name, BigDecimal index) {
if (mySeriesInfo == null) {
if (name != null) {
mySeriesInfo = new SeriesInfo(name, index);
myIsSaved = false;
}
} else if (name == null) {
mySeriesInfo = null;
myIsSaved = false;
} else if (!name.equals(mySeriesInfo.Series.getTitle()) || mySeriesInfo.Index != index) {
mySeriesInfo = new SeriesInfo(name, index);
myIsSaved = false;
}
}
@Override
public String getLanguage() {
return myLanguage;
}
public void setLanguage(String language) {
if (!MiscUtil.equals(myLanguage, language)) {
myLanguage = language;
resetSortKey();
myIsSaved = false;
}
}
public String getEncoding() {
if (myEncoding == null) {
try {
getPlugin().detectLanguageAndEncoding(this);
} catch (BookReadingException e) {
}
if (myEncoding == null) {
setEncoding("utf-8");
}
}
return myEncoding;
}
public String getEncodingNoDetection() {
return myEncoding;
}
public void setEncoding(String encoding) {
if (!MiscUtil.equals(myEncoding, encoding)) {
myEncoding = encoding;
myIsSaved = false;
}
}
public List<Tag> tags() {
return myTags != null ? Collections.unmodifiableList(myTags) : Collections.<Tag>emptyList();
}
void addTagWithNoCheck(Tag tag) {
if (myTags == null) {
myTags = new ArrayList<Tag>();
}
myTags.add(tag);
}
public void removeAllTags() {
if (myTags != null) {
myTags = null;
myIsSaved = false;
}
}
public void addTag(Tag tag) {
if (tag != null) {
if (myTags == null) {
myTags = new ArrayList<Tag>();
}
if (!myTags.contains(tag)) {
myTags.add(tag);
myIsSaved = false;
}
}
}
public void addTag(String 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() {
return myUids != null ? Collections.unmodifiableList(myUids) : Collections.<UID>emptyList();
}
public void addUid(String type, String id) {
addUid(new UID(type, id));
}
void addUidWithNoCheck(UID uid) {
if (uid == null) {
return;
}
if (myUids == null) {
myUids = new ArrayList<UID>();
}
myUids.add(uid);
}
public void addUid(UID uid) {
if (uid == null) {
return;
}
if (myUids == null) {
myUids = new ArrayList<UID>();
}
if (!myUids.contains(uid)) {
myUids.add(uid);
myIsSaved = false;
}
}
public boolean matchesUid(UID uid) {
return myUids.contains(uid);
}
public RationalNumber getProgress() {
return myProgress;
}
public void setProgress(RationalNumber progress) {
if (!MiscUtil.equals(myProgress, progress)) {
myProgress = progress;
myIsSaved = false;
}
}
public void setProgressWithNoCheck(RationalNumber progress) {
myProgress = progress;
}
public boolean matches(String pattern) {
if (MiscUtil.matchesIgnoreCase(getTitle(), pattern)) {
return true;
}
if (mySeriesInfo != null && MiscUtil.matchesIgnoreCase(mySeriesInfo.Series.getTitle(), pattern)) {
return true;
}
if (myAuthors != null) {
for (Author author : myAuthors) {
if (MiscUtil.matchesIgnoreCase(author.DisplayName, pattern)) {
return true;
}
}
}
if (myTags != null) {
for (Tag tag : myTags) {
if (MiscUtil.matchesIgnoreCase(tag.Name, pattern)) {
return true;
}
}
}
if (MiscUtil.matchesIgnoreCase(File.getLongName(), pattern)) {
return true;
}
return false;
}
boolean save(final BooksDatabase database, boolean force) {
if (!force && myId != -1 && myIsSaved) {
return false;
}
final boolean[] result = new boolean[] { true };
database.executeAsTransaction(new Runnable() {
public void run() {
if (myId >= 0) {
final FileInfoSet fileInfos = new FileInfoSet(database, File);
database.updateBookInfo(myId, fileInfos.getId(File), myEncoding, myLanguage, getTitle());
} else {
myId = database.insertBookInfo(File, myEncoding, myLanguage, getTitle());
if (myId == -1) {
result[0] = false;
return;
}
if (myVisitedHyperlinks != null) {
for (String linkId : myVisitedHyperlinks) {
database.addVisitedHyperlink(myId, linkId);
}
}
database.addBookHistoryEvent(myId, BooksDatabase.HistoryEvent.Added);
}
long index = 0;
database.deleteAllBookAuthors(myId);
for (Author author : authors()) {
database.saveBookAuthorInfo(myId, index++, author);
}
database.deleteAllBookTags(myId);
for (Tag tag : tags()) {
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.deleteAllBookUids(myId);
for (UID uid : uids()) {
database.saveBookUid(myId, uid);
}
if (myProgress != null) {
database.saveBookProgress(myId, myProgress);
}
}
});
if (result[0]) {
myIsSaved = true;
return true;
} else {
return false;
}
}
private Set<String> myVisitedHyperlinks;
private void initHyperlinkSet(BooksDatabase database) {
if (myVisitedHyperlinks == null) {
myVisitedHyperlinks = new TreeSet<String>();
if (myId != -1) {
myVisitedHyperlinks.addAll(database.loadVisitedHyperlinks(myId));
}
}
}
boolean isHyperlinkVisited(BooksDatabase database, String linkId) {
initHyperlinkSet(database);
return myVisitedHyperlinks.contains(linkId);
}
void markHyperlinkAsVisited(BooksDatabase database, String linkId) {
initHyperlinkSet(database);
if (!myVisitedHyperlinks.contains(linkId)) {
myVisitedHyperlinks.add(linkId);
if (myId != -1) {
database.addVisitedHyperlink(myId, linkId);
}
}
}
@Override
public int hashCode() {
return File.getShortName().hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof AbstractBook)) {
return false;
}
final AbstractBook obook = ((AbstractBook)o);
final ZLFile ofile = obook.File;
if (File.equals(ofile)) {
return true;
}
if (!File.getShortName().equals(ofile.getShortName())) {
return false;
}
if (myUids == null || obook.myUids == null) {
return false;
}
for (UID uid : obook.myUids) {
if (myUids.contains(uid)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return new StringBuilder("Book[")
.append(File.getPath())
.append(", ")
.append(myId)
.append(", ")
.append(getTitle())
.append("]")
.toString();
}
}

View file

@ -19,615 +19,17 @@
package org.geometerplus.fbreader.book;
import java.math.BigDecimal;
import java.util.*;
import org.geometerplus.zlibrary.core.filesystem.*;
import org.geometerplus.zlibrary.core.util.MiscUtil;
import org.geometerplus.zlibrary.core.util.RationalNumber;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.fbreader.bookmodel.BookReadingException;
import org.geometerplus.fbreader.formats.PluginCollection;
import org.geometerplus.fbreader.formats.FormatPlugin;
import org.geometerplus.fbreader.sort.TitledEntity;
public class Book extends TitledEntity<Book> {
public static final String FAVORITE_LABEL = "favorite";
public static final String READ_LABEL = "read";
public static final String SYNCHRONISED_LABEL = "sync-success";
public static final String SYNC_FAILURE_LABEL = "sync-failure";
public static final String SYNC_DELETED_LABEL = "sync-deleted";
public static final String SYNC_TOSYNC_LABEL = "sync-tosync";
public final ZLFile File;
private volatile long myId;
private volatile String myEncoding;
private volatile String myLanguage;
private volatile List<Author> myAuthors;
private volatile List<Tag> myTags;
private volatile List<String> myLabels;
private volatile SeriesInfo mySeriesInfo;
private volatile List<UID> myUids;
private volatile RationalNumber myProgress;
public volatile boolean HasBookmark;
private volatile boolean myIsSaved;
public class Book extends AbstractBook {
Book(long id, ZLFile file, String title, String encoding, String language) {
super(title);
if (file == null) {
throw new IllegalArgumentException("Creating book with no file");
}
myId = id;
File = file;
myEncoding = encoding;
myLanguage = language;
myIsSaved = true;
super(id, file, title, encoding, language);
}
Book(ZLFile file, FormatPlugin plugin) throws BookReadingException {
super(null);
if (file == null) {
throw new IllegalArgumentException("Creating book with no file");
}
myId = -1;
File = plugin.realBookFile(file);
readMetainfo(plugin);
myIsSaved = false;
}
boolean hasSameMetainfoAs(Book other) {
return
MiscUtil.equals(getTitle(), other.getTitle()) &&
MiscUtil.equals(myEncoding, other.myEncoding) &&
MiscUtil.equals(myLanguage, other.myLanguage) &&
MiscUtil.equals(myAuthors, other.myAuthors) &&
MiscUtil.listsEquals(myTags, other.myTags) &&
MiscUtil.equals(mySeriesInfo, other.mySeriesInfo) &&
MiscUtil.equals(myUids, other.myUids);
}
void merge(Book other, Book base) {
if (!MiscUtil.equals(getTitle(), other.getTitle()) &&
MiscUtil.equals(getTitle(), base.getTitle())) {
setTitle(other.getTitle());
}
if (!MiscUtil.equals(myEncoding, other.myEncoding) &&
MiscUtil.equals(myEncoding, base.myEncoding)) {
setEncoding(other.myEncoding);
}
if (!MiscUtil.equals(myLanguage, other.myLanguage) &&
MiscUtil.equals(myLanguage, base.myLanguage)) {
setLanguage(other.myLanguage);
}
if (!MiscUtil.listsEquals(myTags, other.myTags) &&
MiscUtil.listsEquals(myTags, base.myTags)) {
myTags = other.myTags != null ? new ArrayList<Tag>(other.myTags) : null;
myIsSaved = false;
}
if (!MiscUtil.equals(mySeriesInfo, other.mySeriesInfo) &&
MiscUtil.equals(mySeriesInfo, base.mySeriesInfo)) {
mySeriesInfo = other.mySeriesInfo;
myIsSaved = false;
}
if (!MiscUtil.listsEquals(myUids, other.myUids) &&
MiscUtil.listsEquals(myUids, base.myUids)) {
myUids = other.myUids != null ? new ArrayList<UID>(other.myUids) : null;
myIsSaved = false;
}
}
public void updateFrom(Book book) {
if (book == null || myId != book.myId) {
return;
}
setTitle(book.getTitle());
setEncoding(book.myEncoding);
setLanguage(book.myLanguage);
if (!MiscUtil.equals(myAuthors, book.myAuthors)) {
myAuthors = book.myAuthors != null ? new ArrayList<Author>(book.myAuthors) : null;
myIsSaved = false;
}
if (!MiscUtil.equals(myTags, book.myTags)) {
myTags = book.myTags != null ? new ArrayList<Tag>(book.myTags) : null;
myIsSaved = false;
}
if (!MiscUtil.listsEquals(myLabels, book.myLabels)) {
myLabels = book.myLabels != null ? new ArrayList<String>(book.myLabels) : null;
myIsSaved = false;
}
if (!MiscUtil.equals(mySeriesInfo, book.mySeriesInfo)) {
mySeriesInfo = book.mySeriesInfo;
myIsSaved = false;
}
if (!MiscUtil.listsEquals(myUids, book.myUids)) {
myUids = book.myUids != null ? new ArrayList<UID>(book.myUids) : null;
myIsSaved = false;
}
setProgress(book.myProgress);
if (HasBookmark != book.HasBookmark) {
HasBookmark = book.HasBookmark;
myIsSaved = false;
}
}
public void reloadInfoFromFile() {
try {
readMetainfo(getPlugin());
} catch (BookReadingException e) {
// ignore
}
}
public FormatPlugin getPlugin() throws BookReadingException {
final FormatPlugin plugin = PluginCollection.Instance().getPlugin(File);
if (plugin == null) {
throw new BookReadingException("pluginNotFound", File);
}
return plugin;
}
void readMetainfo() throws BookReadingException {
readMetainfo(getPlugin());
}
void readMetainfo(FormatPlugin plugin) throws BookReadingException {
myEncoding = null;
myLanguage = null;
setTitle(null);
myAuthors = null;
myTags = null;
mySeriesInfo = null;
myUids = null;
myIsSaved = false;
plugin.readMetainfo(this);
if (myUids == null || myUids.isEmpty()) {
plugin.readUids(this);
}
if (isTitleEmpty()) {
final String fileName = File.getShortName();
final int index = fileName.lastIndexOf('.');
setTitle(index > 0 ? fileName.substring(0, index) : fileName);
}
}
void loadLists(BooksDatabase database) {
myAuthors = database.listAuthors(myId);
myTags = database.listTags(myId);
myLabels = database.listLabels(myId);
mySeriesInfo = database.getSeriesInfo(myId);
myUids = database.listUids(myId);
myProgress = database.getProgress(myId);
HasBookmark = database.hasVisibleBookmark(myId);
myIsSaved = true;
if (myUids == null || myUids.isEmpty()) {
try {
getPlugin().readUids(this);
save(database, false);
} catch (BookReadingException e) {
}
}
}
public List<Author> authors() {
return (myAuthors != null) ? Collections.unmodifiableList(myAuthors) : Collections.<Author>emptyList();
}
void addAuthorWithNoCheck(Author author) {
if (myAuthors == null) {
myAuthors = new ArrayList<Author>();
}
myAuthors.add(author);
}
public void removeAllAuthors() {
if (myAuthors != null) {
myAuthors = null;
myIsSaved = false;
}
}
public void addAuthor(Author author) {
if (author == null) {
return;
}
if (myAuthors == null) {
myAuthors = new ArrayList<Author>();
myAuthors.add(author);
myIsSaved = false;
} else if (!myAuthors.contains(author)) {
myAuthors.add(author);
myIsSaved = false;
}
}
public void addAuthor(String name) {
addAuthor(name, "");
}
public void addAuthor(String name, String sortKey) {
if (name == null) {
return;
}
String strippedName = name.trim();
if (strippedName.length() == 0) {
return;
}
String strippedKey = sortKey != null ? sortKey.trim() : "";
if (strippedKey.length() == 0) {
int index = strippedName.lastIndexOf(' ');
if (index == -1) {
strippedKey = strippedName;
} else {
strippedKey = strippedName.substring(index + 1);
while ((index >= 0) && (strippedName.charAt(index) == ' ')) {
--index;
}
strippedName = strippedName.substring(0, index + 1) + ' ' + strippedKey;
}
}
addAuthor(new Author(strippedName, strippedKey));
}
public long getId() {
return myId;
}
@Override
public void setTitle(String title) {
if (title == null) {
return;
}
title = title.trim();
if (title.length() == 0) {
return;
}
if (!getTitle().equals(title)) {
super.setTitle(title);
myIsSaved = false;
}
}
public SeriesInfo getSeriesInfo() {
return mySeriesInfo;
}
void setSeriesInfoWithNoCheck(String name, String index) {
mySeriesInfo = SeriesInfo.createSeriesInfo(name, index);
}
public void setSeriesInfo(String name, String index) {
setSeriesInfo(name, SeriesInfo.createIndex(index));
}
public void setSeriesInfo(String name, BigDecimal index) {
if (mySeriesInfo == null) {
if (name != null) {
mySeriesInfo = new SeriesInfo(name, index);
myIsSaved = false;
}
} else if (name == null) {
mySeriesInfo = null;
myIsSaved = false;
} else if (!name.equals(mySeriesInfo.Series.getTitle()) || mySeriesInfo.Index != index) {
mySeriesInfo = new SeriesInfo(name, index);
myIsSaved = false;
}
}
@Override
public String getLanguage() {
return myLanguage;
}
public void setLanguage(String language) {
if (!MiscUtil.equals(myLanguage, language)) {
myLanguage = language;
resetSortKey();
myIsSaved = false;
}
}
public String getEncoding() {
if (myEncoding == null) {
try {
getPlugin().detectLanguageAndEncoding(this);
} catch (BookReadingException e) {
}
if (myEncoding == null) {
setEncoding("utf-8");
}
}
return myEncoding;
}
public String getEncodingNoDetection() {
return myEncoding;
}
public void setEncoding(String encoding) {
if (!MiscUtil.equals(myEncoding, encoding)) {
myEncoding = encoding;
myIsSaved = false;
}
}
public List<Tag> tags() {
return myTags != null ? Collections.unmodifiableList(myTags) : Collections.<Tag>emptyList();
}
void addTagWithNoCheck(Tag tag) {
if (myTags == null) {
myTags = new ArrayList<Tag>();
}
myTags.add(tag);
}
public void removeAllTags() {
if (myTags != null) {
myTags = null;
myIsSaved = false;
}
}
public void addTag(Tag tag) {
if (tag != null) {
if (myTags == null) {
myTags = new ArrayList<Tag>();
}
if (!myTags.contains(tag)) {
myTags.add(tag);
myIsSaved = false;
}
}
}
public void addTag(String 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() {
return myUids != null ? Collections.unmodifiableList(myUids) : Collections.<UID>emptyList();
}
public void addUid(String type, String id) {
addUid(new UID(type, id));
}
void addUidWithNoCheck(UID uid) {
if (uid == null) {
return;
}
if (myUids == null) {
myUids = new ArrayList<UID>();
}
myUids.add(uid);
}
public void addUid(UID uid) {
if (uid == null) {
return;
}
if (myUids == null) {
myUids = new ArrayList<UID>();
}
if (!myUids.contains(uid)) {
myUids.add(uid);
myIsSaved = false;
}
}
public boolean matchesUid(UID uid) {
return myUids.contains(uid);
}
public RationalNumber getProgress() {
return myProgress;
}
public void setProgress(RationalNumber progress) {
if (!MiscUtil.equals(myProgress, progress)) {
myProgress = progress;
myIsSaved = false;
}
}
public void setProgressWithNoCheck(RationalNumber progress) {
myProgress = progress;
}
public boolean matches(String pattern) {
if (MiscUtil.matchesIgnoreCase(getTitle(), pattern)) {
return true;
}
if (mySeriesInfo != null && MiscUtil.matchesIgnoreCase(mySeriesInfo.Series.getTitle(), pattern)) {
return true;
}
if (myAuthors != null) {
for (Author author : myAuthors) {
if (MiscUtil.matchesIgnoreCase(author.DisplayName, pattern)) {
return true;
}
}
}
if (myTags != null) {
for (Tag tag : myTags) {
if (MiscUtil.matchesIgnoreCase(tag.Name, pattern)) {
return true;
}
}
}
if (MiscUtil.matchesIgnoreCase(File.getLongName(), pattern)) {
return true;
}
return false;
}
boolean save(final BooksDatabase database, boolean force) {
if (!force && myId != -1 && myIsSaved) {
return false;
}
final boolean[] result = new boolean[] { true };
database.executeAsTransaction(new Runnable() {
public void run() {
if (myId >= 0) {
final FileInfoSet fileInfos = new FileInfoSet(database, File);
database.updateBookInfo(myId, fileInfos.getId(File), myEncoding, myLanguage, getTitle());
} else {
myId = database.insertBookInfo(File, myEncoding, myLanguage, getTitle());
if (myId == -1) {
result[0] = false;
return;
}
if (myVisitedHyperlinks != null) {
for (String linkId : myVisitedHyperlinks) {
database.addVisitedHyperlink(myId, linkId);
}
}
database.addBookHistoryEvent(myId, BooksDatabase.HistoryEvent.Added);
}
long index = 0;
database.deleteAllBookAuthors(myId);
for (Author author : authors()) {
database.saveBookAuthorInfo(myId, index++, author);
}
database.deleteAllBookTags(myId);
for (Tag tag : tags()) {
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.deleteAllBookUids(myId);
for (UID uid : uids()) {
database.saveBookUid(myId, uid);
}
if (myProgress != null) {
database.saveBookProgress(myId, myProgress);
}
}
});
if (result[0]) {
myIsSaved = true;
return true;
} else {
return false;
}
}
private Set<String> myVisitedHyperlinks;
private void initHyperlinkSet(BooksDatabase database) {
if (myVisitedHyperlinks == null) {
myVisitedHyperlinks = new TreeSet<String>();
if (myId != -1) {
myVisitedHyperlinks.addAll(database.loadVisitedHyperlinks(myId));
}
}
}
boolean isHyperlinkVisited(BooksDatabase database, String linkId) {
initHyperlinkSet(database);
return myVisitedHyperlinks.contains(linkId);
}
void markHyperlinkAsVisited(BooksDatabase database, String linkId) {
initHyperlinkSet(database);
if (!myVisitedHyperlinks.contains(linkId)) {
myVisitedHyperlinks.add(linkId);
if (myId != -1) {
database.addVisitedHyperlink(myId, linkId);
}
}
}
@Override
public int hashCode() {
return File.getShortName().hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Book)) {
return false;
}
final Book obook = ((Book)o);
final ZLFile ofile = obook.File;
if (File.equals(ofile)) {
return true;
}
if (!File.getShortName().equals(ofile.getShortName())) {
return false;
}
if (myUids == null || obook.myUids == null) {
return false;
}
for (UID uid : obook.myUids) {
if (myUids.contains(uid)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return new StringBuilder("Book[")
.append(File.getPath())
.append(", ")
.append(myId)
.append(", ")
.append(getTitle())
.append("]")
.toString();
super(file, plugin);
}
}

View file

@ -19,7 +19,7 @@
package org.geometerplus.fbreader.formats;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.AbstractBook;
public class ComicBookPlugin extends ExternalFormatPlugin {
public ComicBookPlugin() {
@ -32,7 +32,7 @@ public class ComicBookPlugin extends ExternalFormatPlugin {
}
@Override
public void readMetainfo(Book book) {
public void readMetainfo(AbstractBook book) {
// TODO: implement
}
}

View file

@ -19,7 +19,7 @@
package org.geometerplus.fbreader.formats;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.AbstractBook;
public class DjVuPlugin extends ExternalFormatPlugin {
public DjVuPlugin() {
@ -32,7 +32,7 @@ public class DjVuPlugin extends ExternalFormatPlugin {
}
@Override
public void readMetainfo(Book book) {
public void readMetainfo(AbstractBook book) {
// TODO: implement
}
}

View file

@ -22,7 +22,7 @@ package org.geometerplus.fbreader.formats;
import org.geometerplus.zlibrary.core.encodings.AutoEncodingCollection;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.AbstractBook;
import org.geometerplus.fbreader.book.BookUtil;
public abstract class ExternalFormatPlugin extends FormatPlugin {
@ -48,7 +48,7 @@ public abstract class ExternalFormatPlugin extends FormatPlugin {
}
@Override
public void detectLanguageAndEncoding(Book book) {
public void detectLanguageAndEncoding(AbstractBook book) {
}
@Override
@ -57,7 +57,7 @@ public abstract class ExternalFormatPlugin extends FormatPlugin {
}
@Override
public void readUids(Book book) {
public void readUids(AbstractBook book) {
if (book.uids().isEmpty()) {
book.addUid(BookUtil.createUid(book.File, "SHA-256"));
}

View file

@ -28,7 +28,7 @@ import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.image.ZLImage;
import org.geometerplus.zlibrary.core.resources.ZLResource;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.AbstractBook;
import org.geometerplus.fbreader.bookmodel.BookReadingException;
public abstract class FormatPlugin {
@ -49,12 +49,12 @@ public abstract class FormatPlugin {
public ZLFile realBookFile(ZLFile file) throws BookReadingException {
return file;
}
public List<FileEncryptionInfo> readEncryptionInfos(Book book) {
public List<FileEncryptionInfo> readEncryptionInfos(AbstractBook book) {
return Collections.emptyList();
}
public abstract void readMetainfo(Book book) throws BookReadingException;
public abstract void readUids(Book book) throws BookReadingException;
public abstract void detectLanguageAndEncoding(Book book) throws BookReadingException;
public abstract void readMetainfo(AbstractBook book) throws BookReadingException;
public abstract void readUids(AbstractBook book) throws BookReadingException;
public abstract void detectLanguageAndEncoding(AbstractBook book) throws BookReadingException;
public abstract ZLImage readCover(ZLFile file);
public abstract String readAnnotation(ZLFile file);

View file

@ -28,7 +28,7 @@ import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.image.*;
import org.geometerplus.zlibrary.text.model.CachedCharStorageException;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.AbstractBook;
import org.geometerplus.fbreader.book.BookUtil;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.bookmodel.BookReadingException;
@ -51,7 +51,7 @@ public class NativeFormatPlugin extends BuiltinFormatPlugin {
}
@Override
synchronized public void readMetainfo(Book book) throws BookReadingException {
synchronized public void readMetainfo(AbstractBook book) throws BookReadingException {
final int code = readMetainfoNative(book);
if (code != 0) {
throw new BookReadingException(
@ -62,34 +62,34 @@ public class NativeFormatPlugin extends BuiltinFormatPlugin {
}
}
private native int readMetainfoNative(Book book);
private native int readMetainfoNative(AbstractBook book);
@Override
public List<FileEncryptionInfo> readEncryptionInfos(Book book) {
public List<FileEncryptionInfo> readEncryptionInfos(AbstractBook book) {
final FileEncryptionInfo[] infos = readEncryptionInfosNative(book);
return infos != null
? Arrays.<FileEncryptionInfo>asList(infos)
: Collections.<FileEncryptionInfo>emptyList();
}
private native FileEncryptionInfo[] readEncryptionInfosNative(Book book);
private native FileEncryptionInfo[] readEncryptionInfosNative(AbstractBook book);
@Override
synchronized public void readUids(Book book) throws BookReadingException {
synchronized public void readUids(AbstractBook book) throws BookReadingException {
readUidsNative(book);
if (book.uids().isEmpty()) {
book.addUid(BookUtil.createUid(book.File, "SHA-256"));
}
}
private native boolean readUidsNative(Book book);
private native boolean readUidsNative(AbstractBook book);
@Override
public void detectLanguageAndEncoding(Book book) {
public void detectLanguageAndEncoding(AbstractBook book) {
detectLanguageAndEncodingNative(book);
}
public native void detectLanguageAndEncodingNative(Book book);
public native void detectLanguageAndEncodingNative(AbstractBook book);
@Override
synchronized public void readModel(BookModel model) throws BookReadingException {

View file

@ -23,7 +23,7 @@ import org.pdfparse.model.PDFDocInfo;
import org.pdfparse.model.PDFDocument;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.AbstractBook;
import org.geometerplus.fbreader.bookmodel.BookReadingException;
public class PDFPlugin extends ExternalFormatPlugin {
@ -37,7 +37,7 @@ public class PDFPlugin extends ExternalFormatPlugin {
}
@Override
public void readMetainfo(Book book) {
public void readMetainfo(AbstractBook book) {
final ZLFile file = book.File;
if (file != file.getPhysicalFile()) {
// TODO: throw BookReadingException

View file

@ -28,7 +28,7 @@ import org.geometerplus.zlibrary.core.encodings.AutoEncodingCollection;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.AbstractBook;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.bookmodel.BookReadingException;
import org.geometerplus.fbreader.formats.NativeFormatPlugin;
@ -103,7 +103,7 @@ public class FB2NativePlugin extends NativeFormatPlugin {
}
@Override
public void detectLanguageAndEncoding(Book book) {
public void detectLanguageAndEncoding(AbstractBook book) {
book.setEncoding("auto");
}

View file

@ -26,7 +26,7 @@ import org.geometerplus.zlibrary.core.encodings.EncodingCollection;
import org.geometerplus.zlibrary.core.encodings.AutoEncodingCollection;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.AbstractBook;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.bookmodel.BookReadingException;
import org.geometerplus.fbreader.formats.NativeFormatPlugin;
@ -60,7 +60,7 @@ public class OEBNativePlugin extends NativeFormatPlugin {
}
@Override
public void detectLanguageAndEncoding(Book book) {
public void detectLanguageAndEncoding(AbstractBook book) {
book.setEncoding("auto");
}