diff options
-rw-r--r-- | dist/changes-5.0.0 | 4 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemwatcher.cpp | 99 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemwatcher.h | 8 | ||||
-rw-r--r-- | tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp | 71 |
4 files changed, 121 insertions, 61 deletions
diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0 index 84add0dfcc..3dec253f59 100644 --- a/dist/changes-5.0.0 +++ b/dist/changes-5.0.0 @@ -170,6 +170,10 @@ QtCore * The default value of the property QSortFilterProxyModel::dynamicSortFilter was changed from false to true. +* QFileSystemWatcher is now able to return failure in case of errors whilst + altering the watchlist in both the singular and QStringList overloads of + addPath and removePath. + QtGui ----- * Accessibility has been refactored. The hierachy of accessible objects is implemented via diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index efa9029d56..29abf96af1 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -425,20 +425,28 @@ QFileSystemWatcher::~QFileSystemWatcher() otherwise the fileChanged() signal is emitted when \a path is modified, renamed or removed. - \note There is a system dependent limit to the number of files and - directories that can be monitored simultaneously. If this limit - has been reached, \a path will not be added to the file system - watcher, and a warning message will be printed to \e{stderr}. + If the watch was successful, true is returned. + + Reasons for a watch failure are generally system-dependent, but + may include the resource not existing, access failures, or the + total watch count limit, if the platform has one. + + \note There may be a system dependent limit to the number of + files and directories that can be monitored simultaneously. + If this limit is been reached, \a path will not be monitored, + and false is returned. \sa addPaths(), removePath() */ -void QFileSystemWatcher::addPath(const QString &path) +bool QFileSystemWatcher::addPath(const QString &path) { if (path.isEmpty()) { qWarning("QFileSystemWatcher::addPath: path is empty"); - return; + return true; } - addPaths(QStringList(path)); + + QStringList paths = addPaths(QStringList(path)); + return paths.isEmpty(); } /*! @@ -451,23 +459,37 @@ void QFileSystemWatcher::addPath(const QString &path) otherwise the fileChanged() signal is emitted when the path is modified, renamed, or removed. - \note There is a system dependent limit to the number of files and - directories that can be monitored simultaneously. If this limit - has been reached, the excess \a paths will not be added to the - file system watcher, and a warning message will be printed to - \e{stderr} for each path that could not be added. + The return value is a list of paths that could not be watched. + + Reasons for a watch failure are generally system-dependent, but + may include the resource not existing, access failures, or the + total watch count limit, if the platform has one. + + \note There may be a system dependent limit to the number of + files and directories that can be monitored simultaneously. + If this limit has been reached, the excess \a paths will not + be monitored, and they will be added to the returned QStringList. \sa addPath(), removePaths() */ -void QFileSystemWatcher::addPaths(const QStringList &paths) +QStringList QFileSystemWatcher::addPaths(const QStringList &paths) { Q_D(QFileSystemWatcher); - if (paths.isEmpty()) { + + QStringList p = paths; + QMutableListIterator<QString> it(p); + + while (it.hasNext()) { + const QString &path = it.next(); + if (path.isEmpty()) + it.remove(); + } + + if (p.isEmpty()) { qWarning("QFileSystemWatcher::addPaths: list is empty"); - return; + return QStringList(); } - QStringList p = paths; QFileSystemWatcherEngine *engine = 0; if(!objectName().startsWith(QLatin1String("_qt_autotest_force_engine_"))) { @@ -495,42 +517,65 @@ void QFileSystemWatcher::addPaths(const QStringList &paths) if(engine) p = engine->addPaths(p, &d->files, &d->directories); - if (!p.isEmpty()) - qWarning("QFileSystemWatcher: failed to add paths: %s", - qPrintable(p.join(QLatin1String(", ")))); + return p; } /*! Removes the specified \a path from the file system watcher. + If the watch is successfully removed, true is returned. + + Reasons for watch removal failing are generally system-dependent, + but may be due to the path having already been deleted, for example. + \sa removePaths(), addPath() */ -void QFileSystemWatcher::removePath(const QString &path) +bool QFileSystemWatcher::removePath(const QString &path) { if (path.isEmpty()) { qWarning("QFileSystemWatcher::removePath: path is empty"); - return; + return true; } - removePaths(QStringList(path)); + + QStringList paths = removePaths(QStringList(path)); + return paths.isEmpty(); } /*! Removes the specified \a paths from the file system watcher. + The return value is a list of paths which were not able to be + unwatched successfully. + + Reasons for watch removal failing are generally system-dependent, + but may be due to the path having already been deleted, for example. + \sa removePath(), addPaths() */ -void QFileSystemWatcher::removePaths(const QStringList &paths) +QStringList QFileSystemWatcher::removePaths(const QStringList &paths) { - if (paths.isEmpty()) { - qWarning("QFileSystemWatcher::removePaths: list is empty"); - return; - } Q_D(QFileSystemWatcher); + QStringList p = paths; + QMutableListIterator<QString> it(p); + + while (it.hasNext()) { + const QString &path = it.next(); + if (path.isEmpty()) + it.remove(); + } + + if (p.isEmpty()) { + qWarning("QFileSystemWatcher::removePaths: list is empty"); + return QStringList(); + } + if (d->native) p = d->native->removePaths(p, &d->files, &d->directories); if (d->poller) p = d->poller->removePaths(p, &d->files, &d->directories); + + return p; } /*! diff --git a/src/corelib/io/qfilesystemwatcher.h b/src/corelib/io/qfilesystemwatcher.h index 763c8de0d6..a6954850f0 100644 --- a/src/corelib/io/qfilesystemwatcher.h +++ b/src/corelib/io/qfilesystemwatcher.h @@ -64,10 +64,10 @@ public: QFileSystemWatcher(const QStringList &paths, QObject *parent = 0); ~QFileSystemWatcher(); - void addPath(const QString &file); - void addPaths(const QStringList &files); - void removePath(const QString &file); - void removePaths(const QStringList &files); + bool addPath(const QString &file); + QStringList addPaths(const QStringList &files); + bool removePath(const QString &file); + QStringList removePaths(const QStringList &files); QStringList files() const; QStringList directories() const; diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp index d0eb360d43..ad29c5769c 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp +++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp @@ -105,8 +105,7 @@ void tst_QFileSystemWatcher::basicTest() // create watcher, forcing it to use a specific backend QFileSystemWatcher watcher; watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); - watcher.removePath(testFile.fileName()); - watcher.addPath(testFile.fileName()); + QVERIFY(watcher.addPath(testFile.fileName())); QSignalSpy changedSpy(&watcher, SIGNAL(fileChanged(const QString &))); QVERIFY(changedSpy.isValid()); @@ -140,7 +139,7 @@ void tst_QFileSystemWatcher::basicTest() changedSpy.clear(); // remove the watch and modify the file, should not get a signal from the watcher - watcher.removePath(testFile.fileName()); + QVERIFY(watcher.removePath(testFile.fileName())); testFile.open(QIODevice::WriteOnly | QIODevice::Truncate); testFile.write(QByteArray("hello universe!")); testFile.close(); @@ -152,19 +151,19 @@ void tst_QFileSystemWatcher::basicTest() QCOMPARE(changedSpy.count(), 0); // readd the file watch with a relative path - watcher.addPath(testFile.fileName().prepend("./")); + QVERIFY(watcher.addPath(testFile.fileName().prepend("./"))); testFile.open(QIODevice::WriteOnly | QIODevice::Truncate); testFile.write(QByteArray("hello multiverse!")); testFile.close(); QTRY_VERIFY(changedSpy.count() > 0); - watcher.removePath(testFile.fileName().prepend("./")); + QVERIFY(watcher.removePath(testFile.fileName().prepend("./"))); changedSpy.clear(); // readd the file watch - watcher.addPath(testFile.fileName()); + QVERIFY(watcher.addPath(testFile.fileName())); // change the permissions, should get a signal from the watcher testFile.setPermissions(QFile::ReadOwner); @@ -179,7 +178,7 @@ void tst_QFileSystemWatcher::basicTest() changedSpy.clear(); // remove the watch and modify file permissions, should not get a signal from the watcher - watcher.removePath(testFile.fileName()); + QVERIFY(watcher.removePath(testFile.fileName())); testFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOther); // waiting max 5 seconds for notification for file modification to trigger @@ -189,7 +188,7 @@ void tst_QFileSystemWatcher::basicTest() QCOMPARE(changedSpy.count(), 0); // readd the file watch - watcher.addPath(testFile.fileName()); + QVERIFY(watcher.addPath(testFile.fileName())); // remove the file, should get a signal from the watcher QVERIFY(testFile.remove()); @@ -231,7 +230,7 @@ void tst_QFileSystemWatcher::watchDirectory() QFileSystemWatcher watcher; watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); - watcher.addPath(testDir.dirName()); + QVERIFY(watcher.addPath(testDir.dirName())); QSignalSpy changedSpy(&watcher, SIGNAL(directoryChanged(const QString &))); QVERIFY(changedSpy.isValid()); @@ -247,7 +246,7 @@ void tst_QFileSystemWatcher::watchDirectory() QString fileName; // remove the watch, should not get notification of a new file - watcher.removePath(testDir.dirName()); + QVERIFY(watcher.removePath(testDir.dirName())); QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); testFile.close(); @@ -257,7 +256,7 @@ void tst_QFileSystemWatcher::watchDirectory() QCOMPARE(changedSpy.count(), 0); - watcher.addPath(testDir.dirName()); + QVERIFY(watcher.addPath(testDir.dirName())); // remove the file again, should get a signal from the watcher QVERIFY(testFile.remove()); @@ -300,30 +299,32 @@ void tst_QFileSystemWatcher::addPath() { QFileSystemWatcher watcher; QString home = QDir::homePath(); - watcher.addPath(home); + QVERIFY(watcher.addPath(home)); QCOMPARE(watcher.directories().count(), 1); QCOMPARE(watcher.directories().first(), home); - watcher.addPath(home); + + // second watch on an already-watched path should fail + QVERIFY(!watcher.addPath(home)); QCOMPARE(watcher.directories().count(), 1); // With empty string QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::addPath: path is empty"); - watcher.addPath(QString()); + QVERIFY(watcher.addPath(QString())); } void tst_QFileSystemWatcher::removePath() { QFileSystemWatcher watcher; QString home = QDir::homePath(); - watcher.addPath(home); - watcher.removePath(home); + QVERIFY(watcher.addPath(home)); + QVERIFY(watcher.removePath(home)); QCOMPARE(watcher.directories().count(), 0); - watcher.removePath(home); + QVERIFY(!watcher.removePath(home)); QCOMPARE(watcher.directories().count(), 0); // With empty string QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::removePath: path is empty"); - watcher.removePath(QString()); + QVERIFY(watcher.removePath(QString())); } void tst_QFileSystemWatcher::addPaths() @@ -331,13 +332,13 @@ void tst_QFileSystemWatcher::addPaths() QFileSystemWatcher watcher; QStringList paths; paths << QDir::homePath() << QDir::currentPath(); - watcher.addPaths(paths); + QCOMPARE(watcher.addPaths(paths), QStringList()); QCOMPARE(watcher.directories().count(), 2); // With empty list paths.clear(); QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::addPaths: list is empty"); - watcher.addPaths(paths); + QCOMPARE(watcher.addPaths(paths), QStringList()); } void tst_QFileSystemWatcher::removePaths() @@ -345,9 +346,9 @@ void tst_QFileSystemWatcher::removePaths() QFileSystemWatcher watcher; QStringList paths; paths << QDir::homePath() << QDir::currentPath(); - watcher.addPaths(paths); + QCOMPARE(watcher.addPaths(paths), QStringList()); QCOMPARE(watcher.directories().count(), 2); - watcher.removePaths(paths); + QCOMPARE(watcher.removePaths(paths), QStringList()); QCOMPARE(watcher.directories().count(), 0); //With empty list @@ -377,8 +378,8 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QFileSystemWatcher watcher; watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); - watcher.addPath(testDir.dirName()); - watcher.addPath(testFileName); + QVERIFY(watcher.addPath(testDir.dirName())); + QVERIFY(watcher.addPath(testFileName)); QSignalSpy fileChangedSpy(&watcher, SIGNAL(fileChanged(const QString &))); QSignalSpy dirChangedSpy(&watcher, SIGNAL(directoryChanged(const QString &))); @@ -433,7 +434,8 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() fileChangedSpy.clear(); dirChangedSpy.clear(); - watcher.removePath(testFileName); + // removing a deleted file should fail + QVERIFY(!watcher.removePath(testFileName)); QFile::remove(secondFileName); timer.start(3000); @@ -458,8 +460,17 @@ void tst_QFileSystemWatcher::nonExistingFile() { // Don't crash... QFileSystemWatcher watcher; - watcher.addPath("file_that_does_not_exist.txt"); - QVERIFY(true); + QVERIFY(!watcher.addPath("file_that_does_not_exist.txt")); + + // Test that the paths returned in error aren't messed with + QCOMPARE(watcher.addPaths(QStringList() << "../..//./does-not-exist"), + QStringList() << "../..//./does-not-exist"); + + // empty path is not actually a failure + QCOMPARE(watcher.addPaths(QStringList() << QString()), QStringList()); + + // empty path is not actually a failure + QCOMPARE(watcher.removePaths(QStringList() << QString()), QStringList()); } void tst_QFileSystemWatcher::removeFileAndUnWatch() @@ -472,17 +483,17 @@ void tst_QFileSystemWatcher::removeFileAndUnWatch() testFile.open(QIODevice::WriteOnly); testFile.close(); } - watcher.addPath(filename); + QVERIFY(watcher.addPath(filename)); QFile::remove(filename); - watcher.removePath(filename); + QVERIFY(watcher.removePath(filename)); { QFile testFile(filename); testFile.open(QIODevice::WriteOnly); testFile.close(); } - watcher.addPath(filename); + QVERIFY(watcher.addPath(filename)); } class SomeSingleton : public QObject |