修复 加载应用程序信息时随机崩溃

这个问题就是因为在异步操作时直接修改GUI,导致事件发生时GUI与异步加载线程不同步导致程序崩溃。将所有加载操作已移至
SpkAppInfoLoaderThread,在其需要操作GUI时阻塞该工作线程并发射信号让主线程操作GUI,以解决该问题。
This commit is contained in:
RigoLigoRLC 2020-10-09 02:06:28 +08:00
parent 1b56d3ad52
commit 367c8d857c
6 changed files with 413 additions and 86 deletions

View File

@ -18,7 +18,6 @@ image_show::image_show(QWidget *parent) : QWidget(parent)
void image_show::setImage(QPixmap image) void image_show::setImage(QPixmap image)
{ {
QImage screen0; QImage screen0;
screen0=image.toImage(); screen0=image.toImage();
// QPainter painter(&screen0); // QPainter painter(&screen0);

View File

@ -33,14 +33,16 @@ SOURCES += main.cpp\
downloadlist.cpp \ downloadlist.cpp \
image_show.cpp \ image_show.cpp \
big_image.cpp \ big_image.cpp \
progressload.cpp progressload.cpp \
workerthreads.cpp
HEADERS += \ HEADERS += \
widget.h \ widget.h \
downloadlist.h \ downloadlist.h \
image_show.h \ image_show.h \
big_image.h \ big_image.h \
progressload.h progressload.h \
workerthreads.h

View File

@ -57,6 +57,13 @@ Widget::Widget(DBlurEffectWidget *parent) :
connect(ui->menu_download,&DPushButton::clicked,[=](){Widget::chooseLeftMenu(13);}); connect(ui->menu_download,&DPushButton::clicked,[=](){Widget::chooseLeftMenu(13);});
// connect((ui->titlebar)) // connect((ui->titlebar))
connect(&appinfoLoadThread, SIGNAL(requestResetUi()), this, SLOT(sltAppinfoResetUi()), Qt::ConnectionType::BlockingQueuedConnection);
connect(&appinfoLoadThread, &SpkAppInfoLoaderThread::requestSetTags, this, &Widget::sltAppinfoTags, Qt::ConnectionType::BlockingQueuedConnection);
connect(&appinfoLoadThread, &SpkAppInfoLoaderThread::requestSetAppInformation, this, &Widget::sltAppinfoDetails, Qt::ConnectionType::BlockingQueuedConnection);
connect(&appinfoLoadThread, &SpkAppInfoLoaderThread::finishedIconLoad, this, &Widget::sltAppinfoIcon, Qt::ConnectionType::BlockingQueuedConnection);
connect(&appinfoLoadThread, &SpkAppInfoLoaderThread::finishedScreenshotLoad, this, &Widget::sltAppinfoScreenshot, Qt::ConnectionType::BlockingQueuedConnection);
connect(&appinfoLoadThread, &SpkAppInfoLoaderThread::finishAllLoading, this, &Widget::sltAppinfoFinish, Qt::ConnectionType::BlockingQueuedConnection);
// 搜索事件 // 搜索事件
connect(searchEdit,&DSearchEdit::editingFinished,this,[=](){ connect(searchEdit,&DSearchEdit::editingFinished,this,[=](){
QString searchtext=searchEdit->text(); QString searchtext=searchEdit->text();
@ -126,6 +133,9 @@ void Widget::initUI()
ui->icon->setPixmap(QIcon::fromTheme("spark-store").pixmap(36,36)); ui->icon->setPixmap(QIcon::fromTheme("spark-store").pixmap(36,36));
ui->titlebar->setFixedHeight(50); ui->titlebar->setFixedHeight(50);
label_screen << ui->screen_0 << ui->screen_1 << ui->screen_2 << ui->screen_3 << ui->screen_4;
// 初始化分界线 // 初始化分界线
QGraphicsOpacityEffect *opacityEffect_1=new QGraphicsOpacityEffect; QGraphicsOpacityEffect *opacityEffect_1=new QGraphicsOpacityEffect;
opacityEffect_1->setOpacity(0.1); opacityEffect_1->setOpacity(0.1);
@ -201,9 +211,9 @@ void Widget::initConfig()
QSettings readConfig(QDir::homePath()+"/.config/spark-store/config.ini",QSettings::IniFormat); QSettings readConfig(QDir::homePath()+"/.config/spark-store/config.ini",QSettings::IniFormat);
if(readConfig.value("server/choose").toString()!=""){ if(readConfig.value("server/choose").toString()!=""){
ui->comboBox_server->setCurrentText(readConfig.value("server/choose").toString()); ui->comboBox_server->setCurrentText(readConfig.value("server/choose").toString());
serverUrl=readConfig.value("server/choose").toString(); appinfoLoadThread.setServer(serverUrl=readConfig.value("server/choose").toString());
}else { }else {
serverUrl="http://sucdn.jerrywang.top/"; // 默认URL appinfoLoadThread.setServer(serverUrl="http://sucdn.jerrywang.top/"); // 默认URL
} }
configCanSave=true; // 防止触发保存配置信号 configCanSave=true; // 防止触发保存配置信号
menuUrl[0]=serverUrl + "store/#/"; menuUrl[0]=serverUrl + "store/#/";
@ -223,13 +233,13 @@ void Widget::initConfig()
//web控件初始化 //web控件初始化
// ui->webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); //用来激活接受linkClicked信号 // ui->webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); //用来激活接受linkClicked信号
// ui->webView->page()->settings()->setAttribute(QWebSettings::JavascriptEnabled,true); // ui->webView->page()->settings()->setAttribute(QWebSettings::JavascriptEnabled,true);
ui->webfoot->hide(); ui->webfoot->hide();
//初始化首页 //初始化首页
ui->webEngineView->setUrl(menuUrl[0]); ui->webEngineView->setUrl(menuUrl[0]);
// ui->webEngineView->setUrl(menuUrl[1]); // ui->webEngineView->setUrl(menuUrl[1]);
//给下载列表赋值到数组,方便调用 //给下载列表赋值到数组,方便调用
for (int i =0; i<LIST_MAX;i++){ for (int i =0; i<LIST_MAX;i++){
@ -261,7 +271,7 @@ void Widget::setTheme(bool isDark,QColor color)
ui->btn_openDir->setStyleSheet("color:#8B91A1;background-color:#2E2F30;border:0px"); ui->btn_openDir->setStyleSheet("color:#8B91A1;background-color:#2E2F30;border:0px");
ui->webfoot->setStyleSheet("background-color:#252525"); ui->webfoot->setStyleSheet("background-color:#252525");
ui->label->setStyleSheet("background-color:#252525"); ui->label->setStyleSheet("background-color:#252525");
// ui->scrollArea->setStyleSheet("background-color:#252525"); // ui->scrollArea->setStyleSheet("background-color:#252525");
ui->label_show->setStyleSheet("background-color:#252525"); ui->label_show->setStyleSheet("background-color:#252525");
ui->pushButton_return->setIcon(QIcon(":/icons/icons/category_active_dark.svg")); ui->pushButton_return->setIcon(QIcon(":/icons/icons/category_active_dark.svg"));
ui->pushButton_refresh->setIcon(QIcon(":/icons/icons/refresh-page-dark.svg")); ui->pushButton_refresh->setIcon(QIcon(":/icons/icons/refresh-page-dark.svg"));
@ -272,7 +282,7 @@ void Widget::setTheme(bool isDark,QColor color)
ui->webfoot->setStyleSheet("background-color:#FFFFFF"); ui->webfoot->setStyleSheet("background-color:#FFFFFF");
ui->btn_openDir->setStyleSheet("color:#505050;background-color:#FBFBFB;border:0px"); ui->btn_openDir->setStyleSheet("color:#505050;background-color:#FBFBFB;border:0px");
ui->label->setStyleSheet("background-color:#FFFFFF"); ui->label->setStyleSheet("background-color:#FFFFFF");
// ui->scrollArea->setStyleSheet("background-color:#F8F8F8"); // ui->scrollArea->setStyleSheet("background-color:#F8F8F8");
ui->label_show->setStyleSheet("background-color:#F8F8F8"); ui->label_show->setStyleSheet("background-color:#F8F8F8");
ui->pushButton_return->setIcon(QIcon(":/icons/icons/category_active.svg")); ui->pushButton_return->setIcon(QIcon(":/icons/icons/category_active.svg"));
ui->pushButton_refresh->setIcon(QIcon(":/icons/icons/refresh-page.svg")); ui->pushButton_refresh->setIcon(QIcon(":/icons/icons/refresh-page.svg"));
@ -288,23 +298,23 @@ void Widget::setTheme(bool isDark,QColor color)
DTitlebar* Widget::getTitlebar() DTitlebar* Widget::getTitlebar()
{ {
return ui->titlebar; return ui->titlebar;
} }
void Widget::sendNotification(const QString &message, const int msTimeout, const QString &icon) void Widget::sendNotification(const QString &message, const int msTimeout, const QString &icon)
{ {
system((QString("notify-send --icon=%1 --expire-time=%2 --app-name=").arg(icon).arg(msTimeout) + system((QString("notify-send --icon=%1 --expire-time=%2 --app-name=").arg(icon).arg(msTimeout) +
tr("Spark\\ Store") + tr("Spark\\ Store") +
" '" + message + "'" " '" + message + "'"
).toUtf8()); ).toUtf8());
} }
void Widget::sendNotification(const char *message, const int msTimeout, const QString &icon) void Widget::sendNotification(const char *message, const int msTimeout, const QString &icon)
{ {
system((QString("notify-send --icon=%1 --expire-time=%2 --app-name=").arg(icon).arg(msTimeout) + system((QString("notify-send --icon=%1 --expire-time=%2 --app-name=").arg(icon).arg(msTimeout) +
tr("Spark\\ Store") + tr("Spark\\ Store") +
" '" + message + "'" " '" + message + "'"
).toUtf8()); ).toUtf8());
} }
void Widget::updateUI() void Widget::updateUI()
@ -477,7 +487,7 @@ int Widget::loadappinfo(QUrl arg1)
get_json.waitForFinished(); get_json.waitForFinished();
if(get_json.exitCode()) if(get_json.exitCode())
{ {
sendNotification(tr("Failed to download app info. Please check internet connection.")); sendNotification(tr("Failed to download app info. Please check internet connection."));
} }
QFile app_json("app.json"); QFile app_json("app.json");
@ -560,25 +570,21 @@ int Widget::loadappinfo(QUrl arg1)
get_json.start("curl -o icon.png "+urladdress+"icon.png"); get_json.start("curl -o icon.png "+urladdress+"icon.png");
get_json.waitForFinished(); get_json.waitForFinished();
if(!get_json.exitCode()) { if(!get_json.exitCode()) {
QPixmap appicon(QString::fromUtf8(TMP_PATH)+"/icon.png"); QPixmap appicon(QString::fromUtf8(TMP_PATH)+"/icon.png");
ui->label_appicon->setPixmap(appicon); ui->label_appicon->setPixmap(appicon);
ui->pushButton_download->setEnabled(true); ui->pushButton_download->setEnabled(true);
ui->pushButton->setEnabled(true); ui->pushButton->setEnabled(true);
ui->pushButton_translate->setEnabled(true); ui->pushButton_translate->setEnabled(true);
ui->pushButton_website->setEnabled(true); ui->pushButton_website->setEnabled(true);
} }
else else
sendNotification(tr("Failed to load application icon.")); sendNotification(tr("Failed to load application icon."));
// 截图展示加载 // 截图展示加载
image_show *label_screen[5]; QList<image_show*> label_screen;
label_screen[0]=ui->screen_0; label_screen << ui->screen_0 << ui->screen_1 << ui->screen_2 << ui->screen_3 << ui->screen_4;
label_screen[1]=ui->screen_1; for (int i = 0; i < 5; i++) {
label_screen[2]=ui->screen_2;
label_screen[3]=ui->screen_3;
label_screen[4]=ui->screen_4;
for (int i=0;i<5;i++) {
QString cmd = "curl -o screen_"+QString::number(i+1)+".png "+urladdress+"screen_"+QString::number(i+1)+".png"; QString cmd = "curl -o screen_"+QString::number(i+1)+".png "+urladdress+"screen_"+QString::number(i+1)+".png";
get_json.terminate(); get_json.terminate();
get_json.start(cmd); get_json.start(cmd);
@ -587,6 +593,7 @@ int Widget::loadappinfo(QUrl arg1)
if(s){ if(s){
label_screen[i]->setImage(screen[i]); label_screen[i]->setImage(screen[i]);
label_screen[i]->show(); label_screen[i]->show();
/*
switch(i){ // 故意为之,为了清除多余截图 switch(i){ // 故意为之,为了清除多余截图
case 0: case 0:
label_screen[1]->hide(); label_screen[1]->hide();
@ -596,7 +603,8 @@ int Widget::loadappinfo(QUrl arg1)
label_screen[3]->hide(); label_screen[3]->hide();
case 3: case 3:
label_screen[4]->hide(); label_screen[4]->hide();
}
}*/
}else{ }else{
QFile::remove("screen_"+QString::number(i+1)+".png"); QFile::remove("screen_"+QString::number(i+1)+".png");
break; break;
@ -691,6 +699,111 @@ void Widget::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes)
} }
} }
void Widget::sltAppinfoResetUi()
{
// 先隐藏详情页负责显示截图的label
ui->screen_0->hide();
ui->screen_1->hide();
ui->screen_2->hide();
ui->screen_3->hide();
ui->screen_4->hide();
ui->label_appicon->clear();
ui->tag_community->hide();
ui->tag_ubuntu->hide();
ui->tag_deepin->hide();
ui->tag_uos->hide();
ui->tag_dtk5->hide();
ui->tag_dwine2->hide();
ui->tag_dwine5->hide();
ui->tag_a2d->hide();
// 重置UI状态
ui->pushButton_uninstall->hide();
ui->pushButton_website->setEnabled(false);
ui->pushButton->setEnabled(false);
ui->pushButton_translate->setEnabled(false);
ui->label_show->setText("Loading...");
ui->label_show->show();
}
void Widget::sltAppinfoTags(QStringList *tagList)
{
foreach (const QString &tag, *tagList) {
if(tag=="community")
ui->tag_community->show();
else if(tag=="ubuntu")
ui->tag_ubuntu->show();
else if(tag=="deepin")
ui->tag_deepin->show();
else if(tag=="uos")
ui->tag_uos->show();
else if(tag=="dtk5")
ui->tag_dtk5->show();
else if(tag=="dwine2")
ui->tag_dwine2->show();
else if(tag=="dwine5")
ui->tag_dwine5->show();
else if(tag=="a2d")
ui->tag_a2d->show();
}
}
void Widget::sltAppinfoDetails(QString *name, QString *details, QString *info,
QString *website, QString *packageName, QUrl *fileUrl,
bool isInstalled)
{
ui->label_appname->setText(appName = *name);
ui->label_appname->show();
ui->label_info->setText(*details);
ui->label_info->show();
ui->label_more->setText(*info);
ui->label_more->show();
pkgName = *packageName;
url = *fileUrl;
appweb = *website;
if(isInstalled){
ui->pushButton_download->setText(tr("Reinstall"));
ui->pushButton_uninstall->show();
}else {
ui->pushButton_download->setText(tr("Install"));
}
}
void Widget::sltAppinfoIcon(QPixmap *icon)
{
ui->label_appicon->setPixmap(*icon);
ui->label_appicon->show();
ui->pushButton_download->setEnabled(true);
ui->pushButton->setEnabled(true);
ui->pushButton_translate->setEnabled(true);
ui->pushButton_website->setEnabled(true);
}
void Widget::sltAppinfoScreenshot(QPixmap *picture, int index)
{
if(picture != nullptr) {
screen[index] = *picture;
label_screen[index]->setImage(*picture);
label_screen[index]->show();
switch(index) { // 故意为之,为了清除多余截图
case 0:
label_screen[1]->hide();
case 1:
label_screen[2]->hide();
case 2:
label_screen[3]->hide();
case 3:
label_screen[4]->hide();
}
}
}
void Widget::sltAppinfoFinish()
{
ui->label_show->setText("");
ui->label_show->hide();
}
void Widget::httpFinished() // 完成下载 void Widget::httpFinished() // 完成下载
{ {
file->flush(); file->flush();
@ -727,6 +840,7 @@ void Widget::on_pushButton_return_clicked()
// chooseLeftMenu(13); // chooseLeftMenu(13);
// return; // return;
// } // }
appinfoLoadThread.requestInterruption();
chooseLeftMenu(nowMenu); chooseLeftMenu(nowMenu);
// if(themeIsDark){ // if(themeIsDark){
// QString darkurl=menuUrl[nowMenu].toString(); // QString darkurl=menuUrl[nowMenu].toString();
@ -746,13 +860,14 @@ void Widget::on_pushButton_return_clicked()
void Widget::on_pushButton_refresh_clicked() void Widget::on_pushButton_refresh_clicked()
{ {
if(ui->stackedWidget->currentIndex() == 2) //如果在详情页面要重新触发UrlChanged if(ui->stackedWidget->currentIndex() == 2) //如果在详情页面要重新触发UrlChanged
emit ui->webEngineView->urlChanged(ui->webEngineView->url()); emit ui->webEngineView->urlChanged(ui->webEngineView->url());
else else
ui->webEngineView->reload(); ui->webEngineView->reload();
} }
void Widget::on_comboBox_server_currentIndexChanged(const QString &arg1) void Widget::on_comboBox_server_currentIndexChanged(const QString &arg1)
{ {
appinfoLoadThread.setServer(arg1); // 服务器信息更新
if(configCanSave){ if(configCanSave){
ui->label_setting1->show(); ui->label_setting1->show();
QSettings *setConfig=new QSettings(QDir::homePath()+"/.config/spark-store/config.ini",QSettings::IniFormat); QSettings *setConfig=new QSettings(QDir::homePath()+"/.config/spark-store/config.ini",QSettings::IniFormat);
@ -785,70 +900,70 @@ void Widget::on_pushButton_updateServer_clicked()
void Widget::on_pushButton_updateApt_clicked() void Widget::on_pushButton_updateApt_clicked()
{ {
QtConcurrent::run([=](){ QtConcurrent::run([=](){
ui->pushButton_updateApt->setEnabled(false); ui->pushButton_updateApt->setEnabled(false);
ui->label_aptserver->setText(tr("Updating, please wait...")); ui->label_aptserver->setText(tr("Updating, please wait..."));
std::fstream sourcesList, policy, update; std::fstream sourcesList, policy, update;
QDir tmpdir("/tmp"); QDir tmpdir("/tmp");
auto tmpPath = QString::fromUtf8(TMP_PATH).toStdString(); auto tmpPath = QString::fromUtf8(TMP_PATH).toStdString();
bool unknownError = true; bool unknownError = true;
tmpdir.mkpath("spark-store"); tmpdir.mkpath("spark-store");
sourcesList.open(tmpPath + "/sparkstore.list", std::ios::out); sourcesList.open(tmpPath + "/sparkstore.list", std::ios::out);
//policy.open(tmpPath + "/sparkstore", std::ios::out); //policy.open(tmpPath + "/sparkstore", std::ios::out);
// 商店已经下架会替换系统库的包优先级policy弃用 // 商店已经下架会替换系统库的包优先级policy弃用
if(sourcesList /*&& policy*/) { if(sourcesList /*&& policy*/) {
auto serverAddr = ui->comboBox_server->currentText(); auto serverAddr = ui->comboBox_server->currentText();
sourcesList << "deb [by-hash=force] "; sourcesList << "deb [by-hash=force] ";
sourcesList << serverAddr.toUtf8().toStdString(); sourcesList << serverAddr.toUtf8().toStdString();
sourcesList << " /"; sourcesList << " /";
sourcesList.close(); sourcesList.close();
/* /*
policy << "Package: *\n" policy << "Package: *\n"
"Pin: origin *" << serverAddr.mid(serverAddr.indexOf('.')).toUtf8().toStdString() << "\n" "Pin: origin *" << serverAddr.mid(serverAddr.indexOf('.')).toUtf8().toStdString() << "\n"
"Pin-Priority: 90"; // 降低星火源的优先级,防止从星火安装已存在的系统包,破坏依赖 "Pin-Priority: 90"; // 降低星火源的优先级,防止从星火安装已存在的系统包,破坏依赖
policy.close(); policy.close();
*/ */
update.open(tmpPath + "/update.sh",std::ios::out); update.open(tmpPath + "/update.sh",std::ios::out);
if(update) { if(update) {
unknownError = false; unknownError = false;
update << "#!/bin/sh\n" update << "#!/bin/sh\n"
"mv " + tmpPath + "/sparkstore.list /etc/apt/sources.list.d/sparkstore.list && " "mv " + tmpPath + "/sparkstore.list /etc/apt/sources.list.d/sparkstore.list && "
// "mv " + tmpPath + "/sparkstore /etc/apt/preferences.d/sparkstore && " // "mv " + tmpPath + "/sparkstore /etc/apt/preferences.d/sparkstore && "
"apt update"; "apt update";
update.close(); update.close();
system(("chmod +x " + tmpPath + "/update.sh").c_str()); system(("chmod +x " + tmpPath + "/update.sh").c_str());
QProcess runupdate; QProcess runupdate;
runupdate.start(QString::fromStdString("pkexec " + tmpPath + "/update.sh")); runupdate.start(QString::fromStdString("pkexec " + tmpPath + "/update.sh"));
runupdate.waitForFinished(); runupdate.waitForFinished();
QString error = runupdate.readAllStandardError(); QString error = runupdate.readAllStandardError();
QStringList everyError = error.split("\n"); QStringList everyError = error.split("\n");
bool haveError = false; bool haveError = false;
for (int i=0; i < everyError.size(); i++) { for (int i=0; i < everyError.size(); i++) {
if(everyError[i].left(2) == "E:") { if(everyError[i].left(2) == "E:") {
haveError = true; haveError = true;
} }
} }
if(!haveError) { if(!haveError) {
ui->label_aptserver->setText("deb [by-hash=force] " + ui->comboBox_server->currentText().toUtf8() + " /"); ui->label_aptserver->setText("deb [by-hash=force] " + ui->comboBox_server->currentText().toUtf8() + " /");
} else { } else {
ui->label_aptserver->setText(tr("Apt has reported an error. Please use apt update in terminal to locate the problem.")); ui->label_aptserver->setText(tr("Apt has reported an error. Please use apt update in terminal to locate the problem."));
} }
} }
} }
if(unknownError) { if(unknownError) {
ui->label_aptserver->setText(tr("Unknown error!")); ui->label_aptserver->setText(tr("Unknown error!"));
} }
ui->pushButton_updateApt->setEnabled(true); ui->pushButton_updateApt->setEnabled(true);
}); });
} }
@ -983,10 +1098,16 @@ void Widget::on_webEngineView_urlChanged(const QUrl &arg1)
ui->pushButton_download->setEnabled(false); ui->pushButton_download->setEnabled(false);
ui->stackedWidget->setCurrentIndex(2); ui->stackedWidget->setCurrentIndex(2);
qDebug()<<"https://demo-one-vert.vercel.app/"+type_name+"/"+pname; qDebug()<<"https://demo-one-vert.vercel.app/"+type_name+"/"+pname;
/*
load.cancel();//打开并发加载线程前关闭正在执行的线程 load.cancel();//打开并发加载线程前关闭正在执行的线程
load = QtConcurrent::run([=](){ load = QtConcurrent::run([=](){
int loadresult = loadappinfo(arg1); int loadresult = loadappinfo(arg1);
}); });
*/
appinfoLoadThread.requestInterruption();
appinfoLoadThread.wait(100);
appinfoLoadThread.setUrl(arg1);
appinfoLoadThread.start();
} }
} }
@ -1009,7 +1130,7 @@ void Widget::on_webEngineView_loadProgress(int progress)
void Widget::on_webEngineView_loadFinished(bool arg1) void Widget::on_webEngineView_loadFinished(bool arg1)
{ {
if(arg1){ if(arg1){
m_loadweb->setValue(0); m_loadweb->setValue(0);
}else { }else {
m_loadweb->setValue(0); m_loadweb->setValue(0);
m_loaderror->show(); m_loaderror->show();

View File

@ -21,6 +21,9 @@
#include <DTitlebar> #include <DTitlebar>
#include <DSearchEdit> #include <DSearchEdit>
#include <progressload.h> #include <progressload.h>
#include "workerthreads.h"
#include "image_show.h"
#define LIST_MAX 99 //一次最多下载数量 #define LIST_MAX 99 //一次最多下载数量
#define TMP_PATH "/tmp/spark-store" #define TMP_PATH "/tmp/spark-store"
@ -56,6 +59,17 @@ private slots:
void httpFinished(); void httpFinished();
void httpReadyRead(); void httpReadyRead();
void updateDataReadProgress(qint64,qint64); void updateDataReadProgress(qint64,qint64);
// SpkAppInfoLoaderThread的槽函数
void sltAppinfoResetUi();
void sltAppinfoTags(QStringList *tagList);
void sltAppinfoDetails(QString *name, QString *details, QString *info,
QString *website, QString *packageName,
QUrl *fileUrl, bool isInstalled);
void sltAppinfoIcon(QPixmap *icon);
void sltAppinfoScreenshot(QPixmap *picture, int index);
void sltAppinfoFinish();
void on_pushButton_download_clicked(); void on_pushButton_download_clicked();
void on_pushButton_return_clicked(); void on_pushButton_return_clicked();
void on_comboBox_server_currentIndexChanged(const QString &arg1); void on_comboBox_server_currentIndexChanged(const QString &arg1);
@ -125,6 +139,9 @@ private:
DSearchEdit *searchEdit=new DSearchEdit; DSearchEdit *searchEdit=new DSearchEdit;
DTitlebar *titlebar; DTitlebar *titlebar;
QList<image_show*> label_screen;
SpkAppInfoLoaderThread appinfoLoadThread;
}; };
#endif // WIDGET_H #endif // WIDGET_H

152
workerthreads.cpp Normal file
View File

@ -0,0 +1,152 @@
#include <QProcess>
#include <QDir>
#include <QFile>
#include <QJsonDocument>
#include "workerthreads.h"
#include "widget.h"
void SpkAppInfoLoaderThread::run()
{
emit requestResetUi();
QProcess get_json;
QString urladdress, deatils, more, packagename, appweb;
QDir dir("/tmp");
bool isInstalled;
dir.mkdir("spark-store");
QDir::setCurrent("/tmp/spark-store");
get_json.start("curl -o app.json " + targetUrl.toString());
if(waitDownload(get_json) == -1)
return;
if(get_json.exitCode())
{
Widget::sendNotification(tr("Failed to download app info. Please check internet connection."));
}
QFile app_json("app.json");
if(app_json.open(QIODevice::ReadOnly)){
// 成功得到json文件
QByteArray json_array = app_json.readAll();
// 将路径转化为相应源的下载路径
urladdress = targetUrl.toString().left(targetUrl.toString().length()-8);
QStringList downloadurl=urladdress.split("/");
QString deburl = serverUrl;
deburl = deburl.left(urladdress.length()-1);
urladdress = "https://cdn.jsdelivr.net/gh/Jerrywang959/jsonpng@master/"; // 使用图片专用服务器请保留这行,删除后将使用源服务器
urladdress = urladdress.left(urladdress.length()-1);
for (int i=3;i<downloadurl.size();i++) {
urladdress+="/"+downloadurl[i];
deburl+="/"+downloadurl[i];
}
// 路径转化完成
QJsonObject json= QJsonDocument::fromJson(json_array).object();
QString appName = json["Name"].toString();
QUrl fileUrl = deburl + json["Filename"].toString();
// 软件信息加载
QString details;
details = tr("PkgName: ") + json["Pkgname"].toString()+"\n";
details += tr("Version: ") + json["Version"].toString()+"\n";
if(json["Author"].toString() != "" && json["Author"].toString() != " "){
details += tr("Author: ") + json["Author"].toString() + "\n";
}
if(json["Website"].toString() != "" && json["Website"].toString() != " "){
details += tr("Official Site: ") + json["Website"].toString() + "\n";
//ui->pushButton_website->show(); move to setinfo slot
appweb=json["Website"].toString();
}
details+=tr("Contributor: ")+json["Contributor"].toString()+"\n";
details+=tr("Update Time: ")+json["Update"].toString()+"\n";
details+=tr("Installed Size: ")+json["Size"].toString()+"\n";
more = json["More"].toString();
QProcess isInstall;
packagename = json["Pkgname"].toString();
isInstall.start("dpkg -s "+json["Pkgname"].toString());
isInstall.waitForFinished();
int error=QString::fromStdString(isInstall.readAllStandardError().toStdString()).length();
if(error==0)
isInstalled = true;
else
isInstalled = false;
emit requestSetAppInformation(&appName, &details, &more, &appweb, &packagename, &fileUrl, isInstalled);
//tag加载
QString tags=json["Tags"].toString();
QStringList tagList=tags.split(";");
emit requestSetTags(&tagList);
// 图标加载
get_json.start("curl -o icon.png "+urladdress+"icon.png");
if(waitDownload(get_json) == -1)
return;
if(!get_json.exitCode()) {
QPixmap appicon("icon.png");
emit finishedIconLoad(&appicon);
}
else
Widget::sendNotification(tr("Failed to load application icon."));
// 截图展示加载
QPixmap screenshotCache[5];
for (int i = 0; i < 5; i++) {
QString cmd = "curl -o screen_"+QString::number(i+1)+".png "+urladdress+"screen_"+QString::number(i+1)+".png";
get_json.start(cmd);
if(waitDownload(get_json) == -1)
return;
bool s = screenshotCache[i].load(QString(TMP_PATH) + "/screen_"+QString::number(i+1)+".png");
if(s){
emit finishedScreenshotLoad(&screenshotCache[i], i);
}else{
emit finishedScreenshotLoad(nullptr, i);
QFile::remove("screen_"+QString::number(i+1)+".png");
break;
}
}
emit finishAllLoading();
}
}
void SpkAppInfoLoaderThread::setUrl(const QUrl &url)
{
targetUrl = url;
}
void SpkAppInfoLoaderThread::setServer(const QString &server)
{
serverUrl = server;
}
void SpkAppInfoLoaderThread::downloadFinished(int exitcode, QProcess::ExitStatus status)
{
Q_UNUSED(exitcode);
Q_UNUSED(status);
qDebug() << "Finish one download";
finishedDownload = true;
}
int SpkAppInfoLoaderThread::waitDownload(QProcess& downloader)
{
while(!downloader.waitForFinished(100))
{
if(downloader.state() == QProcess::NotRunning)
return -1;
if(this->isInterruptionRequested())
{
downloader.terminate();
downloader.waitForFinished(-1);
qDebug() << "Appinfo loader thread was forcefully terminated";
return -1;
}
}
return 0;
}

36
workerthreads.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef WORKERTHREADS_H
#define WORKERTHREADS_H
#include <QThread>
#include <QPixmap>
#include <QUrl>
#include <QProcess>
class SpkAppInfoLoaderThread Q_DECL_FINAL : public QThread
{
Q_OBJECT
public:
//explicit SpkAppInfoLoaderThread() = default;
void run() Q_DECL_OVERRIDE;
public slots:
void setUrl(const QUrl &url);
void setServer(const QString &server);
void downloadFinished(int exitcode, QProcess::ExitStatus status);
signals:
void requestResetUi();
void requestSetTags(QStringList *tagList);
void requestSetAppInformation(QString *name, QString *details, QString *info,
QString *website, QString *packageName,
QUrl *fileUrl, bool isInstalled);
void finishedIconLoad(QPixmap *icon);
void finishedScreenshotLoad(QPixmap *icon, int index); // 该信号必须以BlockingQueued方式连接
void finishAllLoading(); // 该信号必须以BlockingQueued方式连接
private:
int waitDownload(QProcess& downloader);
QUrl targetUrl;
QString serverUrl;
bool finishedDownload = false;
int downloaderRetval = 0;
};
#endif // WORKERTHREADS_H