diff --git a/syncthingconnector/syncthingconnection.h b/syncthingconnector/syncthingconnection.h index f527d71..9e99fdc 100644 --- a/syncthingconnector/syncthingconnection.h +++ b/syncthingconnector/syncthingconnection.h @@ -56,7 +56,7 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingItem { CppUtilities::DateTime modificationTime = CppUtilities::DateTime(); std::size_t size = std::size_t(); SyncthingItemType type = SyncthingItemType::Unknown; - std::vector children; + std::vector> children; SyncthingItem *parent = nullptr; // not populated but might be set as needed (take care in case the pointer gets invalidated) std::size_t index = std::size_t(); int level = 0; // the level of nesting, does *not* include levels of the prefix @@ -253,8 +253,7 @@ 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 &&error)> &&callback); + QMetaObject::Connection browse(const QString &dirId, const QString &prefix, int level, std::function > &&, QString &&)> &&callback); Q_SIGNALS: void newConfig(const QJsonObject &rawConfig); @@ -369,7 +368,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 fa87090..d49b32f 100644 --- a/syncthingconnector/syncthingconnection_requests.cpp +++ b/syncthingconnector/syncthingconnection_requests.cpp @@ -1590,7 +1590,7 @@ 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)); @@ -1606,7 +1606,7 @@ QMetaObject::Connection SyncthingConnection::browse(const QString &dirId, const } /// \cond -static void readSyncthingItems(const QJsonArray &array, std::vector &into, int level, int levels) +static void readSyncthingItems(const QJsonArray &array, std::vector> &into, int level, int levels) { into.reserve(static_cast(array.size())); for (const auto &jsonItem : array) { @@ -1617,10 +1617,10 @@ static void readSyncthingItems(const QJsonArray &array, std::vector(jsonItemObj + auto &item = into.emplace_back(std::make_unique()); + item->name = 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")) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) .toInteger() @@ -1628,15 +1628,15 @@ static void readSyncthingItems(const QJsonArray &array, std::vectorindex = index; + item->level = level; if (type == QLatin1String("FILE_INFO_TYPE_FILE")) { - item.type = SyncthingItemType::File; + item->type = SyncthingItemType::File; } else if (type == QLatin1String("FILE_INFO_TYPE_DIRECTORY")) { - item.type = SyncthingItemType::Directory; + item->type = SyncthingItemType::Directory; } - readSyncthingItems(children.toArray(), item.children, level + 1, levels); - item.childrenPopulated = !levels || level < levels; + readSyncthingItems(children.toArray(), item->children, level + 1, levels); + item->childrenPopulated = !levels || level < levels; } } /// \endcond @@ -1645,13 +1645,13 @@ 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) { return; } - auto items = std::vector(); + auto items = std::vector>(); switch (reply->error()) { case QNetworkReply::NoError: { auto jsonError = QJsonParseError(); diff --git a/syncthingmodel/syncthingfilemodel.cpp b/syncthingmodel/syncthingfilemodel.cpp index 303c0bc..d2971c3 100644 --- a/syncthingmodel/syncthingfilemodel.cpp +++ b/syncthingmodel/syncthingfilemodel.cpp @@ -19,14 +19,18 @@ SyncthingFileModel::SyncthingFileModel(SyncthingConnection &connection, const Sy : SyncthingModel(connection, parent) , m_connection(connection) , m_dirId(dir.id) - , m_root({ .name = dir.displayName(), .modificationTime = dir.lastFileTime, .size = dir.globalStats.bytes, .type = SyncthingItemType::Directory }) + , m_root(std::make_unique()) { - m_connection.browse(m_dirId, QString(), 1, [this](std::vector &&items, QString &&errorMessage) { + m_root->name = dir.displayName(); + m_root->modificationTime = dir.lastFileTime; + m_root->size = dir.globalStats.bytes; + m_root->type = SyncthingItemType::Directory; + m_connection.browse(m_dirId, QString(), 1, [this](std::vector> &&items, QString &&errorMessage) { Q_UNUSED(errorMessage) 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); - m_root.childrenPopulated = true; + m_root->children = std::move(items); + m_root->childrenPopulated = true; endInsertRows(); }); } @@ -55,7 +59,7 @@ QModelIndex SyncthingFileModel::index(int row, int column, const QModelIndex &pa return QModelIndex(); } if (!parent.isValid()) { - return static_cast(row) ? QModelIndex() : createIndex(row, column, &m_root); + return static_cast(row) ? QModelIndex() : createIndex(row, column, m_root.get()); } auto *const parentItem = reinterpret_cast(parent.internalPointer()); if (!parentItem) { @@ -66,21 +70,21 @@ QModelIndex SyncthingFileModel::index(int row, int column, const QModelIndex &pa return QModelIndex(); } auto &item = items[static_cast(row)]; - item.parent = parentItem; - return createIndex(row, column, &item); + item->parent = parentItem; + return createIndex(row, column, item.get()); } QModelIndex SyncthingFileModel::index(const QString &path) const { auto parts = path.split(QChar('/'), Qt::SkipEmptyParts); auto res = index(0, 0); - auto *parent = &m_root; + auto *parent = m_root.get(); for (const auto &part : parts) { auto foundPart = false; for (const auto &child : parent->children) { - if (child.name == part) { - parent = &child; - res = index(static_cast(child.index), 0, res); + if (child->name == part) { + parent = child.get(); + res = index(static_cast(child->index), 0, res); foundPart = true; break; } @@ -105,7 +109,7 @@ QString SyncthingFileModel::path(const QModelIndex &index) const parts.reserve(reinterpret_cast(index.internalPointer())->level + 1); for (auto i = index; i.isValid(); i = i.parent()) { const auto *const item = reinterpret_cast(i.internalPointer()); - if (item == &m_root) { + if (item == m_root.get()) { break; } parts.append(reinterpret_cast(i.internalPointer())->name); @@ -247,11 +251,11 @@ bool SyncthingFileModel::canFetchMore(const QModelIndex &parent) const } /// \cond -static void addLevel(std::vector &items, int level) +static void addLevel(std::vector> &items, int level) { for (auto &item : items) { - item.level += level; - addLevel(item.children, level); + item->level += level; + addLevel(item->children, level); } } /// \endcond @@ -293,7 +297,7 @@ 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) { + m_pendingRequest = m_connection.browse(m_dirId, path, 1, [this, p = path](std::vector> &&items, QString &&errorMessage) { Q_UNUSED(errorMessage) m_fetchQueue.removeAll(p); @@ -303,15 +307,23 @@ void SyncthingFileModel::processFetchQueue() } auto *const refreshedItem = reinterpret_cast(refreshedIndex.internalPointer()); if (!refreshedItem->children.empty()) { - beginRemoveRows(refreshedIndex, 0, static_cast(refreshedItem->children.size() - 1)); + if (refreshedItem == m_root.get()) { + beginResetModel(); + } else { + beginRemoveRows(refreshedIndex, 0, static_cast(refreshedItem->children.size() - 1)); + } refreshedItem->children.clear(); - endRemoveRows(); + if (refreshedItem == m_root.get()) { + endResetModel(); + } else { + endRemoveRows(); + } } if (!items.empty()) { const auto last = items.size() - 1; addLevel(items, refreshedItem->level); for (auto &item : items) { - item.parent = refreshedItem; + item->parent = refreshedItem; } beginInsertRows(refreshedIndex, 0, last < std::numeric_limits::max() ? static_cast(last) : std::numeric_limits::max()); refreshedItem->children = std::move(items); diff --git a/syncthingmodel/syncthingfilemodel.h b/syncthingmodel/syncthingfilemodel.h index e03a031..4a4811a 100644 --- a/syncthingmodel/syncthingfilemodel.h +++ b/syncthingmodel/syncthingfilemodel.h @@ -5,6 +5,7 @@ #include +#include #include namespace Data { @@ -47,7 +48,7 @@ private: QString m_dirId; QStringList m_fetchQueue; QMetaObject::Connection m_pendingRequest; - SyncthingItem m_root; + std::unique_ptr m_root; }; } // namespace Data