From a42b4d364f31c405aed253b2ddffeb7d61f4f20e Mon Sep 17 00:00:00 2001 From: Martchus Date: Fri, 12 Apr 2024 18:06:36 +0200 Subject: [PATCH] WIP --- syncthingconnector/syncthingconnection.h | 5 +- .../syncthingconnection_requests.cpp | 12 +- syncthingmodel/syncthingfilemodel.cpp | 113 ++++++++++++------ 3 files changed, 85 insertions(+), 45 deletions(-) diff --git a/syncthingconnector/syncthingconnection.h b/syncthingconnector/syncthingconnection.h index 9e99fdc..ec6dfbc 100644 --- a/syncthingconnector/syncthingconnection.h +++ b/syncthingconnector/syncthingconnection.h @@ -253,7 +253,8 @@ public Q_SLOTS: public: // methods to GET or POST information from/to Syncthing (non-slots) - QMetaObject::Connection browse(const QString &dirId, const QString &prefix, int level, std::function > &&, QString &&)> &&callback); + QMetaObject::Connection browse(const QString &dirId, const QString &prefix, int level, + std::function> &&, QString &&)> &&callback); Q_SIGNALS: void newConfig(const QJsonObject &rawConfig); @@ -368,7 +369,7 @@ private Q_SLOTS: private: // handler to evaluate results from request...() methods - void readBrowse(const QString &dirId, int levels, std::function > &&, QString &&)> &&callback); + void readBrowse(const QString &dirId, int levels, std::function> &&, QString &&)> &&callback); // internal helper methods struct Reply { diff --git a/syncthingconnector/syncthingconnection_requests.cpp b/syncthingconnector/syncthingconnection_requests.cpp index d49b32f..b3015e4 100644 --- a/syncthingconnector/syncthingconnection_requests.cpp +++ b/syncthingconnector/syncthingconnection_requests.cpp @@ -1590,7 +1590,8 @@ void SyncthingConnection::readRevert() * consume results of a specific request. Errors are still reported via the error() signal so there's no extra error handling * required. Note that \a callback is *not* invoked in the error case. */ -QMetaObject::Connection SyncthingConnection::browse(const QString &dirId, const QString &prefix, int levels, std::function> &&, QString &&)> &&callback) +QMetaObject::Connection SyncthingConnection::browse(const QString &dirId, const QString &prefix, int levels, + std::function> &&, QString &&)> &&callback) { auto query = QUrlQuery(); query.addQueryItem(QStringLiteral("folder"), formatQueryItem(dirId)); @@ -1621,11 +1622,11 @@ static void readSyncthingItems(const QJsonArray &array, std::vectorname = jsonItemObj.value(QLatin1String("name")).toString(); item->modificationTime = CppUtilities::DateTime::fromIsoStringGmt(jsonItemObj.value(QLatin1String("modTime")).toString().toUtf8().data()); item->size = static_cast(jsonItemObj - .value(QLatin1String("size")) + .value(QLatin1String("size")) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - .toInteger() + .toInteger() #else - .toDouble() + .toDouble() #endif ); item->index = index; @@ -1645,7 +1646,8 @@ static void readSyncthingItems(const QJsonArray &array, std::vector> &&, QString &&)> &&callback) +void SyncthingConnection::readBrowse( + const QString &dirId, int levels, std::function> &&, QString &&)> &&callback) { auto const [reply, response] = prepareReply(); if (!reply) { diff --git a/syncthingmodel/syncthingfilemodel.cpp b/syncthingmodel/syncthingfilemodel.cpp index d2971c3..1dd3008 100644 --- a/syncthingmodel/syncthingfilemodel.cpp +++ b/syncthingmodel/syncthingfilemodel.cpp @@ -27,6 +27,9 @@ SyncthingFileModel::SyncthingFileModel(SyncthingConnection &connection, const Sy m_root->type = SyncthingItemType::Directory; m_connection.browse(m_dirId, QString(), 1, [this](std::vector> &&items, QString &&errorMessage) { Q_UNUSED(errorMessage) + if (items.empty()) { + return; + } const auto last = items.size() - 1; beginInsertRows(index(0, 0), 0, last < std::numeric_limits::max() ? static_cast(last) : std::numeric_limits::max()); m_root->children = std::move(items); @@ -55,7 +58,7 @@ QHash SyncthingFileModel::roleNames() const QModelIndex SyncthingFileModel::index(int row, int column, const QModelIndex &parent) const { - if (row < 0 || column < 0 || column > 2) { + if (row < 0 || column < 0 || column > 2 || parent.column() > 0) { return QModelIndex(); } if (!parent.isValid()) { @@ -77,19 +80,21 @@ QModelIndex SyncthingFileModel::index(int row, int column, const QModelIndex &pa QModelIndex SyncthingFileModel::index(const QString &path) const { auto parts = path.split(QChar('/'), Qt::SkipEmptyParts); - auto res = index(0, 0); auto *parent = m_root.get(); + auto res = createIndex(0, 0, parent); for (const auto &part : parts) { - auto foundPart = false; + auto index = 0; for (const auto &child : parent->children) { if (child->name == part) { + child->parent = parent; parent = child.get(); - res = index(static_cast(child->index), 0, res); - foundPart = true; + res = createIndex(index, 0, parent); + index = -1; break; } + ++index; } - if (!foundPart) { + if (index >= 0) { res = QModelIndex(); return res; } @@ -258,6 +263,14 @@ static void addLevel(std::vector> &items, int lev addLevel(item->children, level); } } + +static void considerFetched(std::vector> &items) +{ + for (auto &item : items) { + item->childrenPopulated = true; + considerFetched(item->children); + } +} /// \endcond void SyncthingFileModel::fetchMore(const QModelIndex &parent) @@ -297,41 +310,65 @@ void SyncthingFileModel::processFetchQueue() return; } const auto &path = m_fetchQueue.front(); - m_pendingRequest = m_connection.browse(m_dirId, path, 1, [this, p = path](std::vector> &&items, QString &&errorMessage) { - Q_UNUSED(errorMessage) - m_fetchQueue.removeAll(p); + m_pendingRequest = m_connection.browse( + m_dirId, path, 1, [this, p = path](std::vector> &&items, QString &&errorMessage) mutable { + Q_UNUSED(errorMessage) - const auto refreshedIndex = index(p); - if (!refreshedIndex.isValid()) { - return; - } - auto *const refreshedItem = reinterpret_cast(refreshedIndex.internalPointer()); - if (!refreshedItem->children.empty()) { - if (refreshedItem == m_root.get()) { - beginResetModel(); - } else { - beginRemoveRows(refreshedIndex, 0, static_cast(refreshedItem->children.size() - 1)); + { + const auto refreshedIndex = index(p); + if (!refreshedIndex.isValid()) { + m_fetchQueue.removeAll(p); + processFetchQueue(); + return; + } + auto *const refreshedItem = reinterpret_cast(refreshedIndex.internalPointer()); + if (!refreshedItem->children.empty()) { + if (false && refreshedItem == m_root.get()) { + beginResetModel(); + } else { + considerFetched(refreshedItem->children); + std::cout << "begin remove rows at: " << this->path(refreshedIndex).toStdString() << std::endl; + std::cout << " - from 0 to " << static_cast(refreshedItem->children.size() - 1) << std::endl; + for (int row = 0; row < static_cast(refreshedItem->children.size()); ++row) { + std::cout << " - " << row << " - " << index(row, 0, refreshedIndex).data().toString().toStdString() << std::endl; + } + beginRemoveRows(refreshedIndex, 0, static_cast(refreshedItem->children.size() - 1)); + } + std::cout << "old row count: " << rowCount(refreshedIndex) << std::endl; + refreshedItem->children.clear(); + if (false && refreshedItem == m_root.get()) { + endResetModel(); + } else { + endRemoveRows(); + } + std::cout << "new row count: " << rowCount(refreshedIndex) << std::endl; + } } - refreshedItem->children.clear(); - if (refreshedItem == m_root.get()) { - endResetModel(); - } else { - endRemoveRows(); + if (!items.empty()) { + QTimer::singleShot(400, this, [this, p = std::move(p), items = std::move(items)]() mutable { + const auto refreshedIndex = index(p); + if (!refreshedIndex.isValid()) { + m_fetchQueue.removeAll(p); + processFetchQueue(); + return; + } + auto *const refreshedItem = reinterpret_cast(refreshedIndex.internalPointer()); + const auto last = items.size() - 1; + addLevel(items, refreshedItem->level); + for (auto &item : items) { + item->parent = refreshedItem; + } + beginInsertRows( + refreshedIndex, 0, last < std::numeric_limits::max() ? static_cast(last) : std::numeric_limits::max()); + refreshedItem->children = std::move(items); + refreshedItem->childrenPopulated = true; + endInsertRows(); + + m_fetchQueue.removeAll(p); + processFetchQueue(); + }); } - } - if (!items.empty()) { - const auto last = items.size() - 1; - addLevel(items, refreshedItem->level); - for (auto &item : items) { - item->parent = refreshedItem; - } - beginInsertRows(refreshedIndex, 0, last < std::numeric_limits::max() ? static_cast(last) : std::numeric_limits::max()); - refreshedItem->children = std::move(items); - refreshedItem->childrenPopulated = true; - endInsertRows(); - } - processFetchQueue(); - }); + }); } } // namespace Data