plugin/fsm: async update
This commit is contained in:
parent
2601955dfd
commit
c0c4e14e58
4 changed files with 104 additions and 57 deletions
|
|
@ -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)
|
if(QT_KNOWN_POLICY_QTP0001)
|
||||||
qt_policy(SET QTP0001 NEW)
|
qt_policy(SET QTP0001 NEW)
|
||||||
|
|
|
||||||
|
|
@ -24,4 +24,4 @@ install(TARGETS "${module_plugin_target}" LIBRARY DESTINATION "${module_dir}" RU
|
||||||
install(FILES "${module_qmldir}" DESTINATION "${module_dir}")
|
install(FILES "${module_qmldir}" DESTINATION "${module_dir}")
|
||||||
install(FILES "${module_typeinfo}" 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)
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QFutureWatcher>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QtConcurrent>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
|
|
||||||
int FileSystemModel::rowCount(const QModelIndex& parent) const {
|
int FileSystemModel::rowCount(const QModelIndex& parent) const {
|
||||||
|
|
@ -116,77 +118,120 @@ void FileSystemModel::updateEntries() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& future : m_futures) {
|
||||||
|
future.cancel();
|
||||||
|
}
|
||||||
|
m_futures.clear();
|
||||||
|
|
||||||
updateEntriesForDir(m_path);
|
updateEntriesForDir(m_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystemModel::updateEntriesForDir(const QString& dir) {
|
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) {
|
std::optional<QDirIterator> iter;
|
||||||
QStringList filters;
|
|
||||||
for (const auto& format : QImageReader::supportedImageFormats()) {
|
if (filter == Images) {
|
||||||
filters << "*." + format;
|
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();
|
||||||
|
|
||||||
|
if (filter == Images) {
|
||||||
|
QImageReader reader(path);
|
||||||
|
if (!reader.canRead()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newPaths.insert(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<QString> oldPaths;
|
||||||
|
for (const auto& entry : oldEntries) {
|
||||||
|
oldPaths.insert(entry->path());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (promise.isCanceled() || newPaths == oldPaths) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
promise.addResult(qMakePair(oldPaths - newPaths, newPaths - oldPaths));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (m_futures.contains(dir)) {
|
||||||
|
m_futures[dir].cancel();
|
||||||
|
}
|
||||||
|
m_futures.insert(dir, future);
|
||||||
|
|
||||||
|
const auto watcher = new QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>(this);
|
||||||
|
|
||||||
|
connect(watcher, &QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>::finished, this, [watcher, this]() {
|
||||||
|
if (!watcher->future().isResultReadyAt(0)) {
|
||||||
|
watcher->deleteLater();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter.emplace(dir, filters, QDir::Files, flags);
|
QElapsedTimer timer;
|
||||||
} else if (m_filter == Files) {
|
timer.start();
|
||||||
iter.emplace(dir, QDir::Files, flags);
|
|
||||||
} else {
|
|
||||||
iter.emplace(dir, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSet<QString> newPaths;
|
const auto result = watcher->result();
|
||||||
while (iter->hasNext()) {
|
const auto removedPaths = result.first;
|
||||||
QString path = iter->next();
|
const auto addedPaths = result.second;
|
||||||
|
|
||||||
if (m_filter == Images) {
|
beginResetModel();
|
||||||
QImageReader reader(path);
|
|
||||||
if (!reader.canRead()) {
|
const int numEntries = static_cast<int>(m_entries.size());
|
||||||
continue;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newPaths.insert(path);
|
for (const auto& path : addedPaths) {
|
||||||
}
|
const auto entry = new FileSystemEntry(path, m_dir.relativeFilePath(path), this);
|
||||||
|
emit added(entry);
|
||||||
QSet<QString> oldPaths;
|
m_entries << entry;
|
||||||
for (const auto& entry : m_entries) {
|
|
||||||
oldPaths.insert(entry->path());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newPaths == oldPaths) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QSet<QString> removedPaths = oldPaths - newPaths;
|
|
||||||
const QSet<QString> addedPaths = newPaths - oldPaths;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& path : addedPaths) {
|
std::sort(m_entries.begin(), m_entries.end(), [](const FileSystemEntry* a, const FileSystemEntry* b) {
|
||||||
const auto entry = new FileSystemEntry(path, m_dir.relativeFilePath(path), this);
|
if (a->isDir() != b->isDir()) {
|
||||||
emit added(entry);
|
return a->isDir();
|
||||||
m_entries << entry;
|
}
|
||||||
}
|
return a->relativePath().localeAwareCompare(b->relativePath()) < 0;
|
||||||
|
});
|
||||||
|
|
||||||
std::sort(m_entries.begin(), m_entries.end(), [](const FileSystemEntry* a, const FileSystemEntry* b) {
|
emit entriesChanged();
|
||||||
if (a->isDir() != b->isDir()) {
|
|
||||||
return a->isDir();
|
endResetModel();
|
||||||
}
|
|
||||||
return a->relativePath().localeAwareCompare(b->relativePath()) < 0;
|
watcher->deleteLater();
|
||||||
|
|
||||||
|
qDebug() << "Update took" << timer.elapsed() << "ms";
|
||||||
});
|
});
|
||||||
|
|
||||||
emit entriesChanged();
|
watcher->setFuture(future);
|
||||||
|
|
||||||
endResetModel();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
|
#include <QFuture>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
|
|
@ -109,6 +110,7 @@ private:
|
||||||
QDir m_dir;
|
QDir m_dir;
|
||||||
QFileSystemWatcher m_watcher;
|
QFileSystemWatcher m_watcher;
|
||||||
QList<FileSystemEntry*> m_entries;
|
QList<FileSystemEntry*> m_entries;
|
||||||
|
QHash<QString, QFuture<QPair<QSet<QString>, QSet<QString>>>> m_futures;
|
||||||
|
|
||||||
QString m_path;
|
QString m_path;
|
||||||
bool m_recursive;
|
bool m_recursive;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue