/** * Creates a new instance of watcher thread. The watcher is not started but keeps the references * to the directory to be watched, and the associated filter. The lastPass member is used to * detect modification/creation of files between two passes. */ Watcher::Watcher(QString url, bool recursive, Filter *filterP) : QThread(), m_watchSem(1) { m_url = url; m_recursive = recursive; m_filterP = filterP; m_lastPass = QDateTime::currentDateTime(); // connect the activity signals/slots connect(this, SIGNAL(displayActivity(QString)), filterP, SIGNAL(displayActivity(QString))); connect(this, SIGNAL(displayProgress(int,int,int)), filterP, SIGNAL(displayProgress(int,int,int))); // connect the scan results signals/slots connect(this, SIGNAL(fileAdded(QString)), filterP, SLOT(fileAdded(QString))); connect(this, SIGNAL(fileDeleted(QString)), filterP, SLOT(fileDeleted(QString))); connect(this, SIGNAL(fileModified(QString)), filterP, SLOT(fileModified(QString))); connect(this, SIGNAL(directoryAdded(QString)), filterP, SLOT(directoryAdded(QString))); connect(this, SIGNAL(directoryDeleted(QString)), filterP, SLOT(directoryDeleted(QString))); connect(this, SIGNAL(directoryModified(QString)), filterP, SLOT(directoryModified(QString))); }
bool DirectoryUtilities::removeDirectory(const QDir &dir, bool deleteRootDirectory) { bool ok = true; // QDir::NoDotAndDotDot if (dir.exists()) { QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files); int count = entries.size(); for (int i = 0; i < count && ok; i++) { QFileInfo entryInfo = entries[i]; QString path = entryInfo.absoluteFilePath(); if (entryInfo.isDir()) { ok = removeDirectory(QDir(path), true); } else { QFile file(path); if (!file.remove()) { ok = false; ERROR_LOG("No s'ha pogut esborrar el fitxer " + path); } else { emit directoryDeleted(); QCoreApplication::processEvents(); } } } if (deleteRootDirectory) { if (!dir.rmdir(dir.absolutePath())) { ok = false; ERROR_LOG("No s'ha pogut esborrar el directori " + dir.absolutePath()); } } } return ok; }
/** * This is the watcher thread main stuff. It iterates on watching its 'known' directories and * notifying the associated filter with the directories/files changes. */ void Watcher::run() { QTime passStart; int numEntries = 0; const QList<PathSegment *> *pathsP = NULL; // do nothing if no root url set if (m_url.isEmpty()) return; m_stop = false; m_numWatchedFiles = 0; // we'll start by scanning this one m_files.addPath(m_url, true); do { passStart.restart(); #ifdef _VERBOSE_WATCHER qDebug() << "(File)Watcher does a pass at " << passStart; #endif // now, don't let the filter play concurrently if (!tryAcquireWatchSemaphore()) goto nextPass; // check for new or modified files/directories pathsP = m_files.getPaths(true); numEntries = pathsP->count(); for (int i = 0; !m_stop && i < numEntries; i++) { QString filepath = pathsP->at(i)->getPath(); // show progress displayActivity(tr("Scanning directory %1").arg(filepath)); displayProgress(0, numEntries - 1, i); watchDirectory(filepath); } // add the new files and directories to the watch lists #ifdef _VERBOSE_PATH m_files.dump("dumping watched files before merging"); m_newFiles.dump("dumping new files before merging"); #endif m_files.merge(&m_newFiles); m_newFiles.deleteAll(); #ifdef _VERBOSE_PATH m_files.dump("dumping watched files after merging"); m_newFiles.dump("dumping new files after merging"); #endif // now check if any of the watched files have disappeared // check removed directories for (QList<PathSegment *>::const_iterator i = m_files.getPaths(true)->begin(); i != m_files.getPaths(true)->end(); i++) { QString filepath = (*i)->getPath(); QFileInfoExt entryInfo(filepath); if (!entryInfo.exists()) { // we DO NOT need to check the content and signal for everything... // because the content will be checked later on... #ifdef _VERBOSE_WATCHER qDebug() << "Detected deleted directory " << filepath; #endif directoryDeleted(filepath); m_removedFiles.addPath(filepath, true); } } // check removed files for (QList<PathSegment *>::const_iterator i = m_files.getPaths()->begin(); !m_stop && i != m_files.getPaths()->end(); i++) { QString filepath = (*i)->getPath(); QFileInfoExt entryInfo(filepath); if (!entryInfo.exists()) { #ifdef _VERBOSE_WATCHER qDebug() << "Detected deleted file " << filepath; #endif // fileDeleted(filepath); fileDeleted(entryInfo.absoluteFilePath()); m_removedFiles.addPath(filepath); --m_numWatchedFiles; } } // and remove // directories for (QList<PathSegment *>::const_iterator i = m_removedFiles.getPaths(true)->begin(); i != m_removedFiles.getPaths(true)->end(); i++) m_files.deletePath((*i)->getPath(), true); // files for (QList<PathSegment *>::const_iterator i = m_removedFiles.getPaths()->begin(); !m_stop && i != m_removedFiles.getPaths()->end(); i++) m_files.deletePath((*i)->getPath()); m_removedFiles.deleteAll(); // keep last pass time m_lastPass = QDateTime::currentDateTime(); // now, the filter can play releaseWatchSemaphore(); nextPass: #ifdef _VERBOSE_WATCHER qDebug() << "(File)Watcher ends pass at " << m_lastPass << " (duration: " << passStart.elapsed() << " ms)"; #endif QString duration; duration.sprintf("%d", passStart.elapsed()); displayActivity(tr("Scanning pass completed in (%1) milliseconds. Now sleeping.").arg(duration)); displayProgress(1, 100, 100); // a little break if (!m_stop) msleep(WATCH_PASS_INTERVAL); } while (!m_stop); #ifdef _VERBOSE_WATCHER qDebug() << "(File)Watcher now EXITING!"; #endif }