diff --git a/CMakeLists.txt b/CMakeLists.txt index 22a6c7b..6b0700f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,36 +46,29 @@ add_dependencies(gitver check_git) set(SOURCE_FILES src/main.cpp + resource/resource.qrc + inc/gitver.h - gui/spkwindow.cpp - inc/spkwindow.h - gui/spktitlebar.cpp - inc/spktitlebar.h - inc/spkui_general.h - gui/spkui_general.cpp inc/deepinplatform.h inc/dtk/spkdtkplugin.h - src/spklogging.cpp - inc/spklogging.h - inc/spkuimsg.h - src/spkuimsg.cpp - inc/spkmainwindow.h - inc/spkmsgbox.h - gui/spkmsgbox.cpp - inc/spkdialog.h - gui/spkdialog.cpp - inc/spkabout.h - gui/spkabout.cpp - inc/spkstore.h - src/spkstore.cpp - gui/spkmainwindow.cpp - inc/spkpageqsstest.h - gui/spkpageqsstest.cpp - inc/spkconfig.h + inc/spkutils.h src/spkutils.cpp inc/telemetry/collectid.h - gui/spkloading.cpp - inc/spkloading.h + + inc/spkwindow.h gui/spkwindow.cpp + inc/spktitlebar.h gui/spktitlebar.cpp + inc/spkui_general.h gui/spkui_general.cpp + inc/spkmainwindow.h gui/spkmainwindow.cpp + inc/spkmsgbox.h gui/spkmsgbox.cpp + inc/spkdialog.h gui/spkdialog.cpp + inc/spkabout.h gui/spkabout.cpp + inc/spkpageqsstest.h gui/spkpageqsstest.cpp + inc/spkloading.h gui/spkloading.cpp + inc/spksidebartree.h gui/spksidebartree.cpp + + inc/spkstore.h src/spkstore.cpp + inc/spkuimsg.h src/spkuimsg.cpp + inc/spklogging.h src/spklogging.cpp ) include(cmake/FindLibNotify.cmake) diff --git a/gui/spkmainwindow.cpp b/gui/spkmainwindow.cpp index 8ef6c80..fac9518 100644 --- a/gui/spkmainwindow.cpp +++ b/gui/spkmainwindow.cpp @@ -5,6 +5,7 @@ #include "spkmsgbox.h" #include "spkmainwindow.h" #include "spklogging.h" +#include "spkutils.h" #include "spkuimsg.h" SpkMainWindow::SpkMainWindow(QWidget *parent) : SpkWindow(parent) @@ -14,47 +15,23 @@ SpkMainWindow::SpkMainWindow(QWidget *parent) : SpkWindow(parent) SetUseTitleBar(false); SetCentralWidget(ui); SetTitleBar(ui->TitleBar, false); + RefreshCategoryData(); auto size = QGuiApplication::primaryScreen()->size() * 0.25; resize(QGuiApplication::primaryScreen()->size() * 0.5); move(size.width(), size.height()); } -void SpkMainWindow::PopulateCategories(QJsonObject aCategoryData) +void SpkMainWindow::PopulateCategories(QJsonArray aCategoryData) { + using SpkUi::SpkSidebarSelector; + QTreeWidgetItem *catg; auto w = ui->CategoryWidget; - if(!aCategoryData.contains("code")) - { - SpkUiMessage::SendStoreNotification(tr("Failed to load categories; return code lost.")); - return; - } - auto OpRetCode = aCategoryData.value("code"); - if(!OpRetCode.isDouble()) - { - SpkUiMessage::SendStoreNotification(tr("Failed to load categories; invalid return code.")); - return; - } - if(OpRetCode.toInt() != 0) - { - SpkUiMessage::SendStoreNotification(tr("Failed to load categories; operation failed: %1.") - .arg(OpRetCode.toDouble())); - return; - } + if(ui->CategoryParentItem->childCount()) // Clear all existing children if there is any + foreach(auto &i, ui->CategoryParentItem->takeChildren()) + delete i; - if(!aCategoryData.contains("data")) - { - SpkUiMessage::SendStoreNotification(tr("Failed to load categories; data lost.")); - return; - } - auto OpData = aCategoryData.value("data"); - if(!OpRetCode.isArray()) - { - SpkUiMessage::SendStoreNotification(tr("Failed to load categories; invalid data.")); - return; - } - - auto OpDataArr = OpData.toArray(); - foreach(auto i, OpDataArr) + foreach(auto i, aCategoryData) { if(i.isObject()) { @@ -67,20 +44,41 @@ void SpkMainWindow::PopulateCategories(QJsonObject aCategoryData) if(j.contains("type_name") && j.value("type_name").isString()) typeName = j.value("type_name").toString(); else goto WRONG_CATEGORY; - // TODO + catg = new QTreeWidgetItem(ui->CategoryParentItem, QStringList(typeName)); + catg->setData(0, SpkSidebarSelector::RoleItemIsCategory, true); + catg->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, typeId); continue; +WRONG_CATEGORY:; } - WRONG_CATEGORY: - sLog("One category ignored because of invalid data"); + ui->CategoryParentItem->setExpanded(true); } } +void SpkMainWindow::RefreshCategoryData() +{ + // Asynchronously call category API + using namespace SpkUtils; + VerifySingleRequest(mCategoryGetReply); + mCategoryGetReply = STORE->SendApiRequest("type/get_type_list"); + DeleteReplyLater(mCategoryGetReply); + connect(mCategoryGetReply, &QNetworkReply::finished, this, &SpkMainWindow::CategoryDataReceived); +} + +void SpkMainWindow::CategoryDataReceived() +{ + QJsonValue retval; + if(!SpkUtils::VerifyReplyJson(mCategoryGetReply, retval) || !retval.isArray()) + { + sErr(tr("Failed to load categories!")); + // TODO: Switch to an error page + } + PopulateCategories(retval.toArray()); +} + SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent) { setObjectName("spk_mainwidget"); - QTreeWidgetItem *item; - Pager = new QStackedWidget(this); Pager->setObjectName("spk_mw_pager"); Pager->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -140,16 +138,19 @@ SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent) HLaySideTop->addWidget(BtnSettings); VLaySidebar->addLayout(HLaySideTop); - CategoryWidget = new QTreeWidget(this); + using SpkUi::SpkSidebarSelector; + CategoryWidget = new SpkSidebarTree(this); CategoryWidget->setObjectName("spk_mw_category"); CategoryWidget->setAutoFillBackground(true); CategoryWidget->setColumnCount(1); CategoryWidget->setHeaderHidden(true); CategoryWidget->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); - item = new QTreeWidgetItem(QStringList("Placeholder")); - item->setData(0, Qt::UserRole + 1, 1); - item->setData(0, Qt::UserRole + 2, 1); - CategoryWidget->addTopLevelItem(item); + CategoryParentItem = new QTreeWidgetItem(QStringList(tr("Categories"))); + CategoryParentItem->setFlags(CategoryParentItem->flags().setFlag(Qt::ItemIsSelectable, false)); + CategoryParentItem->setExpanded(true); + SidebarMgr->AddUnusableItem(CategoryParentItem); + CategoryWidget->addTopLevelItem(CategoryParentItem); + // FIXMEIFPOSSIBLE: Fusion adds extra gradient. // Details: https://forum.qt.io/topic/128190/fusion-style-kept-adding-an-extra- // layer-of-gradient-to-my-selected-item-of-qtreewidget-even-with-qss diff --git a/gui/spkmsgbox.cpp b/gui/spkmsgbox.cpp index 2178d41..070203e 100644 --- a/gui/spkmsgbox.cpp +++ b/gui/spkmsgbox.cpp @@ -19,7 +19,7 @@ SpkMsgBox::SpkMsgBox(QWidget *parent) } int SpkMsgBox::StaticExec(QString msg, QString title, QMessageBox::Icon icon, - QMessageBox::StandardButtons buttons, QString extra) + QMessageBox::StandardButtons buttons, QString extra, bool expanded) { SpkMsgBox *b = new SpkMsgBox(SpkStore::Instance->GetRootWindow()); QWidget *wMsgWidget = new QWidget; @@ -98,8 +98,12 @@ int SpkMsgBox::StaticExec(QString msg, QString title, QMessageBox::Icon icon, b->AddSpacing(3); AddButtons(b, buttons); - if(hasextra) // Keep conventional buttons centered - b->mBtnLay->addStretch(); + if(hasextra) + { + b->mBtnLay->addStretch(); // Keep conventional buttons centered + if(expanded) + emit wExpandBtn->clicked(); + } InitialHeight = b->minimumSizeHint().height(); auto pos = (SpkUi::PrimaryScreenSize - b->sizeHint()) / 2; b->move(pos.width(), pos.height()); diff --git a/gui/spksidebartree.cpp b/gui/spksidebartree.cpp new file mode 100644 index 0000000..9bfc131 --- /dev/null +++ b/gui/spksidebartree.cpp @@ -0,0 +1,31 @@ + +#include +#include "spksidebartree.h" + +SpkUi::SpkSidebarTree::SpkSidebarTree(QWidget *parent) : + QTreeWidget(parent) +{ + +} + +void SpkUi::SpkSidebarTree::mouseMoveEvent(QMouseEvent *e) +{ + // This is solely for forcibly disabling the view to change selection when dragging on the view + // and probably the only reason why this class began its existence + if((e->buttons() & Qt::LeftButton)) + setState(NoState); + else + QTreeWidget::mouseMoveEvent(e); +} + +void SpkUi::SpkSidebarTree::mousePressEvent(QMouseEvent *e) +{ + // Prevent anything being deselected + if(e->modifiers().testFlag(Qt::ControlModifier) && e->buttons().testFlag(Qt::LeftButton)) + { + auto i = itemAt(e->pos()); + if(i && i->isSelected()) + return; + } + QTreeWidget::mousePressEvent(e); +} diff --git a/gui/spkui_general.cpp b/gui/spkui_general.cpp index cad5f0f..c9266c6 100644 --- a/gui/spkui_general.cpp +++ b/gui/spkui_general.cpp @@ -115,7 +115,7 @@ namespace SpkUi // FIXME: Chameleon style kept adding unwanted blue focus indication border // to widgets that shouldn't have borders. // We need to eliminate this irritating problem. - if(qgetenv("SPARK_NO_QSTYLE_CHANGE") == "1") + if(qgetenv("SPARK_NO_QSTYLE_CHANGE").toInt()) return; OldSystemStyle = QStyleFactory::create("chameleon"); // TreeWidget doesn't work well with Fusion auto styles = QStyleFactory::keys(); diff --git a/inc/spkconfig.h b/inc/spkconfig.h deleted file mode 100644 index 3b9c701..0000000 --- a/inc/spkconfig.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef SPKCONFIG_H -#define SPKCONFIG_H - - - -#endif // SPKCONFIG_H diff --git a/inc/spklogging.h b/inc/spklogging.h index fe5ed38..17ec9b5 100644 --- a/inc/spklogging.h +++ b/inc/spklogging.h @@ -41,4 +41,4 @@ class SpkLogger #define sErr(X) SpkLogger::GetInstance()->Error(X) #define sErrPop(X) SpkLogger::GetInstance()->Error(X,true) #define sCritical(X) SpkLogger::GetInstance()->Critical(X) -#define sNotify(X) +#define sNotify(X) SpkLogger::GetInstance()->Notify(X) diff --git a/inc/spkmainwindow.h b/inc/spkmainwindow.h index 42d08a4..57517bc 100644 --- a/inc/spkmainwindow.h +++ b/inc/spkmainwindow.h @@ -9,9 +9,12 @@ #include #include #include -#include +#include "spksidebartree.h" // In place of #include +#include #include "spkpageqsstest.h" +class QNetworkReply; + namespace SpkUi { class SpkSidebarSelector : public QObject @@ -21,6 +24,7 @@ namespace SpkUi QPushButton *mLastCheckedBtn; QTreeWidgetItem *mLastSelectedItem; QTreeWidget *mCategoryWidget; + QVector mUnusableItems; // Unselectable top level items; never changes public: SpkSidebarSelector(QObject *parent = nullptr) : QObject(parent) @@ -40,9 +44,10 @@ namespace SpkUi void BindCategoryWidget(QTreeWidget* w) { mCategoryWidget = w; - connect(w, &QTreeWidget::itemPressed, this, + connect(w, &QTreeWidget::itemClicked, this, &SpkSidebarSelector::TreeItemSelected); } + void AddUnusableItem(QTreeWidgetItem *i) { mUnusableItems.append(i); } private slots: // We assume the objects in interest all have the correct properties @@ -73,6 +78,10 @@ namespace SpkUi } void TreeItemSelected(QTreeWidgetItem *item, int column) { + if(mUnusableItems.contains(item)) + { + UnusableItemSelected(item); return; + } if(mLastCheckedBtn) { mLastCheckedBtn->setChecked(false); @@ -84,6 +93,18 @@ namespace SpkUi else emit SwitchToPage(item->data(column, RoleItemCategoryPageId).toInt()); } + void UnusableItemSelected(QTreeWidgetItem *i) + { + i->setSelected(false); + if(mLastSelectedItem) + { + mLastSelectedItem->setSelected(true); + } + else if(mLastCheckedBtn) + { + mLastCheckedBtn->setChecked(true); + } + } signals: void SwitchToCategory(int aCategoryId); @@ -109,10 +130,12 @@ namespace SpkUi QHBoxLayout *HLaySideTop; QLabel *StoreIcon; QPushButton *BtnSettings, *BtnFeedback, *BtnLogs; - QTreeWidget *CategoryWidget; + SpkSidebarTree *CategoryWidget; QMap *CategoryItemMap; SpkSidebarSelector *SidebarMgr; + QTreeWidgetItem *CategoryParentItem; + //Pages SpkPageQssTest *PageQssTest; }; @@ -127,5 +150,14 @@ class SpkMainWindow : public SpkWindow public: SpkMainWindow(QWidget *parent = nullptr); - void PopulateCategories(QJsonObject); + void PopulateCategories(QJsonArray); + + private: + QPointer mCategoryGetReply; + + public slots: + void RefreshCategoryData(); + + private slots: + void CategoryDataReceived(); }; diff --git a/inc/spkmsgbox.h b/inc/spkmsgbox.h index c899b74..414cf22 100644 --- a/inc/spkmsgbox.h +++ b/inc/spkmsgbox.h @@ -10,7 +10,8 @@ class SpkMsgBox : public SpkDialog public: SpkMsgBox(QWidget *parent = nullptr); static int StaticExec(QString msg, QString title, QMessageBox::Icon = QMessageBox::NoIcon, - QMessageBox::StandardButtons = QMessageBox::Ok, QString extra = ""); + QMessageBox::StandardButtons = QMessageBox::Ok, QString extra = "", + bool expanded = false); private: static void AddButtons(SpkMsgBox *me, QMessageBox::StandardButtons b); QList mButtonList; diff --git a/inc/spksidebartree.h b/inc/spksidebartree.h new file mode 100644 index 0000000..08f29b8 --- /dev/null +++ b/inc/spksidebartree.h @@ -0,0 +1,17 @@ + +#pragma once + +#include + +namespace SpkUi +{ + class SpkSidebarTree : public QTreeWidget + { + Q_OBJECT + public: + SpkSidebarTree(QWidget* parent = nullptr); + protected: + void mouseMoveEvent(QMouseEvent *) override; + void mousePressEvent(QMouseEvent *) override; + }; +} diff --git a/inc/spkstore.h b/inc/spkstore.h index 97eb54c..a3fce4b 100644 --- a/inc/spkstore.h +++ b/inc/spkstore.h @@ -1,8 +1,9 @@ #pragma once -#include +#include #include +#include #include #include @@ -20,35 +21,19 @@ class SpkStore : public QObject Q_OBJECT public: static SpkStore *Instance; + QSettings *mCfg; SpkStore(bool aCli, QString &aLogPath); ~SpkStore(); SpkMainWindow* GetRootWindow() { return mMainWindow; } + void SetApiResuestUrl(QString aUrlStr) { mApiRequestUrl = aUrlStr; } + QString GetApiRequestUrl() { return mApiRequestUrl; } + QNetworkReply *SendApiRequest(QString path, QJsonDocument param = QJsonDocument()); + private: SpkLogger *mLogger; SpkMainWindow *mMainWindow = nullptr; - QNetworkAccessManager *mNetMgr = nullptr; - - // Following are stationary signal-slot bindings between UI and Store, mostly for handling - // API calls and resource downloading. - public slots: - -// void RequestStoreMetadata(); ///< All required metadata the store needs when launched -// void RequestCategoryPage(int aCategoryId); -// void RequestApplicationMetadata(int aAppId); -// void RequestRefreshApiUrls(QString aCustomUrl); - signals: - void StatusStoreMetadata(QNetworkReply::NetworkError, QString); - void StatusCategoryPage(QNetworkReply::NetworkError, QString); - void StatusApplicationMetadata(QNetworkReply::NetworkError, QString); - void StatusRefreshApiUrls(QNetworkReply::NetworkError, QString); - - private: - // Store manages all kinds of possible replies, and the caller can only get JSON they need - QNetworkReply *mReplyStoreMetadata = nullptr, - *mReplyCategory = nullptr, - *mReplyAppMetadata = nullptr, - *mReplyApiUrls = nullptr; + QString mDistroName, mApiRequestUrl, mUserAgentStr; }; diff --git a/inc/spkutils.h b/inc/spkutils.h new file mode 100644 index 0000000..6511cfd --- /dev/null +++ b/inc/spkutils.h @@ -0,0 +1,25 @@ + +#pragma once + +#include +#include +#include +#include +#include + +#include "spkstore.h" +#include "spklogging.h" + +#define STORE SpkStore::Instance +#define CFG (SpkStore::Instance->mCfg) + +namespace SpkUtils +{ + QString GetDistroName(); + + void VerifySingleRequest(QPointer aReply); + + void DeleteReplyLater(QNetworkReply *aReply); + + bool VerifyReplyJson(QNetworkReply *aReply, QJsonValue& aRetDoc); +} diff --git a/resource/default_config b/resource/default_config new file mode 100644 index 0000000..e7a40cf --- /dev/null +++ b/resource/default_config @@ -0,0 +1,3 @@ + +[Apis] +MasterApiUrl=https://store.deepinos.org/api diff --git a/resource/resource.qrc b/resource/resource.qrc index ee7b1f1..5d63e11 100644 --- a/resource/resource.qrc +++ b/resource/resource.qrc @@ -4,6 +4,7 @@ lipsum.txt + default_config icons/spark-store.svg diff --git a/src/spklogging.cpp b/src/spklogging.cpp index cc851cf..8bdd58f 100644 --- a/src/spklogging.cpp +++ b/src/spklogging.cpp @@ -96,12 +96,12 @@ void SpkLogger::Error(QString message, const bool pop) // .arg(message)); // msgbox.exec(); // I don't know whether we need to show it non-modal. SpkMsgBox::StaticExec(QObject::tr("Spark Store has encountered an error.\n" - "Parts of the experience is expected to be broken.\n\n" - "Details:\n%1"), + "Parts of the experience is expected to be broken.\n\n"), QObject::tr("Spark Store Error"), QMessageBox::Critical, QMessageBox::Ok, - message); + message, + true); } } @@ -122,3 +122,8 @@ void SpkLogger::Critical(QString message) exit(2); } +void SpkLogger::Notify(QString message) +{ + Q_UNUSED(message); +} + diff --git a/src/spkstore.cpp b/src/spkstore.cpp index a4e18ff..9765dc5 100644 --- a/src/spkstore.cpp +++ b/src/spkstore.cpp @@ -1,12 +1,16 @@ #include -#include "dtk/spkdtkplugin.h" #include #include #include +#include +#include "dtk/spkdtkplugin.h" +#include "gitver.h" #include "spkstore.h" +#include "spkutils.h" SpkStore *SpkStore::Instance = nullptr; +static void InstallDefaultConfigs(); SpkStore::SpkStore(bool aCli, QString &aLogPath) { @@ -17,8 +21,27 @@ SpkStore::SpkStore(bool aCli, QString &aLogPath) Instance = this; // Finish all essential initialization after this. + if(QFileInfo(QDir::homePath() + "/.config/spark-store/config").exists()) + mCfg = new QSettings(QDir::homePath() + "/.config/spark-store/config", QSettings::IniFormat); + else + { + mCfg = new QSettings(":/info/default_config", QSettings::IniFormat); +#ifndef NDEBUG + if(!qgetenv("SPARK_NO_INSTALL_CONFIG").toInt()) + { + if(!QFile::copy(":/info/default_config", QDir::homePath() + "/.config/spark-store/config")) + sErrPop(tr("Cannot install default config file!")); + } +#endif + } mNetMgr = new QNetworkAccessManager(this); + mNetMgr->setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); // FIXME + mDistroName = SpkUtils::GetDistroName(); + mApiRequestUrl = "https://store.deepinos.org/api/"; // TODO: CHECK BEFORE 4.0 RELEASE + mUserAgentStr = QString("Spark-Store/%1 Distro/%2") + .arg(GitVer::DescribeTags()) + .arg(mDistroName); // Finish all essential initialization before this. if(aCli) @@ -36,3 +59,17 @@ SpkStore::~SpkStore() delete mMainWindow; delete mLogger; } + +QNetworkReply *SpkStore::SendApiRequest(QString aPath, QJsonDocument aParam) +{ + QNetworkRequest request; + request.setUrl(mApiRequestUrl + aPath); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + request.setHeader(QNetworkRequest::UserAgentHeader, mUserAgentStr); + return mNetMgr->post(request, aParam.isEmpty() ? "{}" : aParam.toJson(QJsonDocument::Compact)); +} + +static void InstallDefaultConfigs() +{ + //TODO:STUB +} diff --git a/src/spkutils.cpp b/src/spkutils.cpp new file mode 100644 index 0000000..c293483 --- /dev/null +++ b/src/spkutils.cpp @@ -0,0 +1,78 @@ + +#include +#include "spkutils.h" + +void SpkUtils::VerifySingleRequest(QPointer aReply) +{ + if(aReply.isNull()) + return; + aReply->disconnect(SIGNAL(finished())); + aReply->abort(); + aReply->deleteLater(); +} + +QString SpkUtils::GetDistroName() +{ + QSettings osRelease("/etc/os-release", QSettings::IniFormat); + return osRelease.value("PRETTY_NAME", "Unknown Distro").toString(); +} + +bool SpkUtils::VerifyReplyJson(QNetworkReply *aReply, QJsonValue &aRetDoc) +{ + QJsonParseError err; + QByteArray rawjson = aReply->readAll(); + qDebug() << "Received:" << rawjson; + QJsonDocument ret = QJsonDocument::fromJson(rawjson, &err); + QJsonObject replyObject; + if(err.error != QJsonParseError::NoError) + { + sNotify(QObject::tr("Failed to parse server reply! Error %1.").arg(err.error)); + sErr(QObject::tr("VerifyReplyJson: returned JSON of request to %1 is unreadable.") + .arg(aReply->url().toString())); + return false; + } + if(!ret.isObject()) + { + sNotify(QObject::tr("Server sent back an invalid response.")); + sErr(QObject::tr("VerifyReplyJson: returned JSON of request to %1 is not an Object.") + .arg(aReply->url().toString())); + return false; + } + replyObject = ret.object(); + if(!replyObject.contains("code")) + { + sWarn(QObject::tr("VerifyReplyJson: reply of request to %1 doesn't have a code.") + .arg(aReply->url().toString())); + } + else + { + auto OpRetCode = replyObject.value("code"); + if(!OpRetCode.isDouble()) + { + sWarn(QObject::tr("VerifyReplyJson: Reply of request to %1 has a non-numeric code.") + .arg(aReply->url().toString())); + } + else if(OpRetCode.toInt() != 0) + { + sNotify(QObject::tr("Server sent back an failure message; code: %1.") + .arg(OpRetCode.toInt())); + sErr(QObject::tr("VerifyReplyJson: Request to %1 failed with code %2.") + .arg(aReply->url().toString()).arg(OpRetCode.toInt())); + return false; + } + } + if(!replyObject.contains("data")) + { + sNotify(QObject::tr("Server did not reply with any data.")); + sErr(QObject::tr("VerifyReplyJson: Reply of request to %1 didn't include any data.") + .arg(aReply->url().toString())); + return false; + } + aRetDoc = replyObject.value("data"); + return true; +} + +void SpkUtils::DeleteReplyLater(QNetworkReply *aReply) +{ + QObject::connect(aReply, &QNetworkReply::finished, aReply, &QObject::deleteLater); +}