WIP
This commit is contained in:
parent
18e30d8af0
commit
23425b6223
|
@ -56,7 +56,7 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingItem {
|
||||||
CppUtilities::DateTime modificationTime = CppUtilities::DateTime();
|
CppUtilities::DateTime modificationTime = CppUtilities::DateTime();
|
||||||
std::size_t size = std::size_t();
|
std::size_t size = std::size_t();
|
||||||
SyncthingItemType type = SyncthingItemType::Unknown;
|
SyncthingItemType type = SyncthingItemType::Unknown;
|
||||||
std::vector<SyncthingItem> children;
|
std::vector<std::unique_ptr<SyncthingItem>> children;
|
||||||
SyncthingItem *parent = nullptr; // not populated but might be set as needed (take care in case the pointer gets invalidated)
|
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();
|
std::size_t index = std::size_t();
|
||||||
int level = 0; // the level of nesting, does *not* include levels of the prefix
|
int level = 0; // the level of nesting, does *not* include levels of the prefix
|
||||||
|
@ -253,8 +253,7 @@ public Q_SLOTS:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// methods to GET or POST information from/to Syncthing (non-slots)
|
// methods to GET or POST information from/to Syncthing (non-slots)
|
||||||
QMetaObject::Connection browse(
|
QMetaObject::Connection browse(const QString &dirId, const QString &prefix, int level, std::function<void (std::vector<std::unique_ptr<SyncthingItem> > &&, QString &&)> &&callback);
|
||||||
const QString &dirId, const QString &prefix, int level, std::function<void(std::vector<SyncthingItem> &&, QString &&error)> &&callback);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void newConfig(const QJsonObject &rawConfig);
|
void newConfig(const QJsonObject &rawConfig);
|
||||||
|
@ -369,7 +368,7 @@ private Q_SLOTS:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// handler to evaluate results from request...() methods
|
// handler to evaluate results from request...() methods
|
||||||
void readBrowse(const QString &dirId, int levels, std::function<void (std::vector<SyncthingItem> &&, QString &&)> &&callback);
|
void readBrowse(const QString &dirId, int levels, std::function<void (std::vector<std::unique_ptr<SyncthingItem> > &&, QString &&)> &&callback);
|
||||||
|
|
||||||
// internal helper methods
|
// internal helper methods
|
||||||
struct Reply {
|
struct Reply {
|
||||||
|
|
|
@ -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
|
* 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.
|
* 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<void (std::vector<SyncthingItem> &&, QString &&)> &&callback)
|
QMetaObject::Connection SyncthingConnection::browse(const QString &dirId, const QString &prefix, int levels, std::function<void (std::vector<std::unique_ptr<SyncthingItem>> &&, QString &&)> &&callback)
|
||||||
{
|
{
|
||||||
auto query = QUrlQuery();
|
auto query = QUrlQuery();
|
||||||
query.addQueryItem(QStringLiteral("folder"), formatQueryItem(dirId));
|
query.addQueryItem(QStringLiteral("folder"), formatQueryItem(dirId));
|
||||||
|
@ -1606,7 +1606,7 @@ QMetaObject::Connection SyncthingConnection::browse(const QString &dirId, const
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \cond
|
/// \cond
|
||||||
static void readSyncthingItems(const QJsonArray &array, std::vector<SyncthingItem> &into, int level, int levels)
|
static void readSyncthingItems(const QJsonArray &array, std::vector<std::unique_ptr<SyncthingItem>> &into, int level, int levels)
|
||||||
{
|
{
|
||||||
into.reserve(static_cast<std::size_t>(array.size()));
|
into.reserve(static_cast<std::size_t>(array.size()));
|
||||||
for (const auto &jsonItem : array) {
|
for (const auto &jsonItem : array) {
|
||||||
|
@ -1617,10 +1617,10 @@ static void readSyncthingItems(const QJsonArray &array, std::vector<SyncthingIte
|
||||||
const auto type = jsonItemObj.value(QLatin1String("type")).toString();
|
const auto type = jsonItemObj.value(QLatin1String("type")).toString();
|
||||||
const auto index = into.size();
|
const auto index = into.size();
|
||||||
const auto children = jsonItemObj.value(QLatin1String("children"));
|
const auto children = jsonItemObj.value(QLatin1String("children"));
|
||||||
auto &item = into.emplace_back();
|
auto &item = into.emplace_back(std::make_unique<SyncthingItem>());
|
||||||
item.name = jsonItemObj.value(QLatin1String("name")).toString();
|
item->name = jsonItemObj.value(QLatin1String("name")).toString();
|
||||||
item.modificationTime = CppUtilities::DateTime::fromIsoStringGmt(jsonItemObj.value(QLatin1String("modTime")).toString().toUtf8().data());
|
item->modificationTime = CppUtilities::DateTime::fromIsoStringGmt(jsonItemObj.value(QLatin1String("modTime")).toString().toUtf8().data());
|
||||||
item.size = static_cast<std::size_t>(jsonItemObj
|
item->size = static_cast<std::size_t>(jsonItemObj
|
||||||
.value(QLatin1String("size"))
|
.value(QLatin1String("size"))
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
.toInteger()
|
.toInteger()
|
||||||
|
@ -1628,15 +1628,15 @@ static void readSyncthingItems(const QJsonArray &array, std::vector<SyncthingIte
|
||||||
.toDouble()
|
.toDouble()
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
item.index = index;
|
item->index = index;
|
||||||
item.level = level;
|
item->level = level;
|
||||||
if (type == QLatin1String("FILE_INFO_TYPE_FILE")) {
|
if (type == QLatin1String("FILE_INFO_TYPE_FILE")) {
|
||||||
item.type = SyncthingItemType::File;
|
item->type = SyncthingItemType::File;
|
||||||
} else if (type == QLatin1String("FILE_INFO_TYPE_DIRECTORY")) {
|
} else if (type == QLatin1String("FILE_INFO_TYPE_DIRECTORY")) {
|
||||||
item.type = SyncthingItemType::Directory;
|
item->type = SyncthingItemType::Directory;
|
||||||
}
|
}
|
||||||
readSyncthingItems(children.toArray(), item.children, level + 1, levels);
|
readSyncthingItems(children.toArray(), item->children, level + 1, levels);
|
||||||
item.childrenPopulated = !levels || level < levels;
|
item->childrenPopulated = !levels || level < levels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
@ -1645,13 +1645,13 @@ static void readSyncthingItems(const QJsonArray &array, std::vector<SyncthingIte
|
||||||
* \brief Reads the response of browse() and reports results via the specified \a callback. Emits error() in case of an error.
|
* \brief Reads the response of browse() and reports results via the specified \a callback. Emits error() in case of an error.
|
||||||
* \remarks The \a callback is also emitted in the error case (with the error message as second parameter and an empty list of items).
|
* \remarks The \a callback is also emitted in the error case (with the error message as second parameter and an empty list of items).
|
||||||
*/
|
*/
|
||||||
void SyncthingConnection::readBrowse(const QString &dirId, int levels, std::function<void (std::vector<SyncthingItem> &&, QString &&)> &&callback)
|
void SyncthingConnection::readBrowse(const QString &dirId, int levels, std::function<void (std::vector<std::unique_ptr<SyncthingItem>> &&, QString &&)> &&callback)
|
||||||
{
|
{
|
||||||
auto const [reply, response] = prepareReply();
|
auto const [reply, response] = prepareReply();
|
||||||
if (!reply) {
|
if (!reply) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto items = std::vector<SyncthingItem>();
|
auto items = std::vector<std::unique_ptr<SyncthingItem>>();
|
||||||
switch (reply->error()) {
|
switch (reply->error()) {
|
||||||
case QNetworkReply::NoError: {
|
case QNetworkReply::NoError: {
|
||||||
auto jsonError = QJsonParseError();
|
auto jsonError = QJsonParseError();
|
||||||
|
|
|
@ -19,14 +19,18 @@ SyncthingFileModel::SyncthingFileModel(SyncthingConnection &connection, const Sy
|
||||||
: SyncthingModel(connection, parent)
|
: SyncthingModel(connection, parent)
|
||||||
, m_connection(connection)
|
, m_connection(connection)
|
||||||
, m_dirId(dir.id)
|
, m_dirId(dir.id)
|
||||||
, m_root({ .name = dir.displayName(), .modificationTime = dir.lastFileTime, .size = dir.globalStats.bytes, .type = SyncthingItemType::Directory })
|
, m_root(std::make_unique<SyncthingItem>())
|
||||||
{
|
{
|
||||||
m_connection.browse(m_dirId, QString(), 1, [this](std::vector<SyncthingItem> &&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<std::unique_ptr<SyncthingItem>> &&items, QString &&errorMessage) {
|
||||||
Q_UNUSED(errorMessage)
|
Q_UNUSED(errorMessage)
|
||||||
const auto last = items.size() - 1;
|
const auto last = items.size() - 1;
|
||||||
beginInsertRows(index(0, 0), 0, last < std::numeric_limits<int>::max() ? static_cast<int>(last) : std::numeric_limits<int>::max());
|
beginInsertRows(index(0, 0), 0, last < std::numeric_limits<int>::max() ? static_cast<int>(last) : std::numeric_limits<int>::max());
|
||||||
m_root.children = std::move(items);
|
m_root->children = std::move(items);
|
||||||
m_root.childrenPopulated = true;
|
m_root->childrenPopulated = true;
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -55,7 +59,7 @@ QModelIndex SyncthingFileModel::index(int row, int column, const QModelIndex &pa
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
if (!parent.isValid()) {
|
if (!parent.isValid()) {
|
||||||
return static_cast<std::size_t>(row) ? QModelIndex() : createIndex(row, column, &m_root);
|
return static_cast<std::size_t>(row) ? QModelIndex() : createIndex(row, column, m_root.get());
|
||||||
}
|
}
|
||||||
auto *const parentItem = reinterpret_cast<SyncthingItem *>(parent.internalPointer());
|
auto *const parentItem = reinterpret_cast<SyncthingItem *>(parent.internalPointer());
|
||||||
if (!parentItem) {
|
if (!parentItem) {
|
||||||
|
@ -66,21 +70,21 @@ QModelIndex SyncthingFileModel::index(int row, int column, const QModelIndex &pa
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
auto &item = items[static_cast<std::size_t>(row)];
|
auto &item = items[static_cast<std::size_t>(row)];
|
||||||
item.parent = parentItem;
|
item->parent = parentItem;
|
||||||
return createIndex(row, column, &item);
|
return createIndex(row, column, item.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex SyncthingFileModel::index(const QString &path) const
|
QModelIndex SyncthingFileModel::index(const QString &path) const
|
||||||
{
|
{
|
||||||
auto parts = path.split(QChar('/'), Qt::SkipEmptyParts);
|
auto parts = path.split(QChar('/'), Qt::SkipEmptyParts);
|
||||||
auto res = index(0, 0);
|
auto res = index(0, 0);
|
||||||
auto *parent = &m_root;
|
auto *parent = m_root.get();
|
||||||
for (const auto &part : parts) {
|
for (const auto &part : parts) {
|
||||||
auto foundPart = false;
|
auto foundPart = false;
|
||||||
for (const auto &child : parent->children) {
|
for (const auto &child : parent->children) {
|
||||||
if (child.name == part) {
|
if (child->name == part) {
|
||||||
parent = &child;
|
parent = child.get();
|
||||||
res = index(static_cast<int>(child.index), 0, res);
|
res = index(static_cast<int>(child->index), 0, res);
|
||||||
foundPart = true;
|
foundPart = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +109,7 @@ QString SyncthingFileModel::path(const QModelIndex &index) const
|
||||||
parts.reserve(reinterpret_cast<SyncthingItem *>(index.internalPointer())->level + 1);
|
parts.reserve(reinterpret_cast<SyncthingItem *>(index.internalPointer())->level + 1);
|
||||||
for (auto i = index; i.isValid(); i = i.parent()) {
|
for (auto i = index; i.isValid(); i = i.parent()) {
|
||||||
const auto *const item = reinterpret_cast<SyncthingItem *>(i.internalPointer());
|
const auto *const item = reinterpret_cast<SyncthingItem *>(i.internalPointer());
|
||||||
if (item == &m_root) {
|
if (item == m_root.get()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parts.append(reinterpret_cast<SyncthingItem *>(i.internalPointer())->name);
|
parts.append(reinterpret_cast<SyncthingItem *>(i.internalPointer())->name);
|
||||||
|
@ -247,11 +251,11 @@ bool SyncthingFileModel::canFetchMore(const QModelIndex &parent) const
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \cond
|
/// \cond
|
||||||
static void addLevel(std::vector<SyncthingItem> &items, int level)
|
static void addLevel(std::vector<std::unique_ptr<SyncthingItem>> &items, int level)
|
||||||
{
|
{
|
||||||
for (auto &item : items) {
|
for (auto &item : items) {
|
||||||
item.level += level;
|
item->level += level;
|
||||||
addLevel(item.children, level);
|
addLevel(item->children, level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
@ -293,7 +297,7 @@ void SyncthingFileModel::processFetchQueue()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto &path = m_fetchQueue.front();
|
const auto &path = m_fetchQueue.front();
|
||||||
m_pendingRequest = m_connection.browse(m_dirId, path, 1, [this, p = path](std::vector<SyncthingItem> &&items, QString &&errorMessage) {
|
m_pendingRequest = m_connection.browse(m_dirId, path, 1, [this, p = path](std::vector<std::unique_ptr<SyncthingItem>> &&items, QString &&errorMessage) {
|
||||||
Q_UNUSED(errorMessage)
|
Q_UNUSED(errorMessage)
|
||||||
m_fetchQueue.removeAll(p);
|
m_fetchQueue.removeAll(p);
|
||||||
|
|
||||||
|
@ -303,15 +307,23 @@ void SyncthingFileModel::processFetchQueue()
|
||||||
}
|
}
|
||||||
auto *const refreshedItem = reinterpret_cast<SyncthingItem *>(refreshedIndex.internalPointer());
|
auto *const refreshedItem = reinterpret_cast<SyncthingItem *>(refreshedIndex.internalPointer());
|
||||||
if (!refreshedItem->children.empty()) {
|
if (!refreshedItem->children.empty()) {
|
||||||
beginRemoveRows(refreshedIndex, 0, static_cast<int>(refreshedItem->children.size() - 1));
|
if (refreshedItem == m_root.get()) {
|
||||||
|
beginResetModel();
|
||||||
|
} else {
|
||||||
|
beginRemoveRows(refreshedIndex, 0, static_cast<int>(refreshedItem->children.size() - 1));
|
||||||
|
}
|
||||||
refreshedItem->children.clear();
|
refreshedItem->children.clear();
|
||||||
endRemoveRows();
|
if (refreshedItem == m_root.get()) {
|
||||||
|
endResetModel();
|
||||||
|
} else {
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!items.empty()) {
|
if (!items.empty()) {
|
||||||
const auto last = items.size() - 1;
|
const auto last = items.size() - 1;
|
||||||
addLevel(items, refreshedItem->level);
|
addLevel(items, refreshedItem->level);
|
||||||
for (auto &item : items) {
|
for (auto &item : items) {
|
||||||
item.parent = refreshedItem;
|
item->parent = refreshedItem;
|
||||||
}
|
}
|
||||||
beginInsertRows(refreshedIndex, 0, last < std::numeric_limits<int>::max() ? static_cast<int>(last) : std::numeric_limits<int>::max());
|
beginInsertRows(refreshedIndex, 0, last < std::numeric_limits<int>::max() ? static_cast<int>(last) : std::numeric_limits<int>::max());
|
||||||
refreshedItem->children = std::move(items);
|
refreshedItem->children = std::move(items);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <syncthingconnector/syncthingconnection.h>
|
#include <syncthingconnector/syncthingconnection.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
@ -47,7 +48,7 @@ private:
|
||||||
QString m_dirId;
|
QString m_dirId;
|
||||||
QStringList m_fetchQueue;
|
QStringList m_fetchQueue;
|
||||||
QMetaObject::Connection m_pendingRequest;
|
QMetaObject::Connection m_pendingRequest;
|
||||||
SyncthingItem m_root;
|
std::unique_ptr<SyncthingItem> m_root;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
Loading…
Reference in New Issue