Improve Features

Support downloading files from website directly;
Show DSpinner before webpage loading progress finished.
This commit is contained in:
忘记、过去 2020-11-28 04:14:04 +08:00
parent 9c8b2fdd94
commit 4a753259d3
12 changed files with 166 additions and 152 deletions

@ -2,7 +2,6 @@
#define GLOBALDEFINE_H #define GLOBALDEFINE_H
#include <QObject> #include <QObject>
#include <QUrl>
#define DEFAULT_TITLE QObject::tr("SparkWebAppRuntime") #define DEFAULT_TITLE QObject::tr("SparkWebAppRuntime")
#define DEFAULT_URL QString("qrc:/help/help.html") #define DEFAULT_URL QString("qrc:/help/help.html")

@ -46,7 +46,7 @@ int main(int argc, char *argv[])
.arg(QObject::tr("Presented By Spark developers # HadesStudio")); .arg(QObject::tr("Presented By Spark developers # HadesStudio"));
dialog->setDescription(szDefaultDesc); dialog->setDescription(szDefaultDesc);
// WebsiteName // WebsiteName
dialog->setWebsiteName("The Spark Project"); dialog->setWebsiteName("Spark Project");
// WebsiteLink // WebsiteLink
dialog->setWebsiteLink("https://gitee.com/deepin-community-store/"); dialog->setWebsiteLink("https://gitee.com/deepin-community-store/");
// License // License

