QFileInfoGatherer: Make it possible to turn off file watching

Add a boolean watch property and delay-create the file system watcher
in watchPaths(). De-inline the watchedFiles(), watchedDirectories(),
watchPaths(), unwatchPaths() helpers and a check for the watcher.

Task-number: QTBUG-76493
Change-Id: Ie02ac496c8c0246be62bc67ff7e0fcdb990b5ca6
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Friedemann Kleint 2019-07-09 13:22:26 +02:00
parent e8c7124768
commit 9cae146c42
2 changed files with 107 additions and 30 deletions

View File

@ -82,21 +82,6 @@ QFileInfoGatherer::QFileInfoGatherer(QObject *parent)
: QThread(parent)
, m_iconProvider(&defaultProvider)
{
#if QT_CONFIG(filesystemwatcher)
watcher = new QFileSystemWatcher(this);
connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(list(QString)));
connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString)));
# if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
const QVariant listener = watcher->property("_q_driveListener");
if (listener.canConvert<QObject *>()) {
if (QObject *driveListener = listener.value<QObject *>()) {
connect(driveListener, SIGNAL(driveAdded()), this, SLOT(driveAdded()));
connect(driveListener, SIGNAL(driveRemoved()), this, SLOT(driveRemoved()));
}
}
# endif // Q_OS_WIN && !Q_OS_WINRT
#endif
start(LowPriority);
}
@ -177,8 +162,8 @@ void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStr
if (files.isEmpty()
&& !path.isEmpty()
&& !path.startsWith(QLatin1String("//")) /*don't watch UNC path*/) {
if (!watcher->directories().contains(path))
watcher->addPath(path);
if (!watchedDirectories().contains(path))
watchPaths(QStringList(path));
}
#endif
}
@ -195,6 +180,91 @@ void QFileInfoGatherer::updateFile(const QString &filePath)
fetchExtendedInformation(dir, QStringList(fileName));
}
QStringList QFileInfoGatherer::watchedFiles() const
{
#if QT_CONFIG(filesystemwatcher)
if (m_watcher)
return m_watcher->files();
#endif
return {};
}
QStringList QFileInfoGatherer::watchedDirectories() const
{
#if QT_CONFIG(filesystemwatcher)
if (m_watcher)
return m_watcher->directories();
#endif
return {};
}
void QFileInfoGatherer::createWatcher()
{
#if QT_CONFIG(filesystemwatcher)
m_watcher = new QFileSystemWatcher(this);
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &QFileInfoGatherer::list);
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &QFileInfoGatherer::updateFile);
# if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
const QVariant listener = m_watcher->property("_q_driveListener");
if (listener.canConvert<QObject *>()) {
if (QObject *driveListener = listener.value<QObject *>()) {
connect(driveListener, SIGNAL(driveAdded()), this, SLOT(driveAdded()));
connect(driveListener, SIGNAL(driveRemoved()), this, SLOT(driveRemoved()));
}
}
# endif // Q_OS_WIN && !Q_OS_WINRT
#endif
}
void QFileInfoGatherer::watchPaths(const QStringList &paths)
{
#if QT_CONFIG(filesystemwatcher)
if (m_watching) {
if (m_watcher == nullptr)
createWatcher();
m_watcher->addPaths(paths);
}
#else
Q_UNUSED(paths);
#endif
}
void QFileInfoGatherer::unwatchPaths(const QStringList &paths)
{
#if QT_CONFIG(filesystemwatcher)
if (m_watcher)
m_watcher->removePaths(paths);
#else
Q_UNUSED(paths);
#endif
}
bool QFileInfoGatherer::isWatching() const
{
bool result = false;
#if QT_CONFIG(filesystemwatcher)
QMutexLocker locker(&mutex);
result = m_watching;
#endif
return result;
}
void QFileInfoGatherer::setWatching(bool v)
{
#if QT_CONFIG(filesystemwatcher)
QMutexLocker locker(&mutex);
if (v != m_watching) {
if (!v) {
delete m_watcher;
m_watcher = nullptr;
}
m_watching = v;
}
#else
Q_UNUSED(v);
#endif
}
/*
List all files in \a directoryPath
@ -204,8 +274,8 @@ void QFileInfoGatherer::clear()
{
#if QT_CONFIG(filesystemwatcher)
QMutexLocker locker(&mutex);
watcher->removePaths(watcher->files());
watcher->removePaths(watcher->directories());
unwatchPaths(watchedFiles());
unwatchPaths(watchedDirectories());
#endif
}
@ -218,7 +288,7 @@ void QFileInfoGatherer::removePath(const QString &path)
{
#if QT_CONFIG(filesystemwatcher)
QMutexLocker locker(&mutex);
watcher->removePath(path);
unwatchPaths(QStringList(path));
#else
Q_UNUSED(path);
#endif
@ -265,12 +335,13 @@ QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const
static const bool watchFiles = qEnvironmentVariableIsSet("QT_FILESYSTEMMODEL_WATCH_FILES");
if (watchFiles) {
if (!fileInfo.exists() && !fileInfo.isSymLink()) {
watcher->removePath(fileInfo.absoluteFilePath());
const_cast<QFileInfoGatherer *>(this)->
unwatchPaths(QStringList(fileInfo.absoluteFilePath()));
} else {
const QString path = fileInfo.absoluteFilePath();
if (!path.isEmpty() && fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable()
&& !watcher->files().contains(path)) {
watcher->addPath(path);
&& !watchedFiles().contains(path)) {
const_cast<QFileInfoGatherer *>(this)->watchPaths(QStringList(path));
}
}
}

View File

@ -169,12 +169,13 @@ public:
explicit QFileInfoGatherer(QObject *parent = nullptr);
~QFileInfoGatherer();
#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
QStringList watchedFiles() const { return watcher->files(); }
QStringList watchedDirectories() const { return watcher->directories(); }
void watchPaths(const QStringList &paths) { watcher->addPaths(paths); }
void unwatchPaths(const QStringList &paths) { watcher->removePaths(paths); }
#endif // filesystemwatcher && Q_OS_WIN
QStringList watchedFiles() const;
QStringList watchedDirectories() const;
void watchPaths(const QStringList &paths);
void unwatchPaths(const QStringList &paths);
bool isWatching() const;
void setWatching(bool v);
// only callable from this->thread():
void clear();
@ -201,6 +202,8 @@ private:
void fetch(const QFileInfo &info, QElapsedTimer &base, bool &firstTime, QVector<QPair<QString, QFileInfo> > &updatedFiles, const QString &path);
private:
void createWatcher();
mutable QMutex mutex;
// begin protected by mutex
QWaitCondition condition;
@ -210,13 +213,16 @@ private:
QAtomicInt abort;
#if QT_CONFIG(filesystemwatcher)
QFileSystemWatcher *watcher = nullptr;
QFileSystemWatcher *m_watcher = nullptr;
#endif
QFileIconProvider *m_iconProvider; // not accessed by run()
QFileIconProvider defaultProvider;
#ifdef Q_OS_WIN
bool m_resolveSymlinks = true; // not accessed by run()
#endif
#if QT_CONFIG(filesystemwatcher)
bool m_watching = true;
#endif
};
QT_END_NAMESPACE