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

file observer (in progress, works with file adding)

This commit is contained in:
Nikolay Pultsin 2013-01-21 09:00:08 +04:00
parent 1e2f1642ae
commit 75943b17bb
4 changed files with 93 additions and 50 deletions

View file

@ -6,3 +6,6 @@ new:
* update book collection on path changing (from options dialog) * update book collection on path changing (from options dialog)
* read book => go to library => go to book info => update book info => return to reading mode: book info is not updated * read book => go to library => go to book info => update book info => return to reading mode: book info is not updated
* text search => found multiple occurencies => turn page right => right button is disabled * text search => found multiple occurencies => turn page right => right button is disabled
* authors/books by author request
* tags/books by tag request
* series/books by series request

View file

@ -44,8 +44,13 @@ public class LibraryService extends Service {
private static final int MASK = private static final int MASK =
MOVE_SELF | MOVED_TO | MOVED_FROM | DELETE_SELF | DELETE | CLOSE_WRITE | ATTRIB; MOVE_SELF | MOVED_TO | MOVED_FROM | DELETE_SELF | DELETE | CLOSE_WRITE | ATTRIB;
public Observer(String path) { private final String myPrefix;
private final BookCollection myCollection;
public Observer(String path, BookCollection collection) {
super(path, MASK); super(path, MASK);
myPrefix = path + '/';
myCollection = collection;
} }
@Override @Override
@ -57,21 +62,21 @@ public class LibraryService extends Service {
// TODO: File(path) removed; stop watching (?) // TODO: File(path) removed; stop watching (?)
break; break;
case MOVED_TO: case MOVED_TO:
// TODO: File(path) removed; File(path) added myCollection.rescan(myPrefix + path);
break; break;
case MOVED_FROM: case MOVED_FROM:
case DELETE: case DELETE:
// TODO: File(path) removed myCollection.rescan(myPrefix + path);
break; break;
case DELETE_SELF: case DELETE_SELF:
// TODO: File(path) removed; watching is stopped automatically (?) // TODO: File(path) removed; watching is stopped automatically (?)
break; break;
case CLOSE_WRITE: case CLOSE_WRITE:
case ATTRIB: case ATTRIB:
// TODO: File(path) changed (added, removed?) myCollection.rescan(myPrefix + path);
break; break;
default: default:
System.err.println("Unexpected event " + event + " on " + path); System.err.println("Unexpected event " + event + " on " + myPrefix + path);
break; break;
} }
} }
@ -84,7 +89,7 @@ public class LibraryService extends Service {
LibraryImplementation() { LibraryImplementation() {
myCollection = new BookCollection(SQLiteBooksDatabase.Instance(LibraryService.this)); myCollection = new BookCollection(SQLiteBooksDatabase.Instance(LibraryService.this));
for (String path : myCollection.bookDirectories()) { for (String path : myCollection.bookDirectories()) {
final Observer observer = new Observer(path); final Observer observer = new Observer(path, myCollection);
observer.startWatching(); observer.startWatching();
myFileObservers.add(observer); myFileObservers.add(observer);
} }

View file

@ -35,6 +35,8 @@ public class BookCollection extends AbstractBookCollection {
Collections.synchronizedMap(new LinkedHashMap<ZLFile,Book>()); Collections.synchronizedMap(new LinkedHashMap<ZLFile,Book>());
private final Map<Long,Book> myBooksById = private final Map<Long,Book> myBooksById =
Collections.synchronizedMap(new HashMap<Long,Book>()); Collections.synchronizedMap(new HashMap<Long,Book>());
private final List<String> myFilesToRescan =
Collections.synchronizedList(new LinkedList<String>());
private static enum BuildStatus { private static enum BuildStatus {
NotStarted, NotStarted,
@ -257,7 +259,10 @@ public class BookCollection extends AbstractBookCollection {
fireBuildEvent(Listener.BuildEvent.Failed); fireBuildEvent(Listener.BuildEvent.Failed);
} finally { } finally {
fireBuildEvent(Listener.BuildEvent.Completed); fireBuildEvent(Listener.BuildEvent.Completed);
myBuildStatus = BuildStatus.Finished; synchronized (myFilesToRescan) {
myBuildStatus = BuildStatus.Finished;
processFilesQueue();
}
} }
} }
}; };
@ -265,6 +270,32 @@ public class BookCollection extends AbstractBookCollection {
builder.start(); builder.start();
} }
public void rescan(String path) {
synchronized (myFilesToRescan) {
myFilesToRescan.add(path);
processFilesQueue();
}
}
private void processFilesQueue() {
synchronized (myFilesToRescan) {
if (myBuildStatus != BuildStatus.Finished) {
return;
}
for (ZLFile file : collectPhysicalFiles(myFilesToRescan)) {
// TODO:
// collect books from archives
// rescan files and check book id
final Book book = getBookByFile(file);
if (book != null) {
saveBook(book, false);
addBook(book, false);
}
}
myFilesToRescan.clear();
}
}
private void build() { private void build() {
// Step 0: get database books marked as "existing" // Step 0: get database books marked as "existing"
final FileInfoSet fileInfos = new FileInfoSet(myDatabase); final FileInfoSet fileInfos = new FileInfoSet(myDatabase);
@ -294,34 +325,32 @@ public class BookCollection extends AbstractBookCollection {
final Set<ZLPhysicalFile> physicalFiles = new HashSet<ZLPhysicalFile>(); final Set<ZLPhysicalFile> physicalFiles = new HashSet<ZLPhysicalFile>();
int count = 0; int count = 0;
for (Book book : savedBooksByFileId.values()) { for (Book book : savedBooksByFileId.values()) {
synchronized (this) { final ZLPhysicalFile file = book.File.getPhysicalFile();
final ZLPhysicalFile file = book.File.getPhysicalFile(); if (file != null) {
if (file != null) { physicalFiles.add(file);
physicalFiles.add(file); }
} if (file != book.File && file != null && file.getPath().endsWith(".epub")) {
if (file != book.File && file != null && file.getPath().endsWith(".epub")) { continue;
}
if (book.File.exists()) {
boolean doAdd = true;
if (file == null) {
continue; continue;
} }
if (book.File.exists()) { if (!fileInfos.check(file, true)) {
boolean doAdd = true; try {
if (file == null) { book.readMetaInfo();
continue; saveBook(book, false);
} catch (BookReadingException e) {
doAdd = false;
} }
if (!fileInfos.check(file, true)) { file.setCached(false);
try {
book.readMetaInfo();
saveBook(book, false);
} catch (BookReadingException e) {
doAdd = false;
}
file.setCached(false);
}
if (doAdd) {
addBook(book, false);
}
} else {
orphanedBooks.add(book);
} }
if (doAdd) {
addBook(book, false);
}
} else {
orphanedBooks.add(book);
} }
} }
myDatabase.setExistingFlag(orphanedBooks, false); myDatabase.setExistingFlag(orphanedBooks, false);
@ -331,7 +360,7 @@ public class BookCollection extends AbstractBookCollection {
final Map<Long,Book> orphanedBooksByFileId = myDatabase.loadBooks(fileInfos, false); final Map<Long,Book> orphanedBooksByFileId = myDatabase.loadBooks(fileInfos, false);
final Set<Book> newBooks = new HashSet<Book>(); final Set<Book> newBooks = new HashSet<Book>();
final List<ZLPhysicalFile> physicalFilesList = collectPhysicalFiles(); final List<ZLPhysicalFile> physicalFilesList = collectPhysicalFiles(bookDirectories());
for (ZLPhysicalFile file : physicalFilesList) { for (ZLPhysicalFile file : physicalFilesList) {
if (physicalFiles.contains(file)) { if (physicalFiles.contains(file)) {
continue; continue;
@ -376,28 +405,31 @@ public class BookCollection extends AbstractBookCollection {
return Collections.singletonList(Paths.BooksDirectoryOption().getValue()); return Collections.singletonList(Paths.BooksDirectoryOption().getValue());
} }
private List<ZLPhysicalFile> collectPhysicalFiles() { private List<ZLPhysicalFile> collectPhysicalFiles(List<String> directories) {
final Queue<ZLFile> dirQueue = new LinkedList<ZLFile>(); final Queue<ZLPhysicalFile> fileQueue = new LinkedList<ZLPhysicalFile>();
final HashSet<ZLFile> dirSet = new HashSet<ZLFile>(); final HashSet<ZLPhysicalFile> dirSet = new HashSet<ZLPhysicalFile>();
final LinkedList<ZLPhysicalFile> fileList = new LinkedList<ZLPhysicalFile>(); final LinkedList<ZLPhysicalFile> fileList = new LinkedList<ZLPhysicalFile>();
for (String path : bookDirectories()) { for (String path : directories) {
dirQueue.offer(new ZLPhysicalFile(new File(path))); fileQueue.offer(new ZLPhysicalFile(new File(path)));
} }
while (!dirQueue.isEmpty()) { while (!fileQueue.isEmpty()) {
for (ZLFile file : dirQueue.poll().children()) { final ZLPhysicalFile entry = fileQueue.poll();
if (file.isDirectory()) { if (entry.isDirectory()) {
if (!dirSet.contains(file)) { if (dirSet.contains(entry)) {
dirQueue.add(file); continue;
dirSet.add(file);
}
} else {
file.setCached(true);
fileList.add((ZLPhysicalFile)file);
} }
dirSet.add(entry);
for (ZLFile file : entry.children()) {
fileQueue.add((ZLPhysicalFile)file);
}
} else {
entry.setCached(true);
fileList.add(entry);
} }
} }
return fileList; return fileList;
} }

View file

@ -77,7 +77,7 @@ public final class Library {
} }
public final IBookCollection Collection; public final IBookCollection Collection;
private final HashMap<Long,Book> myBooks = Collections.synchronizedMap(new HashMap<Long,Book>()); private final Map<Long,Book> myBooks = Collections.synchronizedMap(new HashMap<Long,Book>());
private final RootTree myRootTree = new RootTree(); private final RootTree myRootTree = new RootTree();
private boolean myDoGroupTitlesByFirstLetter; private boolean myDoGroupTitlesByFirstLetter;
@ -113,8 +113,11 @@ public final class Library {
switch (event) { switch (event) {
case Added: case Added:
addBookToLibrary(book); addBookToLibrary(book);
if (Collection.size() % 16 == 0) { synchronized (myStatusLock) {
Library.this.fireModelChangedEvent(ChangeListener.Code.BookAdded); if ((myStatusMask & STATUS_LOADING) == 0 ||
Collection.size() % 16 == 0) {
Library.this.fireModelChangedEvent(ChangeListener.Code.BookAdded);
}
} }
break; break;
} }