diff options
Diffstat (limited to 'src/gui/itemmodels/qfilesystemmodel.cpp')
-rw-r--r-- | src/gui/itemmodels/qfilesystemmodel.cpp | 279 |
1 files changed, 171 insertions, 108 deletions
diff --git a/src/gui/itemmodels/qfilesystemmodel.cpp b/src/gui/itemmodels/qfilesystemmodel.cpp index f0dcb6d801..290891322f 100644 --- a/src/gui/itemmodels/qfilesystemmodel.cpp +++ b/src/gui/itemmodels/qfilesystemmodel.cpp @@ -31,6 +31,7 @@ using namespace Qt::StringLiterals; \value FilePathRole \value FileNameRole \value FilePermissions + \value FileInfoRole The QFileInfo object for the index */ /*! @@ -143,7 +144,7 @@ QFileInfo QFileSystemModel::fileInfo(const QModelIndex &index) const \fn void QFileSystemModel::fileRenamed(const QString &path, const QString &oldName, const QString &newName) This signal is emitted whenever a file with the \a oldName is successfully - renamed to \a newName. The file is located in in the directory \a path. + renamed to \a newName. The file is located in the directory \a path. */ /*! @@ -240,7 +241,7 @@ QModelIndex QFileSystemModel::index(int row, int column, const QModelIndex &pare */ QModelIndex QFileSystemModel::sibling(int row, int column, const QModelIndex &idx) const { - if (row == idx.row() && column < QFileSystemModelPrivate::NumColumns) { + if (row == idx.row() && column < columnCount(idx.parent())) { // cheap sibling operation: just adjust the column: return createIndex(row, column, idx.internalPointer()); } else { @@ -394,12 +395,12 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS QFileSystemModelPrivate::QFileSystemNode *parent = node(index); - for (int i = 0; i < pathElements.count(); ++i) { + for (int i = 0; i < pathElements.size(); ++i) { QString element = pathElements.at(i); if (i != 0) elementPath.append(separator); elementPath.append(element); - if (i == pathElements.count() - 1) + if (i == pathElements.size() - 1) elementPath.append(trailingSeparator); #ifdef Q_OS_WIN // On Windows, "filename " and "filename" are equivalent and @@ -420,7 +421,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS // we couldn't find the path element, we create a new node since we // _know_ that the path is valid if (alreadyExisted) { - if ((parent->children.count() == 0) + if ((parent->children.size() == 0) || (parent->caseSensitive() && parent->children.value(element)->fileName != element) || (!parent->caseSensitive() @@ -438,7 +439,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this); node = p->addNode(parent, element,info); #if QT_CONFIG(filesystemwatcher) - node->populate(fileInfoGatherer.getInfo(info)); + node->populate(fileInfoGatherer->getInfo(info)); #endif } else { node = parent->children.value(element); @@ -476,10 +477,10 @@ void QFileSystemModel::timerEvent(QTimerEvent *event) if (event->timerId() == d->fetchingTimer.timerId()) { d->fetchingTimer.stop(); #if QT_CONFIG(filesystemwatcher) - for (int i = 0; i < d->toFetch.count(); ++i) { + for (int i = 0; i < d->toFetch.size(); ++i) { const QFileSystemModelPrivate::QFileSystemNode *node = d->toFetch.at(i).node; if (!node->hasInformation()) { - d->fileInfoGatherer.fetchExtendedInformation(d->toFetch.at(i).dir, + d->fileInfoGatherer->fetchExtendedInformation(d->toFetch.at(i).dir, QStringList(d->toFetch.at(i).file)); } else { // qDebug("yah!, you saved a little gerbil soul"); @@ -529,14 +530,38 @@ QString QFileSystemModel::type(const QModelIndex &index) const } /*! - Returns the date and time when \a index was last modified. + Returns the date and time (in local time) when \a index was last modified. + + This is an overloaded function, equivalent to calling: + \code + lastModified(index, QTimeZone::LocalTime); + \endcode + + If \a index is invalid, a default constructed QDateTime is returned. */ QDateTime QFileSystemModel::lastModified(const QModelIndex &index) const { + return lastModified(index, QTimeZone::LocalTime); +} + +/*! + \since 6.6 + Returns the date and time, in the time zone \a tz, when + \a index was last modified. + + Typical arguments for \a tz are \c QTimeZone::UTC or \c QTimeZone::LocalTime. + UTC does not require any conversion from the time returned by the native file + system API, therefore getting the time in UTC is potentially faster. LocalTime + is typically chosen if the time is shown to the user. + + If \a index is invalid, a default constructed QDateTime is returned. + */ +QDateTime QFileSystemModel::lastModified(const QModelIndex &index, const QTimeZone &tz) const +{ Q_D(const QFileSystemModel); if (!index.isValid()) return QDateTime(); - return d->node(index)->lastModified(); + return d->node(index)->lastModified(tz); } /*! @@ -626,7 +651,7 @@ void QFileSystemModel::fetchMore(const QModelIndex &parent) return; indexNode->populatedChildren = true; #if QT_CONFIG(filesystemwatcher) - d->fileInfoGatherer.list(filePath(parent)); + d->fileInfoGatherer->list(filePath(parent)); #endif } @@ -640,10 +665,10 @@ int QFileSystemModel::rowCount(const QModelIndex &parent) const return 0; if (!parent.isValid()) - return d->root.visibleChildren.count(); + return d->root.visibleChildren.size(); const QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent); - return parentNode->visibleChildren.count(); + return parentNode->visibleChildren.size(); } /*! @@ -669,7 +694,9 @@ QVariant QFileSystemModel::myComputer(int role) const return QFileSystemModelPrivate::myComputer(); #if QT_CONFIG(filesystemwatcher) case Qt::DecorationRole: - return d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::Computer); + if (auto *provider = d->fileInfoGatherer->iconProvider()) + return provider->icon(QAbstractFileIconProvider::Computer); + break; #endif } return QVariant(); @@ -686,15 +713,15 @@ QVariant QFileSystemModel::data(const QModelIndex &index, int role) const switch (role) { case Qt::EditRole: - if (index.column() == 0) + if (index.column() == QFileSystemModelPrivate::NameColumn) return d->name(index); Q_FALLTHROUGH(); case Qt::DisplayRole: switch (index.column()) { - case 0: return d->displayName(index); - case 1: return d->size(index); - case 2: return d->type(index); - case 3: return d->time(index); + case QFileSystemModelPrivate::NameColumn: return d->displayName(index); + case QFileSystemModelPrivate::SizeColumn: return d->size(index); + case QFileSystemModelPrivate::TypeColumn: return d->type(index); + case QFileSystemModelPrivate::TimeColumn: return d->time(index); default: qWarning("data: invalid display value column %d", index.column()); break; @@ -704,22 +731,23 @@ QVariant QFileSystemModel::data(const QModelIndex &index, int role) const return filePath(index); case FileNameRole: return d->name(index); + case FileInfoRole: + return QVariant::fromValue(fileInfo(index)); case Qt::DecorationRole: - if (index.column() == 0) { + if (index.column() == QFileSystemModelPrivate::NameColumn) { QIcon icon = d->icon(index); #if QT_CONFIG(filesystemwatcher) if (icon.isNull()) { - if (d->node(index)->isDir()) - icon = d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::Folder); - else - icon = d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::File); + using P = QAbstractFileIconProvider; + if (auto *provider = d->fileInfoGatherer->iconProvider()) + icon = provider->icon(d->node(index)->isDir() ? P::Folder: P::File); } #endif // filesystemwatcher return icon; } break; case Qt::TextAlignmentRole: - if (index.column() == 1) + if (index.column() == QFileSystemModelPrivate::SizeColumn) return QVariant(Qt::AlignTrailing | Qt::AlignVCenter); break; case FilePermissions: @@ -765,7 +793,7 @@ QString QFileSystemModelPrivate::time(const QModelIndex &index) const if (!index.isValid()) return QString(); #if QT_CONFIG(datestring) - return QLocale::system().toString(node(index)->lastModified(), QLocale::ShortFormat); + return QLocale::system().toString(node(index)->lastModified(QTimeZone::LocalTime), QLocale::ShortFormat); #else Q_UNUSED(index); return QString(); @@ -792,7 +820,7 @@ QString QFileSystemModelPrivate::name(const QModelIndex &index) const QFileSystemNode *dirNode = node(index); if ( #if QT_CONFIG(filesystemwatcher) - fileInfoGatherer.resolveSymlinks() && + fileInfoGatherer->resolveSymlinks() && #endif !resolvedSymLinks.isEmpty() && dirNode->isSymLink(/* ignoreNtfsSymLinks = */ true)) { QString fullPath = QDir::fromNativeSeparators(filePath(index)); @@ -877,7 +905,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in nodeToRename->fileName = newName; nodeToRename->parent = parentNode; #if QT_CONFIG(filesystemwatcher) - nodeToRename->populate(d->fileInfoGatherer.getInfo(QFileInfo(parentPath, newName))); + nodeToRename->populate(d->fileInfoGatherer->getInfo(QFileInfo(parentPath, newName))); #endif nodeToRename->isVisible = true; parentNode->children[newName] = nodeToRename.release(); @@ -913,23 +941,27 @@ QVariant QFileSystemModel::headerData(int section, Qt::Orientation orientation, QString returnValue; switch (section) { - case 0: returnValue = tr("Name"); - break; - case 1: returnValue = tr("Size"); - break; - case 2: returnValue = + case QFileSystemModelPrivate::NameColumn: + returnValue = tr("Name"); + break; + case QFileSystemModelPrivate::SizeColumn: + returnValue = tr("Size"); + break; + case QFileSystemModelPrivate::TypeColumn: + returnValue = #ifdef Q_OS_MAC - tr("Kind", "Match OS X Finder"); + tr("Kind", "Match OS X Finder"); #else - tr("Type", "All other platforms"); + tr("Type", "All other platforms"); #endif - break; + break; // Windows - Type // OS X - Kind // Konqueror - File Type // Nautilus - Type - case 3: returnValue = tr("Date Modified"); - break; + case QFileSystemModelPrivate::TimeColumn: + returnValue = tr("Date Modified"); + break; default: return QVariant(); } return returnValue; @@ -969,7 +1001,7 @@ Qt::ItemFlags QFileSystemModel::flags(const QModelIndex &index) const /*! \internal */ -void QFileSystemModelPrivate::_q_performDelayedSort() +void QFileSystemModelPrivate::performDelayedSort() { Q_Q(QFileSystemModel); q->sort(sortColumn, sortOrder); @@ -993,7 +1025,7 @@ public: const QFileSystemModelPrivate::QFileSystemNode *r) const { switch (sortColumn) { - case 0: { + case QFileSystemModelPrivate::NameColumn: { #ifndef Q_OS_MAC // place directories before files bool left = l->isDir(); @@ -1003,7 +1035,7 @@ public: #endif return naturalCompare.compare(l->fileName, r->fileName) < 0; } - case 1: + case QFileSystemModelPrivate::SizeColumn: { // Directories go first bool left = l->isDir(); @@ -1017,7 +1049,7 @@ public: return sizeDifference < 0; } - case 2: + case QFileSystemModelPrivate::TypeColumn: { int compare = naturalCompare.compare(l->type(), r->type()); if (compare == 0) @@ -1025,12 +1057,14 @@ public: return compare < 0; } - case 3: + case QFileSystemModelPrivate::TimeColumn: { - if (l->lastModified() == r->lastModified()) + const QDateTime left = l->lastModified(QTimeZone::UTC); + const QDateTime right = r->lastModified(QTimeZone::UTC); + if (left == right) return naturalCompare.compare(l->fileName, r->fileName) < 0; - return l->lastModified() < r->lastModified(); + return left < right; } } Q_ASSERT(false); @@ -1058,7 +1092,7 @@ void QFileSystemModelPrivate::sortChildren(int column, const QModelIndex &parent { Q_Q(QFileSystemModel); QFileSystemModelPrivate::QFileSystemNode *indexNode = node(parent); - if (indexNode->children.count() == 0) + if (indexNode->children.size() == 0) return; QList<QFileSystemModelPrivate::QFileSystemNode *> values; @@ -1076,11 +1110,10 @@ void QFileSystemModelPrivate::sortChildren(int column, const QModelIndex &parent indexNode->visibleChildren.clear(); //No more dirty item we reset our internal dirty index indexNode->dirtyChildrenIndex = -1; - const int numValues = values.count(); - indexNode->visibleChildren.reserve(numValues); - for (int i = 0; i < numValues; ++i) { - indexNode->visibleChildren.append(values.at(i)->fileName); - values.at(i)->isVisible = true; + indexNode->visibleChildren.reserve(values.size()); + for (QFileSystemNode *node : std::as_const(values)) { + indexNode->visibleChildren.append(node->fileName); + node->isVisible = true; } if (!disableRecursiveSort) { @@ -1106,10 +1139,8 @@ void QFileSystemModel::sort(int column, Qt::SortOrder order) emit layoutAboutToBeChanged(); QModelIndexList oldList = persistentIndexList(); QList<QPair<QFileSystemModelPrivate::QFileSystemNode *, int>> oldNodes; - const int nodeCount = oldList.count(); - oldNodes.reserve(nodeCount); - for (int i = 0; i < nodeCount; ++i) { - const QModelIndex &oldNode = oldList.at(i); + oldNodes.reserve(oldList.size()); + for (const QModelIndex &oldNode : oldList) { QPair<QFileSystemModelPrivate::QFileSystemNode*, int> pair(d->node(oldNode), oldNode.column()); oldNodes.append(pair); } @@ -1123,12 +1154,10 @@ void QFileSystemModel::sort(int column, Qt::SortOrder order) d->sortOrder = order; QModelIndexList newList; - const int numOldNodes = oldNodes.size(); - newList.reserve(numOldNodes); - for (int i = 0; i < numOldNodes; ++i) { - const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &oldNode = oldNodes.at(i); - newList.append(d->index(oldNode.first, oldNode.second)); - } + newList.reserve(oldNodes.size()); + for (const auto &[node, col]: std::as_const(oldNodes)) + newList.append(d->index(node, col)); + changePersistentIndexList(oldList, newList); emit layoutChanged(); } @@ -1155,7 +1184,7 @@ QMimeData *QFileSystemModel::mimeData(const QModelIndexList &indexes) const QList<QUrl> urls; QList<QModelIndex>::const_iterator it = indexes.begin(); for (; it != indexes.end(); ++it) - if ((*it).column() == 0) + if ((*it).column() == QFileSystemModelPrivate::NameColumn) urls << QUrl::fromLocalFile(filePath(*it)); QMimeData *data = new QMimeData(); data->setUrls(urls); @@ -1229,6 +1258,7 @@ QHash<int, QByteArray> QFileSystemModel::roleNames() const ret.insert(QFileSystemModel::FilePathRole, QByteArrayLiteral("filePath")); ret.insert(QFileSystemModel::FileNameRole, QByteArrayLiteral("fileName")); ret.insert(QFileSystemModel::FilePermissions, QByteArrayLiteral("filePermissions")); + ret.insert(QFileSystemModel::FileInfoRole, QByteArrayLiteral("fileInfo")); return ret; } @@ -1301,7 +1331,7 @@ void QFileSystemModel::setOptions(Options options) #if QT_CONFIG(filesystemwatcher) Q_D(QFileSystemModel); if (changed.testFlag(DontWatchForChanges)) - d->fileInfoGatherer.setWatching(!options.testFlag(DontWatchForChanges)); + d->fileInfoGatherer->setWatching(!options.testFlag(DontWatchForChanges)); #endif if (changed.testFlag(DontUseCustomDirectoryIcons)) { @@ -1322,7 +1352,7 @@ QFileSystemModel::Options QFileSystemModel::options() const result.setFlag(DontResolveSymlinks, !resolveSymlinks()); #if QT_CONFIG(filesystemwatcher) Q_D(const QFileSystemModel); - result.setFlag(DontWatchForChanges, !d->fileInfoGatherer.isWatching()); + result.setFlag(DontWatchForChanges, !d->fileInfoGatherer->isWatching()); #else result.setFlag(DontWatchForChanges); #endif @@ -1344,7 +1374,7 @@ QString QFileSystemModel::filePath(const QModelIndex &index) const QFileSystemModelPrivate::QFileSystemNode *dirNode = d->node(index); if (dirNode->isSymLink() #if QT_CONFIG(filesystemwatcher) - && d->fileInfoGatherer.resolveSymlinks() + && d->fileInfoGatherer->resolveSymlinks() #endif && d->resolvedSymLinks.contains(fullPath) && dirNode->isDir()) { @@ -1380,7 +1410,7 @@ QString QFileSystemModelPrivate::filePath(const QModelIndex &index) const } QString fullPath = QDir::fromNativeSeparators(path.join(QDir::separator())); #if !defined(Q_OS_WIN) - if ((fullPath.length() > 2) && fullPath[0] == u'/' && fullPath[1] == u'/') + if ((fullPath.size() > 2) && fullPath[0] == u'/' && fullPath[1] == u'/') fullPath = fullPath.mid(1); #else if (fullPath.length() == 2 && fullPath.endsWith(u':')) @@ -1406,7 +1436,7 @@ QModelIndex QFileSystemModel::mkdir(const QModelIndex &parent, const QString &na Q_ASSERT(parentNode->children.contains(name)); QFileSystemModelPrivate::QFileSystemNode *node = parentNode->children[name]; #if QT_CONFIG(filesystemwatcher) - node->populate(d->fileInfoGatherer.getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name))); + node->populate(d->fileInfoGatherer->getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name))); #endif d->addVisibleFiles(parentNode, QStringList(name)); return d->index(node); @@ -1474,7 +1504,7 @@ QModelIndex QFileSystemModel::setRootPath(const QString &newPath) if (!rootPath().isEmpty() && rootPath() != "."_L1) { //This remove the watcher for the old rootPath #if QT_CONFIG(filesystemwatcher) - d->fileInfoGatherer.removePath(rootPath()); + d->fileInfoGatherer->removePath(rootPath()); #endif //This line "marks" the node as dirty, so the next fetchMore //call on the path will ask the gatherer to install a watcher again @@ -1530,7 +1560,7 @@ void QFileSystemModel::setIconProvider(QAbstractFileIconProvider *provider) { Q_D(QFileSystemModel); #if QT_CONFIG(filesystemwatcher) - d->fileInfoGatherer.setIconProvider(provider); + d->fileInfoGatherer->setIconProvider(provider); #endif d->root.updateIcon(provider, QString()); } @@ -1542,9 +1572,9 @@ QAbstractFileIconProvider *QFileSystemModel::iconProvider() const { #if QT_CONFIG(filesystemwatcher) Q_D(const QFileSystemModel); - return d->fileInfoGatherer.iconProvider(); + return d->fileInfoGatherer->iconProvider(); #else - return 0; + return nullptr; #endif } @@ -1598,7 +1628,7 @@ void QFileSystemModel::setResolveSymlinks(bool enable) { #if QT_CONFIG(filesystemwatcher) Q_D(QFileSystemModel); - d->fileInfoGatherer.setResolveSymlinks(enable); + d->fileInfoGatherer->setResolveSymlinks(enable); #else Q_UNUSED(enable); #endif @@ -1608,7 +1638,7 @@ bool QFileSystemModel::resolveSymlinks() const { #if QT_CONFIG(filesystemwatcher) Q_D(const QFileSystemModel); - return d->fileInfoGatherer.resolveSymlinks(); + return d->fileInfoGatherer->resolveSymlinks(); #else return false; #endif @@ -1713,7 +1743,7 @@ bool QFileSystemModel::event(QEvent *event) #if QT_CONFIG(filesystemwatcher) Q_D(QFileSystemModel); if (event->type() == QEvent::LanguageChange) { - d->root.retranslateStrings(d->fileInfoGatherer.iconProvider(), QString()); + d->root.retranslateStrings(d->fileInfoGatherer->iconProvider(), QString()); return true; } #endif @@ -1727,7 +1757,7 @@ bool QFileSystemModel::rmdir(const QModelIndex &aindex) #if QT_CONFIG(filesystemwatcher) if (success) { QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func()); - d->fileInfoGatherer.removePath(path); + d->fileInfoGatherer->removePath(path); } #endif return success; @@ -1739,10 +1769,10 @@ bool QFileSystemModel::rmdir(const QModelIndex &aindex) Performed quick listing and see if any files have been added or removed, then fetch more information on visible files. */ -void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, const QStringList &files) +void QFileSystemModelPrivate::directoryChanged(const QString &directory, const QStringList &files) { QFileSystemModelPrivate::QFileSystemNode *parentNode = node(directory, false); - if (parentNode->children.count() == 0) + if (parentNode->children.size() == 0) return; QStringList toRemove; QStringList newFiles = files; @@ -1752,7 +1782,7 @@ void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, cons if ((iterator == newFiles.end()) || (i.value()->fileName < *iterator)) toRemove.append(i.value()->fileName); } - for (int i = 0 ; i < toRemove.count() ; ++i ) + for (int i = 0 ; i < toRemove.size() ; ++i ) removeNode(parentNode, toRemove[i]); } @@ -1844,11 +1874,11 @@ void QFileSystemModelPrivate::addVisibleFiles(QFileSystemNode *parentNode, const QModelIndex parent = index(parentNode); bool indexHidden = isHiddenByFilter(parentNode, parent); if (!indexHidden) { - q->beginInsertRows(parent, parentNode->visibleChildren.count() , parentNode->visibleChildren.count() + newFiles.count() - 1); + q->beginInsertRows(parent, parentNode->visibleChildren.size() , parentNode->visibleChildren.size() + newFiles.size() - 1); } if (parentNode->dirtyChildrenIndex == -1) - parentNode->dirtyChildrenIndex = parentNode->visibleChildren.count(); + parentNode->dirtyChildrenIndex = parentNode->visibleChildren.size(); for (const auto &newFile : newFiles) { parentNode->visibleChildren.append(newFile); @@ -1887,8 +1917,8 @@ void QFileSystemModelPrivate::removeVisibleFile(QFileSystemNode *parentNode, int The thread has received new information about files, update and emit dataChanged if it has actually changed. */ -void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, - const QList<QPair<QString, QFileInfo>> &updates) +void QFileSystemModelPrivate::fileSystemChanged(const QString &path, + const QList<std::pair<QString, QFileInfo>> &updates) { #if QT_CONFIG(filesystemwatcher) Q_Q(QFileSystemModel); @@ -1899,7 +1929,7 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, for (const auto &update : updates) { QString fileName = update.first; Q_ASSERT(!fileName.isEmpty()); - QExtendedInformation info = fileInfoGatherer.getInfo(update.second); + QExtendedInformation info = fileInfoGatherer->getInfo(update.second); bool previouslyHere = parentNode->children.contains(fileName); if (!previouslyHere) { addNode(parentNode, fileName, info.fileInfo()); @@ -1944,7 +1974,7 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, std::sort(rowsToUpdate.begin(), rowsToUpdate.end()); QString min; QString max; - for (const QString &value : qAsConst(rowsToUpdate)) { + for (const QString &value : std::as_const(rowsToUpdate)) { //##TODO is there a way to bundle signals with QString as the content of the list? /*if (min.isEmpty()) { min = value; @@ -1962,23 +1992,30 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, int visibleMin = parentNode->visibleLocation(min); int visibleMax = parentNode->visibleLocation(max); if (visibleMin >= 0 - && visibleMin < parentNode->visibleChildren.count() + && visibleMin < parentNode->visibleChildren.size() && parentNode->visibleChildren.at(visibleMin) == min && visibleMax >= 0) { - QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMin), 0, parentIndex); - QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMax), 3, parentIndex); - emit q->dataChanged(bottom, top); + // don't use NumColumns here, a subclass might override columnCount + const int lastColumn = q->columnCount(parentIndex) - 1; + const QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMin), + QFileSystemModelPrivate::NameColumn, parentIndex); + const QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMax), + lastColumn, parentIndex); + // We document that emitting dataChanged with indexes that don't have the + // same parent is undefined behavior. + Q_ASSERT(bottom.parent() == top.parent()); + emit q->dataChanged(top, bottom); } /*min = QString(); max = QString();*/ } - if (newFiles.count() > 0) { + if (newFiles.size() > 0) { addVisibleFiles(parentNode, newFiles); } - if (newFiles.count() > 0 || (sortColumn != 0 && rowsToUpdate.count() > 0)) { + if (newFiles.size() > 0 || (sortColumn != 0 && rowsToUpdate.size() > 0)) { forceSort = true; delayedSort(); } @@ -1991,7 +2028,7 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, /*! \internal */ -void QFileSystemModelPrivate::_q_resolvedName(const QString &fileName, const QString &resolvedName) +void QFileSystemModelPrivate::resolvedName(const QString &fileName, const QString &resolvedName) { resolvedSymLinks[fileName] = resolvedName; } @@ -2023,22 +2060,41 @@ QStringList QFileSystemModelPrivate::unwatchPathsAt(const QModelIndex &index) return false; }; - const QStringList &watchedFiles = fileInfoGatherer.watchedFiles(); + const QStringList &watchedFiles = fileInfoGatherer->watchedFiles(); std::copy_if(watchedFiles.cbegin(), watchedFiles.cend(), std::back_inserter(result), filter); - const QStringList &watchedDirectories = fileInfoGatherer.watchedDirectories(); + const QStringList &watchedDirectories = fileInfoGatherer->watchedDirectories(); std::copy_if(watchedDirectories.cbegin(), watchedDirectories.cend(), std::back_inserter(result), filter); - fileInfoGatherer.unwatchPaths(result); + fileInfoGatherer->unwatchPaths(result); return result; } #endif // filesystemwatcher && Q_OS_WIN -QFileSystemModelPrivate::QFileSystemModelPrivate() = default; +QFileSystemModelPrivate::QFileSystemModelPrivate() +#if QT_CONFIG(filesystemwatcher) + : fileInfoGatherer(new QFileInfoGatherer) +#endif // filesystemwatcher +{ +} -QFileSystemModelPrivate::~QFileSystemModelPrivate() = default; +QFileSystemModelPrivate::~QFileSystemModelPrivate() +{ +#if QT_CONFIG(filesystemwatcher) + fileInfoGatherer->requestAbort(); + if (!fileInfoGatherer->wait(1000)) { + // If the thread hangs, perhaps because the network was disconnected + // while the gatherer was stat'ing a remote file, then don't block + // shutting down the model (which might block a file dialog and the + // main thread). Schedule the gatherer for later deletion; it's + // destructor will wait for the thread to finish. + auto *rawGatherer = fileInfoGatherer.release(); + rawGatherer->deleteLater(); + } +#endif // filesystemwatcher +} /*! \internal @@ -2049,18 +2105,20 @@ void QFileSystemModelPrivate::init() delayedSortTimer.setSingleShot(true); - qRegisterMetaType<QList<QPair<QString, QFileInfo>>>(); + qRegisterMetaType<QList<std::pair<QString, QFileInfo>>>(); #if QT_CONFIG(filesystemwatcher) - q->connect(&fileInfoGatherer, SIGNAL(newListOfFiles(QString,QStringList)), - q, SLOT(_q_directoryChanged(QString,QStringList))); - q->connect(&fileInfoGatherer, SIGNAL(updates(QString, QList<QPair<QString, QFileInfo>>)), q, - SLOT(_q_fileSystemChanged(QString, QList<QPair<QString, QFileInfo>>))); - q->connect(&fileInfoGatherer, SIGNAL(nameResolved(QString,QString)), - q, SLOT(_q_resolvedName(QString,QString))); - q->connect(&fileInfoGatherer, SIGNAL(directoryLoaded(QString)), - q, SIGNAL(directoryLoaded(QString))); + QObjectPrivate::connect(fileInfoGatherer.get(), &QFileInfoGatherer::newListOfFiles, + this, &QFileSystemModelPrivate::directoryChanged); + QObjectPrivate::connect(fileInfoGatherer.get(), &QFileInfoGatherer::updates, + this, &QFileSystemModelPrivate::fileSystemChanged); + QObjectPrivate::connect(fileInfoGatherer.get(), &QFileInfoGatherer::nameResolved, + this, &QFileSystemModelPrivate::resolvedName); + q->connect(fileInfoGatherer.get(), &QFileInfoGatherer::directoryLoaded, + q, &QFileSystemModel::directoryLoaded); #endif // filesystemwatcher - q->connect(&delayedSortTimer, SIGNAL(timeout()), q, SLOT(_q_performDelayedSort()), Qt::QueuedConnection); + QObjectPrivate::connect(&delayedSortTimer, &QTimer::timeout, + this, &QFileSystemModelPrivate::performDelayedSort, + Qt::QueuedConnection); } /*! @@ -2073,8 +2131,14 @@ void QFileSystemModelPrivate::init() */ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) const { + // When the model is set to only show files, then a node representing a dir + // should be hidden regardless of bypassFilters. + // QTBUG-74471 + const bool hideDirs = (filters & (QDir::Dirs | QDir::AllDirs)) == 0; + const bool shouldHideDirNode = hideDirs && node->isDir(); + // always accept drives - if (node->parent == &root || bypassFilters.contains(node)) + if (node->parent == &root || (!shouldHideDirNode && bypassFilters.contains(node))) return true; // If we don't know anything yet don't accept it @@ -2083,7 +2147,6 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co const bool filterPermissions = ((filters & QDir::PermissionMask) && (filters & QDir::PermissionMask) != QDir::PermissionMask); - const bool hideDirs = !(filters & (QDir::Dirs | QDir::AllDirs)); const bool hideFiles = !(filters & QDir::Files); const bool hideReadable = !(!filterPermissions || (filters & QDir::Readable)); const bool hideWritable = !(!filterPermissions || (filters & QDir::Writable)); |