diff options
| -rw-r--r-- | plugin/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | plugin/src/Caelestia/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | plugin/src/Caelestia/filesystemmodel.cpp | 147 | ||||
| -rw-r--r-- | plugin/src/Caelestia/filesystemmodel.hpp | 2 |
4 files changed, 100 insertions, 53 deletions
diff --git a/plugin/CMakeLists.txt b/plugin/CMakeLists.txt index a38d3c4..9d5f128 100644 --- a/plugin/CMakeLists.txt +++ b/plugin/CMakeLists.txt @@ -1,4 +1,4 @@ -find_package(Qt6 REQUIRED COMPONENTS Core Qml Gui) +find_package(Qt6 REQUIRED COMPONENTS Core Qml Gui Concurrent) if(QT_KNOWN_POLICY_QTP0001) qt_policy(SET QTP0001 NEW) 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 <QDir> #include <QDirIterator> #include <QFileInfo> +#include <QFutureWatcher> #include <QImageReader> #include <QObject> +#include <QtConcurrent> #include <qqmlintegration.h> 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; - std::optional<QDirIterator> iter; + const auto future = QtConcurrent::run( + [dir, recursive, filter, oldEntries, baseDir](QPromise<QPair<QSet<QString>, QSet<QString>>>& promise) { + const auto flags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags; - if (m_filter == Images) { - QStringList filters; - for (const auto& format : QImageReader::supportedImageFormats()) { - filters << "*." + format; - } + std::optional<QDirIterator> iter; - 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) { + 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); + } + + QSet<QString> newPaths; + while (iter->hasNext()) { + if (promise.isCanceled()) { + return; + } + + QString path = iter->next(); - QSet<QString> newPaths; - while (iter->hasNext()) { - QString path = iter->next(); + if (filter == Images) { + QImageReader reader(path); + if (!reader.canRead()) { + continue; + } + } - if (m_filter == Images) { - QImageReader reader(path); - if (!reader.canRead()) { - continue; + newPaths.insert(path); } - } - newPaths.insert(path); - } + QSet<QString> oldPaths; + for (const auto& entry : oldEntries) { + oldPaths.insert(entry->path()); + } - QSet<QString> oldPaths; - for (const auto& entry : m_entries) { - oldPaths.insert(entry->path()); - } + if (promise.isCanceled() || newPaths == oldPaths) { + return; + } - if (newPaths == oldPaths) { - return; - } + promise.addResult(qMakePair(oldPaths - newPaths, newPaths - oldPaths)); + }); - const QSet<QString> removedPaths = oldPaths - newPaths; - const QSet<QString> addedPaths = newPaths - oldPaths; + if (m_futures.contains(dir)) { + m_futures[dir].cancel(); + } + m_futures.insert(dir, future); - beginResetModel(); + const auto watcher = new QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>(this); - const int numEntries = static_cast<int>(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<QPair<QSet<QString>, QSet<QString>>>::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<int>(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); + } } - return a->relativePath().localeAwareCompare(b->relativePath()) < 0; - }); - emit entriesChanged(); + for (const auto& path : addedPaths) { + const auto entry = new FileSystemEntry(path, m_dir.relativeFilePath(path), this); + emit added(entry); + m_entries << entry; + } + + 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 <QDir> #include <QFileInfo> #include <QFileSystemWatcher> +#include <QFuture> #include <QImageReader> #include <QObject> #include <qqmlintegration.h> @@ -109,6 +110,7 @@ private: QDir m_dir; QFileSystemWatcher m_watcher; QList<FileSystemEntry*> m_entries; + QHash<QString, QFuture<QPair<QSet<QString>, QSet<QString>>>> m_futures; QString m_path; bool m_recursive; |