summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugin/CMakeLists.txt2
-rw-r--r--plugin/src/Caelestia/CMakeLists.txt2
-rw-r--r--plugin/src/Caelestia/filesystemmodel.cpp147
-rw-r--r--plugin/src/Caelestia/filesystemmodel.hpp2
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;