@ -20,7 +20,7 @@ MainWindow::MainWindow(QString szTitle,
: DMainWindow(parent) : DMainWindow(parent)
, m_widget(new Widget(szUrl)) , m_widget(new Widget(szUrl))
, m_dialog(dialog) , m_dialog(dialog)
, btnBackward(new DToolButton(titlebar())) , btnBack(new DToolButton(titlebar()))
, btnForward(new DToolButton(titlebar())) , btnForward(new DToolButton(titlebar()))
, btnRefresh(new DToolButton(titlebar())) , btnRefresh(new DToolButton(titlebar()))
, m_menu(new QMenu) , m_menu(new QMenu)
@ -41,14 +41,14 @@ MainWindow::MainWindow(QString szTitle,
titlebar()->setTitle(szTitle); titlebar()->setTitle(szTitle);
titlebar()->setIcon(QIcon(":/images/spark-webapp-runtime.svg")); titlebar()->setIcon(QIcon(":/images/spark-webapp-runtime.svg"));
btnBackward->setIcon(QIcon(":/images/go-previous-24.svg")); btnBack->setIcon(QIcon(":/images/go-previous-24.svg"));
btnBackward->setIconSize(QSize(36, 36)); btnBack->setIconSize(QSize(36, 36));
btnForward->setIcon(QIcon(":/images/go-next-24.svg")); btnForward->setIcon(QIcon(":/images/go-next-24.svg"));
btnForward->setIconSize(QSize(36, 36)); btnForward->setIconSize(QSize(36, 36));
btnRefresh->setIcon(QIcon(":/images/view-refresh.svg")); btnRefresh->setIcon(QIcon(":/images/view-refresh.svg"));
btnRefresh->setIconSize(QSize(36, 36)); btnRefresh->setIconSize(QSize(36, 36));
titlebar()->addWidget(btnBackward, Qt::AlignLeft); titlebar()->addWidget(btnBack, Qt::AlignLeft);
titlebar()->addWidget(btnForward, Qt::AlignLeft); titlebar()->addWidget(btnForward, Qt::AlignLeft);
titlebar()->addWidget(btnRefresh, Qt::AlignLeft); titlebar()->addWidget(btnRefresh, Qt::AlignLeft);
@ -65,26 +65,17 @@ MainWindow::MainWindow(QString szTitle,
fixSize(); fixSize();
hideButtons(); hideButtons();
connect(btnBackward, &DToolButton::clicked, this, [&]() connect(btnBack, &DToolButton::clicked, this, [&]()
{ {
if (m_widget) m_widget->goBack();
{
m_widget->goBack();
}
}); });
connect(btnForward, &DToolButton::clicked, this, [&]() connect(btnForward, &DToolButton::clicked, this, [&]()
{ {
if (m_widget) m_widget->goForward();
{
m_widget->goForward();
}
}); });
connect(btnRefresh, &DToolButton::clicked, this, [&]() connect(btnRefresh, &DToolButton::clicked, this, [&]()
{ {
if (m_widget) m_widget->refresh();
{
m_widget->refresh();
}
}); });
connect(m_fixSize, &QAction::triggered, this, [=]() connect(m_fixSize, &QAction::triggered, this, [=]()
@ -100,16 +91,8 @@ MainWindow::MainWindow(QString szTitle,
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
emit sigQuit(); emit sigQuit();
if (m_widget) delete m_widget;
{ delete m_dialog;
delete m_widget;
m_widget = nullptr;
}
if (m_dialog)
{
delete m_dialog;
m_dialog = nullptr;
}
} }
void MainWindow::setIcon(QString szIconPath) void MainWindow::setIcon(QString szIconPath)
@ -144,13 +127,13 @@ void MainWindow::hideButtons()
{ {
if(m_hideButtons->isChecked()) if(m_hideButtons->isChecked())
{ {
btnBackward->hide(); btnBack->hide();
btnForward->hide(); btnForward->hide();
btnRefresh->hide(); btnRefresh->hide();
} }
else else
{ {
btnBackward->show(); btnBack->show();
btnForward->show(); btnForward->show();
btnRefresh->show(); btnRefresh->show();
} }

@ -25,18 +25,13 @@ public:
QWidget *parent = nullptr); QWidget *parent = nullptr);
~MainWindow(); ~MainWindow();
void setIcon(QString); void setIcon(QString szIconPath);
void fixSize();
void hideButtons();
signals:
void sigQuit();
private: private:
Widget *m_widget; Widget *m_widget;
DAboutDialog *m_dialog; DAboutDialog *m_dialog;
DToolButton *btnBackward; DToolButton *btnBack;
DToolButton *btnForward; DToolButton *btnForward;
DToolButton *btnRefresh; DToolButton *btnRefresh;
@ -46,8 +41,14 @@ private:
int m_width, m_height; int m_width, m_height;
void fixSize();
void hideButtons();
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
signals:
void sigQuit();
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

@ -9,24 +9,23 @@ DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11 link_pkgconfig CONFIG += c++11 link_pkgconfig
PKGCONFIG += dtkwidget PKGCONFIG += dtkwidget
SOURCES += main.cpp\ HEADERS += \
httpd.cpp \ mainwindow.h \
mainwindow.cpp \
webenginepage.cpp \
widget.cpp
HEADERS += mainwindow.h \
globaldefine.h \ globaldefine.h \
httpd.h \ httpd.h \
httplib.h \ httplib.h \
webenginepage.h \ webenginepage.h \
widget.h widget.h
FORMS += widget.ui SOURCES += \
main.cpp \
httpd.cpp \
mainwindow.cpp \
webenginepage.cpp \
widget.cpp
RESOURCES += imgs.qrc RESOURCES += \
imgs.qrc
TRANSLATIONS += \ TRANSLATIONS += \
translations/spark-webapp-runtime_zh_CN.ts translations/spark-webapp-runtime_zh_CN.ts

@ -17,102 +17,107 @@
<context> <context>
<name>QObject</name> <name>QObject</name>
<message> <message>
<location filename="../main.cpp" line="49"/> <location filename="../main.cpp" line="46"/>
<source>Presented By Spark developers # HadesStudio</source> <source>Presented By Spark developers # HadesStudio</source>
<translation> @ </translation> <translation> @ </translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="56"/> <location filename="../main.cpp" line="53"/>
<source>This program is open source under GPLv3</source> <source>This program is open source under GPLv3</source>
<translation>GPL第三版开源</translation> <translation>GPL第三版开源</translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="42"/> <location filename="../main.cpp" line="39"/>
<source>Version:</source> <source>Version:</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="60"/> <location filename="../main.cpp" line="57"/>
<source>Description: %1</source> <source>Description: %1</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="65"/> <location filename="../main.cpp" line="62"/>
<source>Enable CommandLineParser. Default is false.</source> <source>Enable CommandLineParser. Default is false.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="69"/> <location filename="../main.cpp" line="66"/>
<source>The Title of Application. Default is %1.</source> <source>The Title of Application. Default is %1.</source>
<translation> %1</translation> <translation> %1</translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="75"/> <location filename="../main.cpp" line="72"/>
<source>The target URL. Default is Blank.</source> <source>The target URL. Default is Blank.</source>
<translation> URL</translation> <translation> URL</translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="81"/> <location filename="../main.cpp" line="78"/>
<source>The Width of Application. Default is %1.</source> <source>The Width of Application. Default is %1.</source>
<translation> %1</translation> <translation> %1</translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="87"/> <location filename="../main.cpp" line="84"/>
<source>The Height of Application. Default is %1.</source> <source>The Height of Application. Default is %1.</source>
<translation> %1</translation> <translation> %1</translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="93"/> <location filename="../main.cpp" line="90"/>
<source>Fix Window Size. Default is false.</source> <source>Fix Window Size. Default is false.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="97"/> <location filename="../main.cpp" line="94"/>
<source>Hide Control Buttons. Default is false.</source> <source>Hide Control Buttons. Default is false.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="101"/> <location filename="../main.cpp" line="98"/>
<source>The ICON of Application.</source> <source>The ICON of Application.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="107"/> <location filename="../main.cpp" line="104"/>
<source>The Description of Application.</source> <source>The Description of Application.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="113"/> <location filename="../main.cpp" line="110"/>
<source>The Configuration file of Application.</source> <source>The Configuration file of Application.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="119"/> <location filename="../main.cpp" line="116"/>
<source>The root path of the program web service.</source> <source>The root path of the program web service.</source>
<translation> WebServer </translation> <translation> WebServer </translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="126"/> <location filename="../main.cpp" line="123"/>
<source>The port number of the program web service.</source> <source>The port number of the program web service.</source>
<translation> WebServer </translation> <translation> WebServer </translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="133"/> <location filename="../main.cpp" line="130"/>
<source>The ssl port number of the program web service.</source> <source>The ssl port number of the program web service.</source>
<translation> WebServer SSL </translation> <translation> WebServer SSL </translation>
</message> </message>
<message> <message>
<location filename="../globaldefine.h" line="7"/> <location filename="../globaldefine.h" line="6"/>
<source>SparkWebAppRuntime</source> <source>SparkWebAppRuntime</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context> <context>
<name>Widget</name> <name>WebEnginePage</name>
<message> <message>
<location filename="../widget.ui" line="14"/> <location filename="../webenginepage.cpp" line="38"/>
<source>MainPage</source> <source>Start downloading...</source>
<translation></translation> <translation>...</translation>
</message>
<message>
<location filename="../webenginepage.cpp" line="48"/>
<source>Download finished!</source>
<translation></translation>
</message> </message>
</context> </context>
</TS> </TS>

@ -1,22 +1,49 @@
#include "webenginepage.h" #include "webenginepage.h"
#include <QWebEngineSettings> #include <QDir>
#include <QDebug>
WebEnginePage::WebEnginePage(QObject *parent) : QWebEnginePage(parent) WebEnginePage::WebEnginePage(QObject *parent)
: QWebEnginePage(parent)
, m_profile(this->profile())
, process(new QProcess)
{ {
connect(m_profile, &QWebEngineProfile::downloadRequested, this, &WebEnginePage::on_download);
} }
QWebEnginePage *WebEnginePage::createWindow(QWebEnginePage::WebWindowType type) QWebEnginePage *WebEnginePage::createWindow(QWebEnginePage::WebWindowType type)
{ {
Q_UNUSED(type) Q_UNUSED(type)
WebEnginePage *page = new WebEnginePage(); WebEnginePage *page = new WebEnginePage();
connect(page, &QWebEnginePage::urlChanged, this, &WebEnginePage::onUrlChanged); connect(page, &QWebEnginePage::urlChanged, this, &WebEnginePage::on_urlChanged);
return page; return page;
} }
void WebEnginePage::onUrlChanged(const QUrl url) void WebEnginePage::on_urlChanged(const QUrl url)
{ {
setUrl(url); setUrl(url);
sender()->deleteLater(); sender()->deleteLater();
} }
void WebEnginePage::on_download(QWebEngineDownloadItem *item)
{
connect(item, &QWebEngineDownloadItem::downloadProgress, this, &WebEnginePage::on_downloadProgress);
connect(item, &QWebEngineDownloadItem::finished, this, &WebEnginePage::on_downloadFinished);
// 无法指定下载位置,原因未知;默认位置为 ~/Downloads
// item->setPath(QDir::homePath() + "/Downloads/");
item->accept();
process->start(QString("notify-send -a spark-webapp-runtime -t 5000 \"%1\"").arg(tr("Start downloading...")));
}
void WebEnginePage::on_downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
qDebug() << "Download Progress:\tbytesReceived: " << bytesReceived << "\tbytesTotal: " << bytesTotal;
}
void WebEnginePage::on_downloadFinished()
{
process->start(QString("notify-send -a spark-webapp-runtime -t 5000 \"%1\"").arg(tr("Download finished!")));
}

@ -2,7 +2,9 @@
#define WEBENGINEPAGE_H #define WEBENGINEPAGE_H
#include <QWebEnginePage> #include <QWebEnginePage>
#include <QWebEngineProfile>
#include <QObject> #include <QObject>
#include <QProcess>
class WebEnginePage : public QWebEnginePage class WebEnginePage : public QWebEnginePage
{ {
@ -12,8 +14,16 @@ public:
protected: protected:
QWebEnginePage *createWindow(WebWindowType type) override; QWebEnginePage *createWindow(WebWindowType type) override;
public slots: private:
void onUrlChanged(const QUrl); QWebEngineProfile *m_profile;
QProcess *process;
private slots:
void on_urlChanged(const QUrl url);
void on_download(QWebEngineDownloadItem *item);
void on_downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void on_downloadFinished();
}; };

@ -1,61 +1,76 @@
#include "widget.h" #include "widget.h"
#include "ui_widget.h"
#include <QWebEngineView> Widget::Widget(QString szUrl, QWidget *parent)
: QWidget(parent)
#include "webenginepage.h" , m_webEngineView(new QWebEngineView)
, m_page(new WebEnginePage)
Widget::Widget(QString szUrl, QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
, m_webEngineView(nullptr)
, m_szUrl(szUrl) , m_szUrl(szUrl)
, m_spinner(new DSpinner)
, main(new QHBoxLayout)
{ {
ui->setupUi(this); m_spinner->setFixedSize(96, 96);
setLayout(main);
m_webEngineView = new QWebEngineView(this);
m_webEngineView->setObjectName(QStringLiteral("webEngineView")); m_webEngineView->setObjectName(QStringLiteral("webEngineView"));
m_webEngineView->setEnabled(true); m_webEngineView->setEnabled(true);
m_webEngineView->setAutoFillBackground(false); m_webEngineView->setAutoFillBackground(false);
m_webEngineView->setProperty("url", QVariant(QUrl(QStringLiteral("")))); m_webEngineView->setZoomFactor(1);
m_webEngineView->setProperty("zoomFactor", QVariant(1)); m_webEngineView->setPage(m_page);
ui->verticalLayout->addWidget(m_webEngineView);
WebEnginePage *page = new WebEnginePage();
m_webEngineView->setPage(page);
m_webEngineView->setUrl(QUrl(nullptr));
if (!m_szUrl.isEmpty()) if (!m_szUrl.isEmpty())
{ {
m_webEngineView->setUrl(QUrl(m_szUrl)); m_webEngineView->setUrl(QUrl(m_szUrl));
} }
connect(m_webEngineView, &QWebEngineView::loadStarted, this, &Widget::on_loadStarted);
connect(m_webEngineView, &QWebEngineView::loadFinished, this, &Widget::on_loadFinished);
} }
Widget::~Widget() Widget::~Widget()
{ {
delete ui;
} }
void Widget::goBack() void Widget::goBack()
{ {
if (m_webEngineView) m_webEngineView->back();
{
m_webEngineView->triggerPageAction(QWebEnginePage::Back);
}
} }
void Widget::goForward() void Widget::goForward()
{ {
if (m_webEngineView) m_webEngineView->forward();
{
m_webEngineView->triggerPageAction(QWebEnginePage::Forward);
}
} }
void Widget::refresh() void Widget::refresh()
{ {
if (m_webEngineView) m_webEngineView->reload();
}
void Widget::clearLayout(QLayout *layout)
{
QLayoutItem *item;
while ((item = layout->takeAt(0)) != nullptr)
{ {
m_webEngineView->triggerPageAction(QWebEnginePage::Reload); delete item;
} }
} }
void Widget::on_loadStarted()
{
clearLayout(main);
main->addStretch();
main->addWidget(m_spinner);
main->addStretch();
m_spinner->start();
}
void Widget::on_loadFinished()
{
m_spinner->stop();
clearLayout(main);
main->addWidget(m_webEngineView);
}

@ -2,20 +2,23 @@
#define WIDGET_H #define WIDGET_H
#include <QWidget> #include <QWidget>
#include <QWebEngineView>
#include <QWebEnginePage>
#include <QWebEngineProfile>
#include <QLayout>
namespace Ui #include <DSpinner>
{
class Widget;
}
class QWebEngineView; #include "webenginepage.h"
DWIDGET_USE_NAMESPACE
class Widget : public QWidget class Widget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Widget(QString szUrl = QString(), QWidget *parent = nullptr); explicit Widget(QString szUrl = nullptr, QWidget *parent = nullptr);
~Widget(); ~Widget();
void goBack(); void goBack();
@ -23,10 +26,18 @@ public:
void refresh(); void refresh();
private: private:
Ui::Widget *ui;
QWebEngineView *m_webEngineView; QWebEngineView *m_webEngineView;
WebEnginePage *m_page;
QString m_szUrl; QString m_szUrl;
DSpinner *m_spinner;
QHBoxLayout *main;
void clearLayout(QLayout *layout);
private slots:
void on_loadStarted();
void on_loadFinished();
}; };
#endif // WIDGET_H #endif // WIDGET_H

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1302</width>
<height>720</height>
</rect>
</property>
<property name="windowTitle">
<string>MainPage</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
<resources/>
<connections/>
</ui>