From 7b35c23bd0d2e4ce1e3a30a8953669762e409972 Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Wed, 3 Sep 2025 00:21:36 +1000 Subject: plugin/fsm: incremental updates --- plugin/src/Caelestia/filesystemmodel.cpp | 109 ++++++++++++++++++++++++------- plugin/src/Caelestia/filesystemmodel.hpp | 2 + 2 files changed, 88 insertions(+), 23 deletions(-) (limited to 'plugin/src/Caelestia') diff --git a/plugin/src/Caelestia/filesystemmodel.cpp b/plugin/src/Caelestia/filesystemmodel.cpp index 3f75303..7f973a0 100644 --- a/plugin/src/Caelestia/filesystemmodel.cpp +++ b/plugin/src/Caelestia/filesystemmodel.cpp @@ -266,38 +266,101 @@ void FileSystemModel::updateEntriesForDir(const QString& dir) { } const auto result = watcher->result(); - const auto removedPaths = result.first; - const auto addedPaths = result.second; + applyChanges(result.first, result.second); - beginResetModel(); + watcher->deleteLater(); + }); - const int numEntries = static_cast(m_entries.size()); - for (int i = numEntries - 1; i >= 0; --i) { - if (removedPaths.contains(m_entries[i]->path())) { + watcher->setFuture(future); +} + +void FileSystemModel::applyChanges(const QSet& removedPaths, const QSet& addedPaths) { + QList removedIndices; + for (int i = 0; i < m_entries.size(); ++i) { + if (removedPaths.contains(m_entries[i]->path())) { + removedIndices << i; + } + } + std::sort(removedIndices.begin(), removedIndices.end(), std::greater()); + + int start = -1; + int end = -1; + for (int idx : removedIndices) { + if (start == -1) { + start = idx; + end = idx; + } else if (idx == end - 1) { + end = idx; + } else { + beginRemoveRows(QModelIndex(), end, start); + for (int i = start; i >= end; --i) { emit removed(m_entries[i]->path()); delete m_entries.takeAt(i); } - } + endRemoveRows(); - for (const auto& path : addedPaths) { - const auto entry = new FileSystemEntry(path, m_dir.relativeFilePath(path), this); - emit added(entry); - m_entries << entry; + start = idx; + end = idx; + } + } + if (start != -1) { + beginRemoveRows(QModelIndex(), end, start); + for (int i = start; i >= end; --i) { + emit removed(m_entries[i]->path()); + delete m_entries.takeAt(i); } + endRemoveRows(); + } - std::sort(m_entries.begin(), m_entries.end(), [](const FileSystemEntry* a, const FileSystemEntry* b) { - if (a->isDir() != b->isDir()) { - return a->isDir(); + QList newEntries; + for (const auto& path : addedPaths) { + newEntries << new FileSystemEntry(path, m_dir.relativeFilePath(path), this); + } + std::sort(newEntries.begin(), newEntries.end(), &FileSystemModel::compareEntries); + + int insertStart = -1; + int prevRow = -1; + QList batchItems; + for (const auto& entry : newEntries) { + const auto it = std::lower_bound(m_entries.begin(), m_entries.end(), entry, &FileSystemModel::compareEntries); + int row = static_cast(it - m_entries.begin()); + + if (insertStart == -1) { + insertStart = row; + prevRow = row; + batchItems.clear(); + batchItems << entry; + } else if (row == prevRow + 1) { + prevRow = row; + batchItems << entry; + } else { + beginInsertRows(QModelIndex(), insertStart, static_cast(insertStart + batchItems.size() - 1)); + for (int i = 0; i < batchItems.size(); ++i) { + m_entries.insert(insertStart + i, batchItems[i]); + emit added(batchItems[i]); } - return a->relativePath().localeAwareCompare(b->relativePath()) < 0; - }); - - emit entriesChanged(); - - endResetModel(); + endInsertRows(); - watcher->deleteLater(); - }); + insertStart = row; + prevRow = row; + batchItems.clear(); + batchItems << entry; + } + prevRow = static_cast(m_entries.indexOf(entry)); + } + if (!batchItems.isEmpty()) { + beginInsertRows(QModelIndex(), insertStart, static_cast(insertStart + batchItems.size() - 1)); + for (int i = 0; i < batchItems.size(); ++i) { + m_entries.insert(insertStart + i, batchItems[i]); + emit added(batchItems[i]); + } + endInsertRows(); + } +} - watcher->setFuture(future); +bool FileSystemModel::compareEntries(const FileSystemEntry* a, const FileSystemEntry* b) { + if (a->isDir() != b->isDir()) { + return a->isDir(); + } + return a->relativePath().localeAwareCompare(b->relativePath()) < 0; } diff --git a/plugin/src/Caelestia/filesystemmodel.hpp b/plugin/src/Caelestia/filesystemmodel.hpp index fdcd6c1..2e3bf93 100644 --- a/plugin/src/Caelestia/filesystemmodel.hpp +++ b/plugin/src/Caelestia/filesystemmodel.hpp @@ -154,4 +154,6 @@ private: void updateWatcher(); void updateEntries(); void updateEntriesForDir(const QString& dir); + void applyChanges(const QSet& removedPaths, const QSet& addedPaths); + static bool compareEntries(const FileSystemEntry* a, const FileSystemEntry* b); }; -- cgit v1.2.3-freya