mirror of
https://gitee.com/spark-store-project/spark-store
synced 2025-11-14 04:52:20 +08:00
添加API调用接口,添加读取分类,添加SpkUtils实用函数
使用了SpkSidebarTree子类实现对TreeWidget的特殊要求:不能取消选择,不能拖拽选择。 API调用接口暂时写死。API会获取 配置文件已添加但暂不使用。
This commit is contained in:
parent
48c9046993
commit
e3c43198b9
@ -46,36 +46,29 @@ add_dependencies(gitver check_git)
|
|||||||
|
|
||||||
set(SOURCE_FILES
|
set(SOURCE_FILES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
|
||||||
resource/resource.qrc
|
resource/resource.qrc
|
||||||
|
|
||||||
inc/gitver.h
|
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/deepinplatform.h
|
||||||
inc/dtk/spkdtkplugin.h
|
inc/dtk/spkdtkplugin.h
|
||||||
src/spklogging.cpp
|
inc/spkutils.h src/spkutils.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/telemetry/collectid.h
|
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)
|
include(cmake/FindLibNotify.cmake)
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "spkmsgbox.h"
|
#include "spkmsgbox.h"
|
||||||
#include "spkmainwindow.h"
|
#include "spkmainwindow.h"
|
||||||
#include "spklogging.h"
|
#include "spklogging.h"
|
||||||
|
#include "spkutils.h"
|
||||||
#include "spkuimsg.h"
|
#include "spkuimsg.h"
|
||||||
|
|
||||||
SpkMainWindow::SpkMainWindow(QWidget *parent) : SpkWindow(parent)
|
SpkMainWindow::SpkMainWindow(QWidget *parent) : SpkWindow(parent)
|
||||||
@ -14,47 +15,23 @@ SpkMainWindow::SpkMainWindow(QWidget *parent) : SpkWindow(parent)
|
|||||||
SetUseTitleBar(false);
|
SetUseTitleBar(false);
|
||||||
SetCentralWidget(ui);
|
SetCentralWidget(ui);
|
||||||
SetTitleBar(ui->TitleBar, false);
|
SetTitleBar(ui->TitleBar, false);
|
||||||
|
RefreshCategoryData();
|
||||||
|
|
||||||
auto size = QGuiApplication::primaryScreen()->size() * 0.25;
|
auto size = QGuiApplication::primaryScreen()->size() * 0.25;
|
||||||
resize(QGuiApplication::primaryScreen()->size() * 0.5);
|
resize(QGuiApplication::primaryScreen()->size() * 0.5);
|
||||||
move(size.width(), size.height());
|
move(size.width(), size.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpkMainWindow::PopulateCategories(QJsonObject aCategoryData)
|
void SpkMainWindow::PopulateCategories(QJsonArray aCategoryData)
|
||||||
{
|
{
|
||||||
|
using SpkUi::SpkSidebarSelector;
|
||||||
|
QTreeWidgetItem *catg;
|
||||||
auto w = ui->CategoryWidget;
|
auto w = ui->CategoryWidget;
|
||||||
if(!aCategoryData.contains("code"))
|
if(ui->CategoryParentItem->childCount()) // Clear all existing children if there is any
|
||||||
{
|
foreach(auto &i, ui->CategoryParentItem->takeChildren())
|
||||||
SpkUiMessage::SendStoreNotification(tr("Failed to load categories; return code lost."));
|
delete i;
|
||||||
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(!aCategoryData.contains("data"))
|
foreach(auto i, aCategoryData)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if(i.isObject())
|
if(i.isObject())
|
||||||
{
|
{
|
||||||
@ -67,20 +44,41 @@ void SpkMainWindow::PopulateCategories(QJsonObject aCategoryData)
|
|||||||
if(j.contains("type_name") && j.value("type_name").isString())
|
if(j.contains("type_name") && j.value("type_name").isString())
|
||||||
typeName = j.value("type_name").toString();
|
typeName = j.value("type_name").toString();
|
||||||
else goto WRONG_CATEGORY;
|
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;
|
continue;
|
||||||
|
WRONG_CATEGORY:;
|
||||||
}
|
}
|
||||||
WRONG_CATEGORY:
|
ui->CategoryParentItem->setExpanded(true);
|
||||||
sLog("One category ignored because of invalid data");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
|
||||||
{
|
{
|
||||||
setObjectName("spk_mainwidget");
|
setObjectName("spk_mainwidget");
|
||||||
|
|
||||||
QTreeWidgetItem *item;
|
|
||||||
|
|
||||||
Pager = new QStackedWidget(this);
|
Pager = new QStackedWidget(this);
|
||||||
Pager->setObjectName("spk_mw_pager");
|
Pager->setObjectName("spk_mw_pager");
|
||||||
Pager->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
Pager->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
@ -140,16 +138,19 @@ SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
|
|||||||
HLaySideTop->addWidget(BtnSettings);
|
HLaySideTop->addWidget(BtnSettings);
|
||||||
VLaySidebar->addLayout(HLaySideTop);
|
VLaySidebar->addLayout(HLaySideTop);
|
||||||
|
|
||||||
CategoryWidget = new QTreeWidget(this);
|
using SpkUi::SpkSidebarSelector;
|
||||||
|
CategoryWidget = new SpkSidebarTree(this);
|
||||||
CategoryWidget->setObjectName("spk_mw_category");
|
CategoryWidget->setObjectName("spk_mw_category");
|
||||||
CategoryWidget->setAutoFillBackground(true);
|
CategoryWidget->setAutoFillBackground(true);
|
||||||
CategoryWidget->setColumnCount(1);
|
CategoryWidget->setColumnCount(1);
|
||||||
CategoryWidget->setHeaderHidden(true);
|
CategoryWidget->setHeaderHidden(true);
|
||||||
CategoryWidget->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
|
CategoryWidget->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
|
||||||
item = new QTreeWidgetItem(QStringList("Placeholder"));
|
CategoryParentItem = new QTreeWidgetItem(QStringList(tr("Categories")));
|
||||||
item->setData(0, Qt::UserRole + 1, 1);
|
CategoryParentItem->setFlags(CategoryParentItem->flags().setFlag(Qt::ItemIsSelectable, false));
|
||||||
item->setData(0, Qt::UserRole + 2, 1);
|
CategoryParentItem->setExpanded(true);
|
||||||
CategoryWidget->addTopLevelItem(item);
|
SidebarMgr->AddUnusableItem(CategoryParentItem);
|
||||||
|
CategoryWidget->addTopLevelItem(CategoryParentItem);
|
||||||
|
|
||||||
// FIXMEIFPOSSIBLE: Fusion adds extra gradient.
|
// FIXMEIFPOSSIBLE: Fusion adds extra gradient.
|
||||||
// Details: https://forum.qt.io/topic/128190/fusion-style-kept-adding-an-extra-
|
// 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
|
// layer-of-gradient-to-my-selected-item-of-qtreewidget-even-with-qss
|
||||||
|
|||||||
@ -19,7 +19,7 @@ SpkMsgBox::SpkMsgBox(QWidget *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int SpkMsgBox::StaticExec(QString msg, QString title, QMessageBox::Icon icon,
|
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());
|
SpkMsgBox *b = new SpkMsgBox(SpkStore::Instance->GetRootWindow());
|
||||||
QWidget *wMsgWidget = new QWidget;
|
QWidget *wMsgWidget = new QWidget;
|
||||||
@ -98,8 +98,12 @@ int SpkMsgBox::StaticExec(QString msg, QString title, QMessageBox::Icon icon,
|
|||||||
|
|
||||||
b->AddSpacing(3);
|
b->AddSpacing(3);
|
||||||
AddButtons(b, buttons);
|
AddButtons(b, buttons);
|
||||||
if(hasextra) // Keep conventional buttons centered
|
if(hasextra)
|
||||||
b->mBtnLay->addStretch();
|
{
|
||||||
|
b->mBtnLay->addStretch(); // Keep conventional buttons centered
|
||||||
|
if(expanded)
|
||||||
|
emit wExpandBtn->clicked();
|
||||||
|
}
|
||||||
InitialHeight = b->minimumSizeHint().height();
|
InitialHeight = b->minimumSizeHint().height();
|
||||||
auto pos = (SpkUi::PrimaryScreenSize - b->sizeHint()) / 2;
|
auto pos = (SpkUi::PrimaryScreenSize - b->sizeHint()) / 2;
|
||||||
b->move(pos.width(), pos.height());
|
b->move(pos.width(), pos.height());
|
||||||
|
|||||||
31
gui/spksidebartree.cpp
Normal file
31
gui/spksidebartree.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
@ -115,7 +115,7 @@ namespace SpkUi
|
|||||||
// FIXME: Chameleon style kept adding unwanted blue focus indication border
|
// FIXME: Chameleon style kept adding unwanted blue focus indication border
|
||||||
// to widgets that shouldn't have borders.
|
// to widgets that shouldn't have borders.
|
||||||
// We need to eliminate this irritating problem.
|
// We need to eliminate this irritating problem.
|
||||||
if(qgetenv("SPARK_NO_QSTYLE_CHANGE") == "1")
|
if(qgetenv("SPARK_NO_QSTYLE_CHANGE").toInt())
|
||||||
return;
|
return;
|
||||||
OldSystemStyle = QStyleFactory::create("chameleon"); // TreeWidget doesn't work well with Fusion
|
OldSystemStyle = QStyleFactory::create("chameleon"); // TreeWidget doesn't work well with Fusion
|
||||||
auto styles = QStyleFactory::keys();
|
auto styles = QStyleFactory::keys();
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
#ifndef SPKCONFIG_H
|
|
||||||
#define SPKCONFIG_H
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SPKCONFIG_H
|
|
||||||
@ -41,4 +41,4 @@ class SpkLogger
|
|||||||
#define sErr(X) SpkLogger::GetInstance()->Error(X)
|
#define sErr(X) SpkLogger::GetInstance()->Error(X)
|
||||||
#define sErrPop(X) SpkLogger::GetInstance()->Error(X,true)
|
#define sErrPop(X) SpkLogger::GetInstance()->Error(X,true)
|
||||||
#define sCritical(X) SpkLogger::GetInstance()->Critical(X)
|
#define sCritical(X) SpkLogger::GetInstance()->Critical(X)
|
||||||
#define sNotify(X)
|
#define sNotify(X) SpkLogger::GetInstance()->Notify(X)
|
||||||
|
|||||||
@ -9,9 +9,12 @@
|
|||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QTreeWidget>
|
#include "spksidebartree.h" // In place of #include <QTreeWidget>
|
||||||
|
#include <QPointer>
|
||||||
#include "spkpageqsstest.h"
|
#include "spkpageqsstest.h"
|
||||||
|
|
||||||
|
class QNetworkReply;
|
||||||
|
|
||||||
namespace SpkUi
|
namespace SpkUi
|
||||||
{
|
{
|
||||||
class SpkSidebarSelector : public QObject
|
class SpkSidebarSelector : public QObject
|
||||||
@ -21,6 +24,7 @@ namespace SpkUi
|
|||||||
QPushButton *mLastCheckedBtn;
|
QPushButton *mLastCheckedBtn;
|
||||||
QTreeWidgetItem *mLastSelectedItem;
|
QTreeWidgetItem *mLastSelectedItem;
|
||||||
QTreeWidget *mCategoryWidget;
|
QTreeWidget *mCategoryWidget;
|
||||||
|
QVector<QTreeWidgetItem *> mUnusableItems; // Unselectable top level items; never changes
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SpkSidebarSelector(QObject *parent = nullptr) : QObject(parent)
|
SpkSidebarSelector(QObject *parent = nullptr) : QObject(parent)
|
||||||
@ -40,9 +44,10 @@ namespace SpkUi
|
|||||||
void BindCategoryWidget(QTreeWidget* w)
|
void BindCategoryWidget(QTreeWidget* w)
|
||||||
{
|
{
|
||||||
mCategoryWidget = w;
|
mCategoryWidget = w;
|
||||||
connect(w, &QTreeWidget::itemPressed, this,
|
connect(w, &QTreeWidget::itemClicked, this,
|
||||||
&SpkSidebarSelector::TreeItemSelected);
|
&SpkSidebarSelector::TreeItemSelected);
|
||||||
}
|
}
|
||||||
|
void AddUnusableItem(QTreeWidgetItem *i) { mUnusableItems.append(i); }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// We assume the objects in interest all have the correct properties
|
// We assume the objects in interest all have the correct properties
|
||||||
@ -73,6 +78,10 @@ namespace SpkUi
|
|||||||
}
|
}
|
||||||
void TreeItemSelected(QTreeWidgetItem *item, int column)
|
void TreeItemSelected(QTreeWidgetItem *item, int column)
|
||||||
{
|
{
|
||||||
|
if(mUnusableItems.contains(item))
|
||||||
|
{
|
||||||
|
UnusableItemSelected(item); return;
|
||||||
|
}
|
||||||
if(mLastCheckedBtn)
|
if(mLastCheckedBtn)
|
||||||
{
|
{
|
||||||
mLastCheckedBtn->setChecked(false);
|
mLastCheckedBtn->setChecked(false);
|
||||||
@ -84,6 +93,18 @@ namespace SpkUi
|
|||||||
else
|
else
|
||||||
emit SwitchToPage(item->data(column, RoleItemCategoryPageId).toInt());
|
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:
|
signals:
|
||||||
void SwitchToCategory(int aCategoryId);
|
void SwitchToCategory(int aCategoryId);
|
||||||
@ -109,10 +130,12 @@ namespace SpkUi
|
|||||||
QHBoxLayout *HLaySideTop;
|
QHBoxLayout *HLaySideTop;
|
||||||
QLabel *StoreIcon;
|
QLabel *StoreIcon;
|
||||||
QPushButton *BtnSettings, *BtnFeedback, *BtnLogs;
|
QPushButton *BtnSettings, *BtnFeedback, *BtnLogs;
|
||||||
QTreeWidget *CategoryWidget;
|
SpkSidebarTree *CategoryWidget;
|
||||||
QMap<int, QTreeWidgetItem> *CategoryItemMap;
|
QMap<int, QTreeWidgetItem> *CategoryItemMap;
|
||||||
SpkSidebarSelector *SidebarMgr;
|
SpkSidebarSelector *SidebarMgr;
|
||||||
|
|
||||||
|
QTreeWidgetItem *CategoryParentItem;
|
||||||
|
|
||||||
//Pages
|
//Pages
|
||||||
SpkPageQssTest *PageQssTest;
|
SpkPageQssTest *PageQssTest;
|
||||||
};
|
};
|
||||||
@ -127,5 +150,14 @@ class SpkMainWindow : public SpkWindow
|
|||||||
public:
|
public:
|
||||||
SpkMainWindow(QWidget *parent = nullptr);
|
SpkMainWindow(QWidget *parent = nullptr);
|
||||||
|
|
||||||
void PopulateCategories(QJsonObject);
|
void PopulateCategories(QJsonArray);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<QNetworkReply> mCategoryGetReply;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void RefreshCategoryData();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void CategoryDataReceived();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,8 @@ class SpkMsgBox : public SpkDialog
|
|||||||
public:
|
public:
|
||||||
SpkMsgBox(QWidget *parent = nullptr);
|
SpkMsgBox(QWidget *parent = nullptr);
|
||||||
static int StaticExec(QString msg, QString title, QMessageBox::Icon = QMessageBox::NoIcon,
|
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:
|
private:
|
||||||
static void AddButtons(SpkMsgBox *me, QMessageBox::StandardButtons b);
|
static void AddButtons(SpkMsgBox *me, QMessageBox::StandardButtons b);
|
||||||
QList<QMessageBox::StandardButton> mButtonList;
|
QList<QMessageBox::StandardButton> mButtonList;
|
||||||
|
|||||||
17
inc/spksidebartree.h
Normal file
17
inc/spksidebartree.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QTreeWidget>
|
||||||
|
|
||||||
|
namespace SpkUi
|
||||||
|
{
|
||||||
|
class SpkSidebarTree : public QTreeWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SpkSidebarTree(QWidget* parent = nullptr);
|
||||||
|
protected:
|
||||||
|
void mouseMoveEvent(QMouseEvent *) override;
|
||||||
|
void mousePressEvent(QMouseEvent *) override;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,8 +1,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMap>
|
#include <QJsonDocument>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QSettings>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
#include <QtNetwork/QNetworkAccessManager>
|
#include <QtNetwork/QNetworkAccessManager>
|
||||||
|
|
||||||
@ -20,35 +21,19 @@ class SpkStore : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static SpkStore *Instance;
|
static SpkStore *Instance;
|
||||||
|
QSettings *mCfg;
|
||||||
SpkStore(bool aCli, QString &aLogPath);
|
SpkStore(bool aCli, QString &aLogPath);
|
||||||
~SpkStore();
|
~SpkStore();
|
||||||
|
|
||||||
SpkMainWindow* GetRootWindow() { return mMainWindow; }
|
SpkMainWindow* GetRootWindow() { return mMainWindow; }
|
||||||
|
|
||||||
|
void SetApiResuestUrl(QString aUrlStr) { mApiRequestUrl = aUrlStr; }
|
||||||
|
QString GetApiRequestUrl() { return mApiRequestUrl; }
|
||||||
|
QNetworkReply *SendApiRequest(QString path, QJsonDocument param = QJsonDocument());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SpkLogger *mLogger;
|
SpkLogger *mLogger;
|
||||||
SpkMainWindow *mMainWindow = nullptr;
|
SpkMainWindow *mMainWindow = nullptr;
|
||||||
|
|
||||||
QNetworkAccessManager *mNetMgr = nullptr;
|
QNetworkAccessManager *mNetMgr = nullptr;
|
||||||
|
QString mDistroName, mApiRequestUrl, mUserAgentStr;
|
||||||
// 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;
|
|
||||||
};
|
};
|
||||||
|
|||||||
25
inc/spkutils.h
Normal file
25
inc/spkutils.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QString>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
|
||||||
|
#include "spkstore.h"
|
||||||
|
#include "spklogging.h"
|
||||||
|
|
||||||
|
#define STORE SpkStore::Instance
|
||||||
|
#define CFG (SpkStore::Instance->mCfg)
|
||||||
|
|
||||||
|
namespace SpkUtils
|
||||||
|
{
|
||||||
|
QString GetDistroName();
|
||||||
|
|
||||||
|
void VerifySingleRequest(QPointer<QNetworkReply> aReply);
|
||||||
|
|
||||||
|
void DeleteReplyLater(QNetworkReply *aReply);
|
||||||
|
|
||||||
|
bool VerifyReplyJson(QNetworkReply *aReply, QJsonValue& aRetDoc);
|
||||||
|
}
|
||||||
3
resource/default_config
Normal file
3
resource/default_config
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
[Apis]
|
||||||
|
MasterApiUrl=https://store.deepinos.org/api
|
||||||
@ -4,6 +4,7 @@
|
|||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/info">
|
<qresource prefix="/info">
|
||||||
<file>lipsum.txt</file>
|
<file>lipsum.txt</file>
|
||||||
|
<file>default_config</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>icons/spark-store.svg</file>
|
<file>icons/spark-store.svg</file>
|
||||||
|
|||||||
@ -96,12 +96,12 @@ void SpkLogger::Error(QString message, const bool pop)
|
|||||||
// .arg(message));
|
// .arg(message));
|
||||||
// msgbox.exec(); // I don't know whether we need to show it non-modal.
|
// 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"
|
SpkMsgBox::StaticExec(QObject::tr("Spark Store has encountered an error.\n"
|
||||||
"Parts of the experience is expected to be broken.\n\n"
|
"Parts of the experience is expected to be broken.\n\n"),
|
||||||
"Details:\n%1"),
|
|
||||||
QObject::tr("Spark Store Error"),
|
QObject::tr("Spark Store Error"),
|
||||||
QMessageBox::Critical,
|
QMessageBox::Critical,
|
||||||
QMessageBox::Ok,
|
QMessageBox::Ok,
|
||||||
message);
|
message,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,3 +122,8 @@ void SpkLogger::Critical(QString message)
|
|||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpkLogger::Notify(QString message)
|
||||||
|
{
|
||||||
|
Q_UNUSED(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
|
|
||||||
#include <spkui_general.h>
|
#include <spkui_general.h>
|
||||||
#include "dtk/spkdtkplugin.h"
|
|
||||||
#include <QPluginLoader>
|
#include <QPluginLoader>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QtNetwork/QNetworkProxy>
|
||||||
|
#include "dtk/spkdtkplugin.h"
|
||||||
|
#include "gitver.h"
|
||||||
#include "spkstore.h"
|
#include "spkstore.h"
|
||||||
|
#include "spkutils.h"
|
||||||
|
|
||||||
SpkStore *SpkStore::Instance = nullptr;
|
SpkStore *SpkStore::Instance = nullptr;
|
||||||
|
static void InstallDefaultConfigs();
|
||||||
|
|
||||||
SpkStore::SpkStore(bool aCli, QString &aLogPath)
|
SpkStore::SpkStore(bool aCli, QString &aLogPath)
|
||||||
{
|
{
|
||||||
@ -17,8 +21,27 @@ SpkStore::SpkStore(bool aCli, QString &aLogPath)
|
|||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
// Finish all essential initialization after 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 = 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.
|
// Finish all essential initialization before this.
|
||||||
if(aCli)
|
if(aCli)
|
||||||
@ -36,3 +59,17 @@ SpkStore::~SpkStore()
|
|||||||
delete mMainWindow;
|
delete mMainWindow;
|
||||||
delete mLogger;
|
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
|
||||||
|
}
|
||||||
|
|||||||
78
src/spkutils.cpp
Normal file
78
src/spkutils.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include "spkutils.h"
|
||||||
|
|
||||||
|
void SpkUtils::VerifySingleRequest(QPointer<QNetworkReply> 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);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user