Remove subdirectory watches after a directory is removed from the library. Otherwise subdirectories that changed after the directory was removed would be re-scanned and re-added.

This commit is contained in:
David Sansome 2012-01-29 17:39:28 +00:00
parent b4e1cef2c2
commit facb366017
8 changed files with 42 additions and 26 deletions

View File

@ -26,6 +26,7 @@ class FileSystemWatcherInterface : public QObject {
FileSystemWatcherInterface(QObject* parent = 0); FileSystemWatcherInterface(QObject* parent = 0);
virtual void Init() {} virtual void Init() {}
virtual void AddPath(const QString& path) = 0; virtual void AddPath(const QString& path) = 0;
virtual void RemovePath(const QString& path) = 0;
virtual void Clear() = 0; virtual void Clear() = 0;
static FileSystemWatcherInterface* Create(QObject* parent = 0); static FileSystemWatcherInterface* Create(QObject* parent = 0);

View File

@ -32,6 +32,7 @@ class MacFSListener : public FileSystemWatcherInterface {
explicit MacFSListener(QObject* parent = 0); explicit MacFSListener(QObject* parent = 0);
void Init(); void Init();
void AddPath(const QString& path); void AddPath(const QString& path);
void RemovePath(const QString& path);
void Clear(); void Clear();
signals: signals:

View File

@ -59,6 +59,12 @@ void MacFSListener::AddPath(const QString& path) {
UpdateStream(); UpdateStream();
} }
void MacFSListener::RemovePath(const QString& path) {
Q_ASSERT(run_loop_);
paths_.remove(path);
UpdateStream();
}
void MacFSListener::Clear() { void MacFSListener::Clear() {
paths_.clear(); paths_.clear();
UpdateStream(); UpdateStream();

View File

@ -30,6 +30,10 @@ void QtFSListener::AddPath(const QString& path) {
watcher_.addPath(path); watcher_.addPath(path);
} }
void QtFSListener::RemovePath(const QString& path) {
watcher_.removePath(path);
}
void QtFSListener::Clear() { void QtFSListener::Clear() {
watcher_.removePaths(watcher_.directories()); watcher_.removePaths(watcher_.directories());
watcher_.removePaths(watcher_.files()); watcher_.removePaths(watcher_.files());

View File

@ -27,6 +27,7 @@ class QtFSListener : public FileSystemWatcherInterface {
public: public:
QtFSListener(QObject* parent); QtFSListener(QObject* parent);
virtual void AddPath(const QString& path); virtual void AddPath(const QString& path);
virtual void RemovePath(const QString& path);
virtual void Clear(); virtual void Clear();
private: private:

View File

@ -27,13 +27,17 @@ class QSqlQuery;
struct Directory { struct Directory {
Directory() : id(-1) {} Directory() : id(-1) {}
bool operator ==(const Directory& other) const {
return path == other.path && id == other.id;
}
QString path; QString path;
int id; int id;
}; };
Q_DECLARE_METATYPE(Directory); Q_DECLARE_METATYPE(Directory)
typedef QList<Directory> DirectoryList; typedef QList<Directory> DirectoryList;
Q_DECLARE_METATYPE(DirectoryList); Q_DECLARE_METATYPE(DirectoryList)
struct Subdirectory { struct Subdirectory {
@ -43,9 +47,9 @@ struct Subdirectory {
QString path; QString path;
uint mtime; uint mtime;
}; };
Q_DECLARE_METATYPE(Subdirectory); Q_DECLARE_METATYPE(Subdirectory)
typedef QList<Subdirectory> SubdirectoryList; typedef QList<Subdirectory> SubdirectoryList;
Q_DECLARE_METATYPE(SubdirectoryList); Q_DECLARE_METATYPE(SubdirectoryList)
#endif // DIRECTORY_H #endif // DIRECTORY_H

View File

@ -184,9 +184,7 @@ SubdirectoryList LibraryWatcher::ScanTransaction::GetAllSubdirs() {
} }
void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList& subdirs) { void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList& subdirs) {
DirData data; watched_dirs_[dir.id] = dir;
data.dir = dir;
watched_dirs_[dir.id] = data;
if (subdirs.isEmpty()) { if (subdirs.isEmpty()) {
// This is a new directory that we've never seen before. // This is a new directory that we've never seen before.
@ -208,7 +206,7 @@ void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList&
ScanSubdirectory(subdir.path, subdir, &transaction); ScanSubdirectory(subdir.path, subdir, &transaction);
if (monitor_) if (monitor_)
AddWatch(data, subdir.path); AddWatch(dir, subdir.path);
} }
} }
@ -223,8 +221,8 @@ void LibraryWatcher::ScanSubdirectory(
// Do not scan symlinked dirs that are already in collection // Do not scan symlinked dirs that are already in collection
if (path_info.isSymLink()) { if (path_info.isSymLink()) {
QString real_path = path_info.symLinkTarget(); QString real_path = path_info.symLinkTarget();
foreach (const DirData& dir_data, watched_dirs_) { foreach (const Directory& dir, watched_dirs_) {
if (real_path.startsWith(dir_data.dir.path)) { if (real_path.startsWith(dir.path)) {
t->AddToProgress(1); t->AddToProgress(1);
return; return;
} }
@ -550,7 +548,7 @@ uint LibraryWatcher::GetMtimeForCue(const QString& cue_path) {
: 0; : 0;
} }
void LibraryWatcher::AddWatch(const DirData& dir, const QString& path) { void LibraryWatcher::AddWatch(const Directory& dir, const QString& path) {
if (!QFile::exists(path)) if (!QFile::exists(path))
return; return;
@ -563,6 +561,12 @@ void LibraryWatcher::AddWatch(const DirData& dir, const QString& path) {
void LibraryWatcher::RemoveDirectory(const Directory& dir) { void LibraryWatcher::RemoveDirectory(const Directory& dir) {
rescan_queue_.remove(dir.id); rescan_queue_.remove(dir.id);
watched_dirs_.remove(dir.id); watched_dirs_.remove(dir.id);
// Stop watching the directory's subdirectories
foreach (const QString& subdir_path, subdir_mapping_.keys(dir)) {
fs_watcher_->RemovePath(subdir_path);
subdir_mapping_.remove(subdir_path);
}
} }
bool LibraryWatcher::FindSongByPath(const SongList& list, const QString& path, Song* out) { bool LibraryWatcher::FindSongByPath(const SongList& list, const QString& path, Song* out) {
@ -578,11 +582,11 @@ bool LibraryWatcher::FindSongByPath(const SongList& list, const QString& path, S
void LibraryWatcher::DirectoryChanged(const QString &subdir) { void LibraryWatcher::DirectoryChanged(const QString &subdir) {
// Find what dir it was in // Find what dir it was in
QHash<QString, DirData>::const_iterator it = subdir_mapping_.constFind(subdir); QHash<QString, Directory>::const_iterator it = subdir_mapping_.constFind(subdir);
if (it == subdir_mapping_.constEnd()) { if (it == subdir_mapping_.constEnd()) {
return; return;
} }
Directory dir = it->dir; Directory dir = *it;
qLog(Debug) << "Subdir" << subdir << "changed under directory" << dir.path << "id" << dir.id; qLog(Debug) << "Subdir" << subdir << "changed under directory" << dir.path << "id" << dir.id;
@ -702,10 +706,10 @@ void LibraryWatcher::ReloadSettings() {
fs_watcher_->Clear(); fs_watcher_->Clear();
} else if (monitor_ && !was_monitoring_before) { } else if (monitor_ && !was_monitoring_before) {
// Add all directories to all QFileSystemWatchers again // Add all directories to all QFileSystemWatchers again
foreach (const DirData& data, watched_dirs_.values()) { foreach (const Directory& dir, watched_dirs_.values()) {
SubdirectoryList subdirs = backend_->SubdirsInDirectory(data.dir.id); SubdirectoryList subdirs = backend_->SubdirsInDirectory(dir.id);
foreach (const Subdirectory& subdir, subdirs) { foreach (const Subdirectory& subdir, subdirs) {
AddWatch(data, subdir.path); AddWatch(dir, subdir.path);
} }
} }
} }
@ -739,8 +743,8 @@ void LibraryWatcher::FullScanNow() {
} }
void LibraryWatcher::PerformScan(bool incremental, bool ignore_mtimes) { void LibraryWatcher::PerformScan(bool incremental, bool ignore_mtimes) {
foreach (const DirData& data, watched_dirs_.values()) { foreach (const Directory& dir, watched_dirs_.values()) {
ScanTransaction transaction(this, data.dir.id, ScanTransaction transaction(this, dir.id,
incremental, ignore_mtimes); incremental, ignore_mtimes);
SubdirectoryList subdirs(transaction.GetAllSubdirs()); SubdirectoryList subdirs(transaction.GetAllSubdirs());
transaction.AddToProgressMax(subdirs.count()); transaction.AddToProgressMax(subdirs.count());

View File

@ -140,18 +140,13 @@ class LibraryWatcher : public QObject {
ScanTransaction* t, bool force_noincremental = false); ScanTransaction* t, bool force_noincremental = false);
private: private:
// One of these gets stored for each Directory we're watching
struct DirData {
Directory dir;
};
static bool FindSongByPath(const SongList& list, const QString& path, Song* out); static bool FindSongByPath(const SongList& list, const QString& path, Song* out);
inline static QString NoExtensionPart( const QString &fileName ); inline static QString NoExtensionPart( const QString &fileName );
inline static QString ExtensionPart( const QString &fileName ); inline static QString ExtensionPart( const QString &fileName );
inline static QString DirectoryPart( const QString &fileName ); inline static QString DirectoryPart( const QString &fileName );
QString PickBestImage(const QStringList& images); QString PickBestImage(const QStringList& images);
QString ImageForSong(const QString& path, QMap<QString, QStringList>& album_art); QString ImageForSong(const QString& path, QMap<QString, QStringList>& album_art);
void AddWatch(const DirData& dir, const QString& path); void AddWatch(const Directory& dir, const QString& path);
uint GetMtimeForCue(const QString& cue_path); uint GetMtimeForCue(const QString& cue_path);
void PerformScan(bool incremental, bool ignore_mtimes); void PerformScan(bool incremental, bool ignore_mtimes);
@ -181,7 +176,7 @@ class LibraryWatcher : public QObject {
QString device_name_; QString device_name_;
FileSystemWatcherInterface* fs_watcher_; FileSystemWatcherInterface* fs_watcher_;
QHash<QString, DirData> subdir_mapping_; QHash<QString, Directory> subdir_mapping_;
/* A list of words use to try to identify the (likely) best image /* A list of words use to try to identify the (likely) best image
* found in an directory to use as cover artwork. * found in an directory to use as cover artwork.
@ -194,7 +189,7 @@ class LibraryWatcher : public QObject {
bool scan_on_startup_; bool scan_on_startup_;
bool monitor_; bool monitor_;
QMap<int, DirData> watched_dirs_; QMap<int, Directory> watched_dirs_;
QTimer* rescan_timer_; QTimer* rescan_timer_;
QMap<int, QStringList> rescan_queue_; // dir id -> list of subdirs to be scanned QMap<int, QStringList> rescan_queue_; // dir id -> list of subdirs to be scanned
bool rescan_paused_; bool rescan_paused_;