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:
parent
1e2f1642ae
commit
75943b17bb
4 changed files with 93 additions and 50 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
synchronized (myFilesToRescan) {
|
||||||
myBuildStatus = BuildStatus.Finished;
|
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,7 +325,6 @@ 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);
|
||||||
|
@ -323,7 +353,6 @@ public class BookCollection extends AbstractBookCollection {
|
||||||
orphanedBooks.add(book);
|
orphanedBooks.add(book);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
myDatabase.setExistingFlag(orphanedBooks, false);
|
myDatabase.setExistingFlag(orphanedBooks, false);
|
||||||
|
|
||||||
// Step 3: collect books from physical files; add new, update already added,
|
// Step 3: collect books from physical files; add new, update already added,
|
||||||
|
@ -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);
|
}
|
||||||
|
dirSet.add(entry);
|
||||||
|
for (ZLFile file : entry.children()) {
|
||||||
|
fileQueue.add((ZLPhysicalFile)file);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
file.setCached(true);
|
entry.setCached(true);
|
||||||
fileList.add((ZLPhysicalFile)file);
|
fileList.add(entry);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileList;
|
return fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,9 +113,12 @@ public final class Library {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case Added:
|
case Added:
|
||||||
addBookToLibrary(book);
|
addBookToLibrary(book);
|
||||||
if (Collection.size() % 16 == 0) {
|
synchronized (myStatusLock) {
|
||||||
|
if ((myStatusMask & STATUS_LOADING) == 0 ||
|
||||||
|
Collection.size() % 16 == 0) {
|
||||||
Library.this.fireModelChangedEvent(ChangeListener.Code.BookAdded);
|
Library.this.fireModelChangedEvent(ChangeListener.Code.BookAdded);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue