From c0c4e14e5859546d9308e0107d9f9b12249d5896 Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:59:24 +1000 Subject: plugin/fsm: async update --- plugin/src/Caelestia/CMakeLists.txt | 2 +- plugin/src/Caelestia/filesystemmodel.cpp | 147 ++++++++++++++++++++----------- plugin/src/Caelestia/filesystemmodel.hpp | 2 + 3 files changed, 99 insertions(+), 52 deletions(-) (limited to 'plugin/src') diff --git a/plugin/src/Caelestia/CMakeLists.txt b/plugin/src/Caelestia/CMakeLists.txt index a56074e..d00247e 100644 --- a/plugin/src/Caelestia/CMakeLists.txt +++ b/plugin/src/Caelestia/CMakeLists.txt @@ -24,4 +24,4 @@ install(TARGETS "${module_plugin_target}" LIBRARY DESTINATION "${module_dir}" RU install(FILES "${module_qmldir}" DESTINATION "${module_dir}") install(FILES "${module_typeinfo}" DESTINATION "${module_dir}") -target_link_libraries(caelestia PRIVATE Qt::Core Qt::Qml Qt::Gui) +target_link_libraries(caelestia PRIVATE Qt::Core Qt::Qml Qt::Gui Qt::Concurrent) diff --git a/plugin/src/Caelestia/filesystemmodel.cpp b/plugin/src/Caelestia/filesystemmodel.cpp index 8e2efae..ee2f524 100644 --- a/plugin/src/Caelestia/filesystemmodel.cpp +++ b/plugin/src/Caelestia/filesystemmodel.cpp @@ -4,8 +4,10 @@ #include #include #include +#include #include #include +#include #include int FileSystemModel::rowCount(const QModelIndex& parent) const { @@ -116,77 +118,120 @@ void FileSystemModel::updateEntries() { return; } + for (auto& future : m_futures) { + future.cancel(); + } + m_futures.clear(); + updateEntriesForDir(m_path); } void FileSystemModel::updateEntriesForDir(const QString& dir) { - const auto flags = m_recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags; + const bool recursive = m_recursive; + const auto filter = m_filter; + const auto oldEntries = m_entries; + const auto baseDir = m_dir; + + const auto future = QtConcurrent::run( + [dir, recursive, filter, oldEntries, baseDir](QPromise, QSet>>& promise) { + const auto flags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags; + + std::optional iter; + + if (filter == Images) { + QStringList filters; + for (const auto& format : QImageReader::supportedImageFormats()) { + filters << "*." + format; + } + + iter.emplace(dir, filters, QDir::Files, flags); + } else if (filter == Files) { + iter.emplace(dir, QDir::Files, flags); + } else { + iter.emplace(dir, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, flags); + } - std::optional iter; + QSet newPaths; + while (iter->hasNext()) { + if (promise.isCanceled()) { + return; + } - if (m_filter == Images) { - QStringList filters; - for (const auto& format : QImageReader::supportedImageFormats()) { - filters << "*." + format; - } + QString path = iter->next(); - iter.emplace(dir, filters, QDir::Files, flags); - } else if (m_filter == Files) { - iter.emplace(dir, QDir::Files, flags); - } else { - iter.emplace(dir, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, flags); - } + if (filter == Images) { + QImageReader reader(path); + if (!reader.canRead()) { + continue; + } + } - QSet newPaths; - while (iter->hasNext()) { - QString path = iter->next(); + newPaths.insert(path); + } - if (m_filter == Images) { - QImageReader reader(path); - if (!reader.canRead()) { - continue; + QSet oldPaths; + for (const auto& entry : oldEntries) { + oldPaths.insert(entry->path()); } - } - newPaths.insert(path); - } + if (promise.isCanceled() || newPaths == oldPaths) { + return; + } - QSet oldPaths; - for (const auto& entry : m_entries) { - oldPaths.insert(entry->path()); - } + promise.addResult(qMakePair(oldPaths - newPaths, newPaths - oldPaths)); + }); - if (newPaths == oldPaths) { - return; + if (m_futures.contains(dir)) { + m_futures[dir].cancel(); } + m_futures.insert(dir, future); - const QSet removedPaths = oldPaths - newPaths; - const QSet addedPaths = newPaths - oldPaths; - - beginResetModel(); + const auto watcher = new QFutureWatcher, QSet>>(this); - const int numEntries = static_cast(m_entries.size()); - for (int i = numEntries - 1; i >= 0; --i) { - if (removedPaths.contains(m_entries[i]->path())) { - emit removed(m_entries[i]->path()); - delete m_entries.takeAt(i); + connect(watcher, &QFutureWatcher, QSet>>::finished, this, [watcher, this]() { + if (!watcher->future().isResultReadyAt(0)) { + watcher->deleteLater(); + return; } - } - for (const auto& path : addedPaths) { - const auto entry = new FileSystemEntry(path, m_dir.relativeFilePath(path), this); - emit added(entry); - m_entries << entry; - } + QElapsedTimer timer; + timer.start(); + + const auto result = watcher->result(); + const auto removedPaths = result.first; + const auto addedPaths = result.second; - std::sort(m_entries.begin(), m_entries.end(), [](const FileSystemEntry* a, const FileSystemEntry* b) { - if (a->isDir() != b->isDir()) { - return a->isDir(); + beginResetModel(); + + const int numEntries = static_cast(m_entries.size()); + for (int i = numEntries - 1; i >= 0; --i) { + if (removedPaths.contains(m_entries[i]->path())) { + emit removed(m_entries[i]->path()); + delete m_entries.takeAt(i); + } + } + + for (const auto& path : addedPaths) { + const auto entry = new FileSystemEntry(path, m_dir.relativeFilePath(path), this); + emit added(entry); + m_entries << entry; } - return a->relativePath().localeAwareCompare(b->relativePath()) < 0; - }); - emit entriesChanged(); + std::sort(m_entries.begin(), m_entries.end(), [](const FileSystemEntry* a, const FileSystemEntry* b) { + if (a->isDir() != b->isDir()) { + return a->isDir(); + } + return a->relativePath().localeAwareCompare(b->relativePath()) < 0; + }); + + emit entriesChanged(); + + endResetModel(); + + watcher->deleteLater(); + + qDebug() << "Update took" << timer.elapsed() << "ms"; + }); - endResetModel(); + watcher->setFuture(future); } diff --git a/plugin/src/Caelestia/filesystemmodel.hpp b/plugin/src/Caelestia/filesystemmodel.hpp index e7e1cf2..978497e 100644 --- a/plugin/src/Caelestia/filesystemmodel.hpp +++ b/plugin/src/Caelestia/filesystemmodel.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -109,6 +110,7 @@ private: QDir m_dir; QFileSystemWatcher m_watcher; QList m_entries; + QHash, QSet>>> m_futures; QString m_path; bool m_recursive; -- cgit v1.2.3-freya