summaryrefslogtreecommitdiffstats
path: root/src/widgets/dialogs/qfilesystemmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/dialogs/qfilesystemmodel.cpp')
-rw-r--r--src/widgets/dialogs/qfilesystemmodel.cpp93
1 files changed, 78 insertions, 15 deletions
diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp
index 14ac6ad31b..33b8b51216 100644
--- a/src/widgets/dialogs/qfilesystemmodel.cpp
+++ b/src/widgets/dialogs/qfilesystemmodel.cpp
@@ -207,14 +207,17 @@ bool QFileSystemModel::remove(const QModelIndex &aindex)
const QString path = d->filePath(aindex);
const QFileInfo fileInfo(path);
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+ // QTBUG-65683: Remove file system watchers prior to deletion to prevent
+ // failure due to locked files on Windows.
+ const QStringList watchedPaths = d->unwatchPathsAt(aindex);
+#endif // filesystemwatcher && Q_OS_WIN
const bool success = (fileInfo.isFile() || fileInfo.isSymLink())
? QFile::remove(path) : QDir(path).removeRecursively();
-#ifndef QT_NO_FILESYSTEMWATCHER
- if (success) {
- QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
- d->fileInfoGatherer.removePath(path);
- }
-#endif
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+ if (!success)
+ d->watchPaths(watchedPaths);
+#endif // filesystemwatcher && Q_OS_WIN
return success;
}
@@ -851,6 +854,20 @@ QIcon QFileSystemModelPrivate::icon(const QModelIndex &index) const
return node(index)->icon();
}
+static void displayRenameFailedMessage(const QString &newName)
+{
+#if QT_CONFIG(messagebox)
+ const QString message =
+ QFileSystemModel::tr("<b>The name \"%1\" cannot be used.</b>"
+ "<p>Try using another name, with fewer characters or no punctuation marks.")
+ .arg(newName);
+ QMessageBox::information(nullptr, QFileSystemModel::tr("Invalid filename"),
+ message, QMessageBox::Ok);
+#else
+ Q_UNUSED(newName)
+#endif // QT_CONFIG(messagebox)
+}
+
/*!
\reimp
*/
@@ -871,15 +888,21 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in
const QString parentPath = filePath(parent(idx));
- if (newName.isEmpty()
- || QDir::toNativeSeparators(newName).contains(QDir::separator())
- || !QDir(parentPath).rename(oldName, newName)) {
-#if QT_CONFIG(messagebox)
- QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"),
- QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.")
- .arg(newName),
- QMessageBox::Ok);
-#endif // QT_CONFIG(messagebox)
+ if (newName.isEmpty() || QDir::toNativeSeparators(newName).contains(QDir::separator())) {
+ displayRenameFailedMessage(newName);
+ return false;
+ }
+
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+ // QTBUG-65683: Remove file system watchers prior to renaming to prevent
+ // failure due to locked files on Windows.
+ const QStringList watchedPaths = d->unwatchPathsAt(idx);
+#endif // filesystemwatcher && Q_OS_WIN
+ if (!QDir(parentPath).rename(oldName, newName)) {
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+ d->watchPaths(watchedPaths);
+#endif
+ displayRenameFailedMessage(newName);
return false;
} else {
/*
@@ -1882,6 +1905,46 @@ void QFileSystemModelPrivate::_q_resolvedName(const QString &fileName, const QSt
resolvedSymLinks[fileName] = resolvedName;
}
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+// Remove file system watchers at/below the index and return a list of previously
+// watched files. This should be called prior to operations like rename/remove
+// which might fail due to watchers on platforms like Windows. The watchers
+// should be restored on failure.
+QStringList QFileSystemModelPrivate::unwatchPathsAt(const QModelIndex &index)
+{
+ const QFileSystemModelPrivate::QFileSystemNode *indexNode = node(index);
+ if (indexNode == nullptr)
+ return QStringList();
+ const Qt::CaseSensitivity caseSensitivity = indexNode->caseSensitive()
+ ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ const QString path = indexNode->fileInfo().absoluteFilePath();
+
+ QStringList result;
+ const auto filter = [path, caseSensitivity] (const QString &watchedPath)
+ {
+ const int pathSize = path.size();
+ if (pathSize == watchedPath.size()) {
+ return path.compare(watchedPath, caseSensitivity) == 0;
+ } else if (watchedPath.size() > pathSize) {
+ return watchedPath.at(pathSize) == QLatin1Char('/')
+ && watchedPath.startsWith(path, caseSensitivity);
+ }
+ return false;
+ };
+
+ const QStringList &watchedFiles = fileInfoGatherer.watchedFiles();
+ std::copy_if(watchedFiles.cbegin(), watchedFiles.cend(),
+ std::back_inserter(result), filter);
+
+ const QStringList &watchedDirectories = fileInfoGatherer.watchedDirectories();
+ std::copy_if(watchedDirectories.cbegin(), watchedDirectories.cend(),
+ std::back_inserter(result), filter);
+
+ fileInfoGatherer.unwatchPaths(result);
+ return result;
+}
+#endif // filesystemwatcher && Q_OS_WIN
+
/*!
\internal
*/