feat: adapt to Qt6

adapt to Qt6

Log: adapt to Qt6; bump version to 1.7.1
This commit is contained in:
zty199 2024-06-26 15:59:05 +08:00
parent a95e7e1beb
commit 4dd7f7fcec
41 changed files with 357 additions and 359 deletions

17
.gitignore vendored

@ -6,6 +6,7 @@
*.la
*.lai
*.so
*.so.*
*.dll
*.dylib
@ -28,6 +29,8 @@ ui_*.h
*.jsc
Makefile*
*build-*
*.qm
*.prl
# Qt unit tests
target_wrapper.*
@ -42,13 +45,21 @@ target_wrapper.*
# QtCreator CMake
CMakeLists.txt.user*
# Qt qm files
*.qm
# QtCreator 4.8< compilation database
compile_commands.json
# Debian dpkg-buildpackage
# QtCreator local machine specific files for imported projects
*creator.user*
*_qmlcache.qrc
# debian
debian/*.debhelper*
debian/files
debian/*.substvars
debian/spark-webapp-runtime
# Others
build
obj-*
.vscode

36
CMakeLists.txt Normal file

@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.12)
project(spark-webapp-runtime)
add_compile_definitions(PROJECT_NAME="${PROJECT_NAME}")
if(NOT DEFINED VERSION)
set(VERSION 1.0)
endif()
add_compile_definitions(VERSION="${VERSION}")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(AUTOMOC_COMPILER_PREDEFINES ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall")
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "sw_64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mieee")
endif ()
if (NOT ${CMAKE_BUILD_TYPE} MATCHES "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
endif ()
add_compile_definitions(QT_MESSAGELOGCONTEXT)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX /usr)
endif()
include(GNUInstallDirs)
add_subdirectory(src)
add_subdirectory(translations)

7
debian/changelog vendored

@ -1,3 +1,10 @@
spark-webapp-runtime (1.7.1) stable; urgency=medium
* adapt to Qt6
-- shenmo <shenmo@spark-app.store> Wed, 26 Jun 2024 16:15:00 +0800
spark-webapp-runtime (1.7.0-1) stable; urgency=medium
* Transmit web notification to system notification center

33
debian/control vendored

@ -3,37 +3,24 @@ Maintainer: shenmo <shenmo@spark-app.store>
Section: utils
Priority: optional
Build-Depends:
debhelper (>= 9),
debhelper (>= 11),
cmake (>= 3.12),
pkg-config,
qtchooser (>= 55-gc9562a1-1~),
libqt5core5a,
libqt5gui5,
libqt5widgets5,
libqt5concurrent5,
libqt5dbus5,
libqt5svg5-dev,
qtwebengine5-dev,
qttools5-private-dev,
libdtkcore-dev (>= 5.0),
libdtkgui-dev (>= 5.0),
libdtkwidget-dev (>= 5.0)
qt6-base-dev,
qt6-tools-dev,
qt6-webengine-dev,
libdtkcommon-dev,
libdtk6core-dev,
libdtk6gui-dev,
libdtk6widget-dev
Standards-Version: 1.0
Homepage: https://gitee.com/deepin-community-store/spark-web-app-runtime
Package: spark-webapp-runtime
Architecture: any
Depends:${shlibs:Depends}, ${misc:Depends},
libqt5core5a,
libqt5gui5,
libqt5widgets5,
libqt5concurrent5,
libqt5dbus5,
libqt5svg5,
libqt5webenginewidgets5,
libdtkcore5,
libdtkgui5,
libdtkwidget5
Depends:${shlibs:Depends}, ${misc:Depends}
Conflicts: store.spark-app.spark-webapp-runtime
Provides: store.spark-app.spark-webapp-runtime
Replaces: store.spark-app.spark-webapp-runtime

39
debian/rules vendored

@ -1,39 +1,28 @@
#!/usr/bin/make -f
export QT_SELECT=5
include /usr/share/dpkg/default.mk
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
DH_AUTO_ARGS = --parallel --buildsystem=qmake
export QT_SELECT = qt6
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
DEB_CFLAGS ?= $(shell dpkg-buildflags --get CFLAGS)
DEB_CPPFLAGS ?= $(shell dpkg-buildflags --get CPPFLAGS)
DEB_CXXFLAGS ?= $(shell dpkg-buildflags --get CXXFLAGS)
# Uncomment this to turn on verbose mode.
# export DH_VERBOSE=1
#export DH_VERBOSE = 1
%:
dh $@ --parallel
override_dh_auto_clean:
rm -rf $(CURDIR)/build
override_dh_auto_configure:
mkdir -p $(CURDIR)/build
dh_auto_configure -- \
-DVERSION=$(DEB_VERSION_UPSTREAM) \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_FLAGS="$(DEB_CFLAGS) $(DEB_CPPFLAGS)" \
-DCMAKE_CXX_FLAGS="$(DEB_CXXFLAGS) $(DEB_CPPFLAGS)"
dh_auto_configure MAKEFLAGS=-j$(JOBS) -- spark-webapp-runtime.pro \
-spec linux-g++ CONFIG+=qtquickcompiler \
-o $(CURDIR)/build/
override_dh_auto_build:
make -C $(CURDIR)/build -j$(JOBS)
override_dh_auto_install:
make -C $(CURDIR)/build install \
INSTALL_ROOT=$(CURDIR)/debian/spark-webapp-runtime
# Ignore the dpkg-shlibdeps: warning (it uses none of the library's symbols)
# Qt Mutidedia lib will ref to network libraray.
#Ignore the dpkg-shlibdeps: warning (it uses none of the library's symbols)
#Qt Mutidedia lib will ref to network libraray.
override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--warnings=0

@ -1,12 +0,0 @@
#!/bin/sh
case "$1" in
configure)
# Create symbol links for binary files
ln -s -f /opt/durapps/spark-webapp-runtime/bin/spark-webapp-runtime /usr/bin/spark-webapp-runtime
ln -s -f /opt/durapps/spark-webapp-runtime/share/spark-webapp-runtime /usr/share/spark-webapp-runtime
;;
*)
;;
esac

@ -1,7 +0,0 @@
#!/bin/bash
if [ "$1" = "remove" -o "$1" = "purge" ] ; then
# Remove residual symbol links
rm -f /usr/bin/spark-webapp-runtime
rm -rf /usr/share/spark-webapp-runtime
fi

@ -4,10 +4,4 @@ TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += \
spark-webapp-runtime
# Update translation files
CONFIG(release, debug|release) {
system(bash $${PWD}/translate_update.sh)
system(bash $${PWD}/translate_generation.sh)
}
src/spark-webapp-runtime.pro

@ -1,111 +0,0 @@
#include "application.h"
#include "globaldefine.h"
#include <DPlatformWindowHandle>
#include <DAboutDialog>
#include <QStandardPaths>
#include <unistd.h>
Application::Application(int &argc, char **argv)
: DApplication(argc, argv)
{
saveLaunchParams(argc, argv);
loadTranslator();
setAttribute(Qt::AA_UseHighDpiPixmaps);
if (!DPlatformWindowHandle::pluginVersion().isEmpty()) {
setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
}
setApplicationVersion(QString(CURRENT_VER));
setOrganizationName(ORGANIZATION_NAME); // 添加组织名称,和商店主体的文件夹同在 ~/.local/share/spark-union 文件夹下
setApplicationName(APPLICATION_NAME); // 这里不要翻译,否则 ~/.local/share 中文件夹名也会被翻译
setProductName(DEFAULT_TITLE);
setApplicationDisplayName(DEFAULT_TITLE);
setApplicationLicense(" <a href='https://www.gnu.org/licenses/gpl-3.0.html'>GPLv3</a> ");
}
void Application::handleAboutAction()
{
if (aboutDialog()) {
DApplication::handleAboutAction();
return;
}
initAboutDialog();
DApplication::handleAboutAction();
}
QStringList Application::launchParams() const
{
return m_argv;
}
void Application::setMainWindow(MainWindow *window)
{
m_mainWindow = window;
}
MainWindow *Application::mainWindow()
{
return m_mainWindow;
}
void Application::saveLaunchParams(int &argc, char **argv)
{
m_argc = argc;
m_argv.clear();
for (int i = 0; i < m_argc; i++) {
m_argv.append(argv[i]);
}
qDebug() << Q_FUNC_INFO << m_argc << m_argv;
}
void Application::initAboutDialog()
{
// Customized DAboutDialog
DAboutDialog *dialog = new DAboutDialog(activeWindow());
// WindowIcon
dialog->setWindowIcon(QIcon(":/images/spark-webapp-runtime.svg"));
// ProductIcon
dialog->setProductIcon(QIcon(":/images/spark-webapp-runtime.svg"));
// ProductName
dialog->setProductName(productName());
// Version
dialog->setVersion(translate("DAboutDialog", "Version: %1").arg(applicationVersion()));
// CompanyLogo
dialog->setCompanyLogo(QPixmap(":/images/Logo-Spark.png"));
// Description
QString szDefaultDesc = QString("<a href='https://gitee.com/deepin-community-store/spark-web-app-runtime'><span style='font-size:12pt;font-weight:500;'>%1</span></a><br/>"
"<span style='font-size:12pt;'>%2</span>")
.arg(DEFAULT_TITLE)
.arg(QObject::tr("Presented By Spark developers # HadesStudio"));
dialog->setDescription(szDefaultDesc);
// WebsiteName
dialog->setWebsiteName("Spark Project");
// WebsiteLink
dialog->setWebsiteLink("https://gitee.com/deepin-community-store/");
// License
dialog->setLicense(translate("DAboutDialog", "%1 is released under %2").arg(productName()).arg(applicationLicense()));
setAboutDialog(dialog);
connect(aboutDialog(), &DAboutDialog::destroyed, this, [=] {
setAboutDialog(nullptr);
});
dialog->hide();
}
void Application::slotMainWindowClose()
{
if (aboutDialog()) {
aboutDialog()->close();
}
}

36
src/CMakeLists.txt Normal file

@ -0,0 +1,36 @@
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Concurrent WebEngineWidgets)
find_package(Dtk6 REQUIRED COMPONENTS Core Gui Widget)
include(src.cmake)
add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES} ${QRC_FILE})
target_include_directories(${PROJECT_NAME} PUBLIC
Qt6::Core
Qt6::Gui
Qt6::Widgets
Qt6::Concurrent
Qt6::WebEngineWidgets
Dtk6::Core
Dtk6::Gui
Dtk6::Widget
)
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
Qt6::Concurrent
Qt6::WebEngineWidgets
Dtk6::Core
Dtk6::Gui
Dtk6::Widget
)
install(TARGETS ${PROJECT_NAME} DESTINATION /opt/durapps/${PROJECT_NAME}/bin)
file(CREATE_LINK /opt/durapps/${PROJECT_NAME}/bin/${PROJECT_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.link SYMBOLIC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.link DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME ${PROJECT_NAME})
file(CREATE_LINK /opt/durapps/${PROJECT_NAME}/share/${PROJECT_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_datadir.link SYMBOLIC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_datadir.link DESTINATION ${CMAKE_INSTALL_DATADIR} RENAME ${PROJECT_NAME})

84
src/application.cpp Normal file

@ -0,0 +1,84 @@
#include "application.h"
#include "globaldefine.h"
#include <DPlatformWindowHandle>
#include <DAboutDialog>
const QString websiteLinkTemplate = "<a href='%1' style='text-decoration: none; color: rgba(0,129,255,0.9);'>%2</a>";
Application::Application(int &argc, char **argv)
: DApplication(argc, argv)
{
saveLaunchParams(argc, argv);
loadTranslator();
if (!DPlatformWindowHandle::pluginVersion().isEmpty()) {
setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
}
setOrganizationName(ORGANIZATION_NAME); // 添加组织名称,和商店主体的文件夹同在 ~/.local/share/spark-union 文件夹下
setApplicationName(PROJECT_NAME); // 这里不要翻译,否则 ~/.local/share 中文件夹名也会被翻译
setApplicationVersion(VERSION);
setApplicationDisplayName(DEFAULT_TITLE);
setWindowIcon(QIcon(":/images/spark-webapp-runtime.svg"));
setProductIcon(QIcon(":/images/spark-webapp-runtime.svg"));
setProductName(websiteLinkTemplate.arg("https://gitee.com/deepin-community-store/spark-web-app-runtime", DEFAULT_TITLE));
setApplicationDescription(QObject::tr("Presented By Spark developers # HadesStudio"));
setApplicationLicense(websiteLinkTemplate.arg("https://gitee.com/spark-store-project/spark-web-app-runtime/blob/master/LICENSE", "GPLv3"));
}
void Application::triggerAboutAction()
{
handleAboutAction();
}
QStringList Application::launchParams() const
{
return m_argv;
}
void Application::setMainWindow(MainWindow *window)
{
m_mainWindow = window;
}
MainWindow *Application::mainWindow()
{
return m_mainWindow;
}
void Application::handleAboutAction()
{
DApplication::handleAboutAction();
DAboutDialog *dialog = aboutDialog();
if (dialog) {
// CompanyLogo
dialog->setCompanyLogo(QPixmap(":/images/Logo-Spark.png"));
// WebsiteName
dialog->setWebsiteName("Spark Project");
// WebsiteLink
dialog->setWebsiteLink("https://gitee.com/deepin-community-store/");
}
}
void Application::saveLaunchParams(int &argc, char **argv)
{
m_argc = argc;
m_argv.clear();
for (int i = 0; i < m_argc; i++) {
m_argv.append(argv[i]);
}
qDebug() << Q_FUNC_INFO << m_argc << m_argv;
}
void Application::slotMainWindowClose()
{
if (aboutDialog()) {
aboutDialog()->close();
}
}

@ -13,16 +13,18 @@ class Application : public DApplication
public:
Application(int &argc, char **argv);
void handleAboutAction() override;
void triggerAboutAction();
QStringList launchParams() const;
void setMainWindow(MainWindow *window);
MainWindow *mainWindow();
protected:
void handleAboutAction() override;
private:
void saveLaunchParams(int &argc, char **argv);
void initAboutDialog();
signals:
void sigQuit();

@ -4,7 +4,6 @@
#include <QObject>
#define DEFAULT_TITLE QObject::tr("SparkWebAppRuntime")
#define APPLICATION_NAME QString("spark-webapp-runtime")
#define ORGANIZATION_NAME QString("spark-union")
#define DEFAULT_URL QString("qrc:/help/help.html")
#define DEFAULT_WIDTH (1024)
@ -18,6 +17,4 @@
#define DEFAULT_PORT 0
#define DEFAULT_GPU 1
#define CURRENT_VER QString("1.7.0")
#endif // GLOBALDEFINE_H

@ -8,7 +8,6 @@
#include "httpd.h"
#include <DSysInfo>
#include <DApplicationSettings>
#include <QCommandLineParser>
#include <QCommandLineOption>
@ -19,27 +18,15 @@
int main(int argc, char *argv[])
{
if (!QString(qgetenv("XDG_CURRENT_DESKTOP")).toLower().startsWith("deepin")) {
qputenv("XDG_CURRENT_DESKTOP", "Deepin");
}
// 龙芯机器配置,使得 DApplication 能正确加载 QTWEBENGINE
qputenv("DTK_FORCE_RASTER_WIDGETS", "FALSE");
// qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--disable-features=UseModernMediaControls");
// qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--disable-web-security");
#ifdef __sw_64__
#if defined __sw_64__ || __loongarch__
qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--no-sandbox");
#endif
if (!Dtk::Core::DSysInfo::isDDE()) {
#ifndef DSTORE_NO_DXCBs
DApplication::loadDXcbPlugin();
#endif
}
// 开启 HiDPI 缩放支持
DApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
// 强制使用 DTK 平台插件
int fakeArgc = argc + 2;
QVector<char *> fakeArgv(fakeArgc);
@ -51,9 +38,6 @@ int main(int argc, char *argv[])
}
Application a(fakeArgc, fakeArgv.data());
// 保存 DTK 主题
DApplicationSettings settings;
// 解析命令行启动参数
QCommandLineParser parser;
@ -180,10 +164,7 @@ int main(int argc, char *argv[])
#if SSL_SERVER
quint16 u16sslPort = 0;
#endif
QString szDefaultDesc = QString("<a href='https://gitee.com/deepin-community-store/spark-web-app-runtime'><span style='font-size:12pt;font-weight:500;'>%1</span></a><br/>"
"<span style='font-size:12pt;'>%2</span>")
.arg(DEFAULT_TITLE)
.arg(QObject::tr("Presented By Spark developers # HadesStudio"));
QString szDefaultDesc = QObject::tr("Presented By Spark developers # HadesStudio");
// 解析可能存在的配置文件
QString szCfgFile = DEFAULT_CFG;

@ -3,6 +3,7 @@
#include "webengineview.h"
#include "webenginepage.h"
#include <DPlatformWindowHandle>
#include <DLog>
#include <DWidgetUtil>
#include <DTitlebar>
@ -50,8 +51,8 @@ MainWindow::MainWindow(QString szTitle,
, m_clearCache(new QAction(QObject::tr("Clear Cache"), this))
, t_menu(new QMenu(this))
, t_show(new QAction(QObject::tr("Show MainWindow"), this))
, t_about(new QAction(qApp->translate("TitleBarMenu", "About"), this))
, t_exit(new QAction(qApp->translate("TitleBarMenu", "Exit"), this))
, t_about(new QAction(qApp->translate("TitleBarMenu", QString("About").toUtf8().data()), this))
, t_exit(new QAction(qApp->translate("TitleBarMenu", QString("Exit").toUtf8().data()), this))
, downloadMessage(new DFloatingMessage(DFloatingMessage::ResidentType, this))
, downloadProgressWidget(new QWidget(downloadMessage))
, progressBarLayout(new QHBoxLayout(downloadProgressWidget))
@ -73,9 +74,22 @@ MainWindow::~MainWindow()
{
}
bool MainWindow::event(QEvent *event)
{
/**
* @bug QWebEngineView in Qt6 will recreate window handle
* @ref https://github.com/linuxdeepin/deepin-deepinid-client/commit/2a305926a9047c699cf4d12e3e64aae17e8c367b
*/
if (event->type() == QEvent::WinIdChange) {
DPlatformWindowHandle handle(this);
}
return DMainWindow::event(event);
}
void MainWindow::setIcon(QString szIconPath)
{
if (!QFileInfo(szIconPath).exists()) {
if (!QFile::exists(szIconPath)) {
return;
}
@ -83,19 +97,13 @@ void MainWindow::setIcon(QString szIconPath)
setWindowIcon(QIcon(szIconPath));
m_tray->setIcon(QIcon(szIconPath));
DAboutDialog *aboutDialog = qobject_cast<Application *>(qApp)->aboutDialog();
if (aboutDialog) {
aboutDialog->setWindowIcon(QIcon::fromTheme(szIconPath));
aboutDialog->setProductIcon(QIcon::fromTheme(szIconPath));
}
qApp->setWindowIcon(QIcon::fromTheme(szIconPath));
qApp->setProductIcon(QIcon::fromTheme(szIconPath));
}
void MainWindow::setDescription(const QString &desc)
{
DAboutDialog *aboutDialog = qobject_cast<Application *>(qApp)->aboutDialog();
if (aboutDialog) {
aboutDialog->setDescription(desc);
}
qApp->setApplicationDescription(desc);
}
QString MainWindow::title() const
@ -156,6 +164,7 @@ void MainWindow::initLog()
DLogManager::setlogFilePath(tmpDir() + "/" + "log");
DLogManager::registerFileAppender();
DLogManager::registerConsoleAppender();
DLogManager::registerJournalAppender();
}
void MainWindow::initTmpDir()
@ -242,7 +251,7 @@ void MainWindow::initDownloadProgressBar()
btnResume->setFixedSize(80, 32);
btnCancel->setFixedSize(80, 32);
progressBarLayout->setMargin(0);
progressBarLayout->setContentsMargins(0, 0, 0, 0);
progressBarLayout->setSpacing(0);
progressBarLayout->setAlignment(Qt::AlignCenter);
progressBarLayout->addWidget(downloadProgressBar);
@ -251,7 +260,7 @@ void MainWindow::initDownloadProgressBar()
progressBarLayout->addWidget(btnResume);
progressBarLayout->addWidget(btnCancel);
downloadMessage->setIcon(QIcon::fromTheme("deepin-download").pixmap(64, 64));
downloadMessage->setIcon(QIcon::fromTheme("deepin-download"));
downloadMessage->setWidget(downloadProgressWidget);
downloadMessage->hide();
}
@ -301,7 +310,7 @@ void MainWindow::initConnections()
fixSize();
});
connect(t_about, &QAction::triggered, this, [=]() {
qobject_cast<Application *>(qApp)->handleAboutAction();
qobject_cast<Application *>(qApp)->triggerAboutAction();
});
connect(t_exit, &QAction::triggered, this, [=]() {
exit(0);
@ -322,14 +331,14 @@ void MainWindow::fullScreen()
m_fixSize->setDisabled(true);
m_menu->update();
showFullScreen();
// DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-information").pixmap(64, 64), QString(QObject::tr("%1Fullscreen Mode")).arg(" "));
// DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-information"), QString(QObject::tr("%1Fullscreen Mode")).arg(" "));
} else {
if (!m_isFixedSize) {
m_fixSize->setDisabled(false); // 命令行参数没有固定窗口大小时,窗口模式下允许手动选择固定窗口大小
}
m_menu->update();
showNormal();
// DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-information").pixmap(64, 64), QString(QObject::tr("%1Windowed Mode")).arg(" "));
// DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-information"), QString(QObject::tr("%1Windowed Mode")).arg(" "));
}
}
@ -382,7 +391,7 @@ QString MainWindow::saveAs(QString fileName)
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/" + fileName);
if (!saveFile.isEmpty()) {
// 判断上层目录是否可写入
if (QFileInfo(QFileInfo(saveFile).absolutePath()).isWritable()) {
if (QFileInfo(QFileInfo(saveFile).absoluteDir().canonicalPath()).isWritable()) {
return saveFile;
} else {
return saveAs(fileName);
@ -412,40 +421,46 @@ void MainWindow::on_trayIconActivated(QSystemTrayIcon::ActivationReason reason)
}
}
void MainWindow::on_downloadStart(QWebEngineDownloadItem *item)
void MainWindow::on_downloadStart(QWebEngineDownloadRequest *request)
{
// 尝试加锁互斥量,禁止同时下载多个文件
if (mutex.tryLock()) {
QString fileName = QFileInfo(item->path()).fileName();
QString fileName = request->suggestedFileName();
QString filePath = saveAs(fileName);
if (filePath.isEmpty()) {
mutex.unlock();
return;
}
item->setPath(filePath);
filePath = QFileInfo(item->path()).absoluteFilePath();
connect(item, &QWebEngineDownloadItem::downloadProgress, this, &MainWindow::on_downloadProgress);
connect(item, &QWebEngineDownloadItem::finished, this, [=]() {
QFileInfo fileInfo(filePath);
fileName = fileInfo.fileName();
QString dirPath = fileInfo.absoluteDir().canonicalPath();
filePath = QDir(dirPath).absoluteFilePath(fileName);
request->setDownloadDirectory(dirPath);
request->setDownloadFileName(fileName);
connect(request, &QWebEngineDownloadRequest::receivedBytesChanged, this, &MainWindow::on_receivedBytesChanged);
connect(request, &QWebEngineDownloadRequest::isFinishedChanged, this, [=]() {
on_downloadFinish(filePath);
});
connect(btnPause, &DPushButton::clicked, this, [=]() {
on_downloadPause(item);
on_downloadPause(request);
});
connect(btnResume, &DPushButton::clicked, this, [=]() {
on_downloadResume(item);
on_downloadResume(request);
});
connect(btnCancel, &DPushButton::clicked, this, [=]() {
on_downloadCancel(item);
on_downloadCancel(request);
});
DFloatingMessage *message = new DFloatingMessage(DFloatingMessage::TransientType);
message->setIcon(QIcon::fromTheme("dialog-information").pixmap(64, 64));
message->setMessage(QString(QObject::tr("%1Start downloading %2")).arg(" ").arg(fileName));
message->setIcon(QIcon::fromTheme("dialog-information"));
message->setMessage(QObject::tr("%1Start downloading %2").arg(" ", fileName));
DMessageManager::instance()->sendMessage(this, message);
item->accept();
request->accept();
// 重置 DownloadProgressBar 状态
isCanceled = false;
@ -453,14 +468,16 @@ void MainWindow::on_downloadStart(QWebEngineDownloadItem *item)
btnPause->show();
this->downloadMessage->show(); // 上一次下载完成后隐藏了进度条,这里要重新显示
} else {
DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-cancel").pixmap(64, 64), QString(QObject::tr("%1Wait for previous download to complete!")).arg(" "));
DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-cancel"), QString(QObject::tr("%1Wait for previous download to complete!")).arg(" "));
}
}
void MainWindow::on_downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
void MainWindow::on_receivedBytesChanged()
{
int value = int(double(bytesReceived) / double(bytesTotal) * 100.0);
downloadProgressBar->setValue(value);
QWebEngineDownloadRequest *request = qobject_cast<QWebEngineDownloadRequest *>(sender());
int value = int(double(request->receivedBytes()) / double(request->totalBytes()) * 100.0);
downloadProgressBar->setValue(qBound(downloadProgressBar->value(), value, 100));
downloadMessage->setMessage(" " + QString::number(value) + "%");
@ -469,6 +486,11 @@ void MainWindow::on_downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
void MainWindow::on_downloadFinish(QString filePath)
{
QWebEngineDownloadRequest *request = qobject_cast<QWebEngineDownloadRequest *>(sender());
if (!request->isFinished()) {
return;
}
mutex.unlock(); // 解锁互斥量,允许下载新文件
downloadMessage->hide();
@ -478,8 +500,8 @@ void MainWindow::on_downloadFinish(QString filePath)
DPushButton *button = new DPushButton(QObject::tr("Open"));
DFloatingMessage *message = new DFloatingMessage(DFloatingMessage::ResidentType);
message->setIcon(QIcon::fromTheme("dialog-ok").pixmap(64, 64));
message->setMessage(QString(" %1 %2 %3").arg(QFileInfo(filePath).fileName()).arg(QObject::tr("download finished.")).arg(QObject::tr("Show in file manager?")));
message->setIcon(QIcon::fromTheme("dialog-ok"));
message->setMessage(QString(" %1 %2 %3").arg(QFileInfo(filePath).fileName(), QObject::tr("download finished."), QObject::tr("Show in file manager?")));
message->setWidget(button);
DMessageManager::instance()->sendMessage(this, message);
@ -491,36 +513,36 @@ void MainWindow::on_downloadFinish(QString filePath)
}
}
void MainWindow::on_downloadPause(QWebEngineDownloadItem *item)
void MainWindow::on_downloadPause(QWebEngineDownloadRequest *request)
{
item->pause();
request->pause();
downloadMessage->setIcon(QIcon::fromTheme("package-download-failed").pixmap(64, 64));
downloadMessage->setIcon(QIcon::fromTheme("package-download-failed"));
btnResume->show();
btnPause->hide();
}
void MainWindow::on_downloadResume(QWebEngineDownloadItem *item)
void MainWindow::on_downloadResume(QWebEngineDownloadRequest *request)
{
item->resume();
request->resume();
downloadMessage->setIcon(QIcon::fromTheme("deepin-download").pixmap(64, 64));
downloadMessage->setIcon(QIcon::fromTheme("deepin-download"));
btnResume->hide();
btnPause->show();
}
void MainWindow::on_downloadCancel(QWebEngineDownloadItem *item)
void MainWindow::on_downloadCancel(QWebEngineDownloadRequest *request)
{
isCanceled = true; // 取消下载
item->cancel();
request->cancel();
mutex.unlock();
downloadMessage->hide();
DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-error").pixmap(64, 64), QString(QObject::tr("%1Download canceled!")).arg(" "));
DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-error"), QString(QObject::tr("%1Download canceled!")).arg(" "));
}
void MainWindow::slotLoadErrorOccurred()
{
DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-warning").pixmap(64, 64), QString(QObject::tr("%1Load error occurred!")).arg(" "));
DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-warning"), QString(QObject::tr("%1Load error occurred!")).arg(" "));
}

@ -32,6 +32,7 @@ public:
bool nHideButtons = false,
QWidget *parent = nullptr);
~MainWindow();
bool event(QEvent *event) override;
void setIcon(QString szIconPath);
void setDescription(const QString &desc);
@ -70,12 +71,12 @@ public slots:
private slots:
void on_trayIconActivated(QSystemTrayIcon::ActivationReason reason);
void on_downloadStart(QWebEngineDownloadItem *item);
void on_downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void on_downloadStart(QWebEngineDownloadRequest *request);
void on_receivedBytesChanged();
void on_downloadFinish(QString filePath);
void on_downloadPause(QWebEngineDownloadItem *item);
void on_downloadResume(QWebEngineDownloadItem *item);
void on_downloadCancel(QWebEngineDownloadItem *item);
void on_downloadPause(QWebEngineDownloadRequest *request);
void on_downloadResume(QWebEngineDownloadRequest *request);
void on_downloadCancel(QWebEngineDownloadRequest *request);
void slotLoadErrorOccurred();

Before

(image error) Size: 17 KiB

After

(image error) Size: 17 KiB

@ -1,4 +1,4 @@
QT += core gui webenginewidgets svg concurrent dbus
QT += core gui concurrent webenginewidgets
greaterThan(QT_MAJOR_VERSION, 5): QT += widgets
@ -6,8 +6,8 @@ TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11 link_pkgconfig
PKGCONFIG += dtkcore dtkgui dtkwidget
CONFIG += c++17 link_pkgconfig
PKGCONFIG += dtk6core dtk6gui dtk6widget
HEADERS += \
mainwindow.h \
@ -31,18 +31,7 @@ SOURCES += \
webengineurlrequestinterceptor.cpp
RESOURCES += \
resources/resources.qrc
resources/resources.qrc
TRANSLATIONS += \
translations/spark-webapp-runtime_zh_CN.ts
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/durapps/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# Rules for deployment
qm.files += translations/*.qm
qm.path = /opt/durapps/$${TARGET}/share/$${TARGET}/translations
INSTALLS += qm
../translations/spark-webapp-runtime_zh_CN.ts

11
src/src.cmake Normal file

@ -0,0 +1,11 @@
# https://cmake.org/cmake/help/v3.12/command/file.html#glob-recurse
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/*.hpp"
)
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
)
qt6_add_resources(QRC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/resources/resources.qrc)

@ -34,7 +34,7 @@ void WebEngineView::handleChromiumFlags()
DGuiApplicationHelper::ColorType themeType = DGuiApplicationHelper::instance()->themeType();
QString env = qgetenv("QTWEBENGINE_CHROMIUM_FLAGS");
QStringList flags = env.split(" ", QString::SkipEmptyParts);
QStringList flags = env.split(" ", Qt::SkipEmptyParts);
/**
* --blink-settings=preferredColorScheme=0 prefers-color-scheme=dark (>= 5.14)

@ -58,7 +58,7 @@ void Widget::initUI()
QWidget *spinnerWidget = new QWidget(this);
QHBoxLayout *spinnerLayout = new QHBoxLayout(spinnerWidget);
spinnerLayout->setMargin(0);
spinnerLayout->setContentsMargins(0, 0, 0, 0);
spinnerLayout->setSpacing(0);
spinnerLayout->setAlignment(Qt::AlignCenter);
spinnerLayout->addStretch();

@ -1,6 +0,0 @@
#!/bin/bash
# this file is used to auto-generate .qm file from .ts file.
cd $(dirname $0)
lrelease ./spark-webapp-runtime/spark-webapp-runtime.pro

@ -1,6 +0,0 @@
#!/bin/bash
# this file is used to auto-update .ts file.
cd $(dirname $0)
lupdate ./spark-webapp-runtime/spark-webapp-runtime.pro -no-obsolete

@ -0,0 +1,19 @@
# Have to disable cleaning for this folder because cmake deletes .ts files upon clean
# Not sure what else wont clean up / dirty workaround of Qt bug
# @ref https://bugreports.qt.io/browse/QTBUG-41736
# @ref https://stackoverflow.com/a/24245615/1917249
set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE)
find_package(Qt6 REQUIRED COMPONENTS LinguistTools)
# Update ts files and release qm files only in Release build
file(GLOB TS_FILES "*.ts")
if (NOT ${CMAKE_BUILD_TYPE} MATCHES "Debug")
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_SOURCE_DIR})
qt6_create_translation(QM_FILES ${CMAKE_SOURCE_DIR}/src ${TS_FILES} OPTIONS -no-obsolete)
# https://stackoverflow.com/questions/70665191/cmake-does-not-generate-ts-files
add_custom_target(${PROJECT_NAME}_translations DEPENDS ${TS_FILES} ${QM_FILES})
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_translations)
endif ()
install(FILES ${QM_FILES} DESTINATION /opt/durapps/${PROJECT_NAME}/share/${PROJECT_NAME}/translations)

@ -1,214 +1,188 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
<name>DAboutDialog</name>
<message>
<location filename="../application.cpp" line="82"/>
<source>Version: %1</source>
<translation>%1</translation>
</message>
<message>
<location filename="../application.cpp" line="98"/>
<source>%1 is released under %2</source>
<translation>%1%2</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../application.cpp" line="90"/>
<location filename="../main.cpp" line="186"/>
<location filename="../src/application.cpp" line="28"/>
<location filename="../src/main.cpp" line="167"/>
<source>Presented By Spark developers # HadesStudio</source>
<translation> @ </translation>
</message>
<message>
<location filename="../main.cpp" line="60"/>
<location filename="../src/main.cpp" line="44"/>
<source>Description: %1</source>
<translation>%1</translation>
</message>
<message>
<location filename="../main.cpp" line="66"/>
<location filename="../src/main.cpp" line="50"/>
<source>Enable CommandLineParser. Default is false.</source>
<translation></translation>
</message>
<message>
<location filename="../main.cpp" line="71"/>
<location filename="../src/main.cpp" line="55"/>
<source>The Title of Application. Default is %1.</source>
<translation> %1</translation>
</message>
<message>
<location filename="../main.cpp" line="78"/>
<location filename="../src/main.cpp" line="62"/>
<source>The target URL. Default is Blank.</source>
<translation> URL</translation>
</message>
<message>
<location filename="../main.cpp" line="85"/>
<location filename="../src/main.cpp" line="69"/>
<source>The Width of Application. Default is %1.</source>
<translation> %1</translation>
</message>
<message>
<location filename="../main.cpp" line="92"/>
<location filename="../src/main.cpp" line="76"/>
<source>The Height of Application. Default is %1.</source>
<translation> %1</translation>
</message>
<message>
<location filename="../main.cpp" line="99"/>
<location filename="../src/main.cpp" line="83"/>
<source>Enable Tray Icon. Default is false.</source>
<translation></translation>
</message>
<message>
<location filename="../main.cpp" line="103"/>
<location filename="../src/main.cpp" line="87"/>
<source>Run in Fullscreen Mode. Default is false.</source>
<translation></translation>
</message>
<message>
<location filename="../main.cpp" line="107"/>
<location filename="../src/main.cpp" line="91"/>
<source>Fix Window Size. Default is false.</source>
<translation></translation>
</message>
<message>
<location filename="../main.cpp" line="111"/>
<location filename="../src/main.cpp" line="95"/>
<source>Hide Control Buttons. Default is false.</source>
<translation></translation>
</message>
<message>
<location filename="../main.cpp" line="116"/>
<location filename="../src/main.cpp" line="100"/>
<source>The ICON of Application.</source>
<translation></translation>
</message>
<message>
<location filename="../main.cpp" line="123"/>
<location filename="../src/main.cpp" line="107"/>
<source>The Description of Application.</source>
<translation></translation>
</message>
<message>
<location filename="../main.cpp" line="130"/>
<location filename="../src/main.cpp" line="114"/>
<source>The Configuration file of Application.</source>
<translation></translation>
</message>
<message>
<location filename="../main.cpp" line="137"/>
<location filename="../src/main.cpp" line="121"/>
<source>The root path of the program web service.</source>
<translation> WebServer </translation>
</message>
<message>
<location filename="../main.cpp" line="144"/>
<location filename="../src/main.cpp" line="128"/>
<source>The port number of the program web service.</source>
<translation> WebServer </translation>
</message>
<message>
<location filename="../main.cpp" line="151"/>
<location filename="../src/main.cpp" line="135"/>
<source>To use GPU instead of CPU to decoding. Default True.</source>
<translation>GPU渲染</translation>
</message>
<message>
<location filename="../main.cpp" line="159"/>
<location filename="../src/main.cpp" line="143"/>
<source>The ssl port number of the program web service.</source>
<translation> WebServer SSL </translation>
</message>
<message>
<location filename="../globaldefine.h" line="6"/>
<location filename="../src/globaldefine.h" line="6"/>
<source>SparkWebAppRuntime</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="47"/>
<location filename="../src/mainwindow.cpp" line="48"/>
<source>Full Screen</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="48"/>
<location filename="../src/mainwindow.cpp" line="49"/>
<source>Fix Size</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="49"/>
<location filename="../src/mainwindow.cpp" line="50"/>
<source>Hide Buttons</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="50"/>
<location filename="../src/mainwindow.cpp" line="51"/>
<source>Clear Cache</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="52"/>
<location filename="../src/mainwindow.cpp" line="53"/>
<source>Show MainWindow</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="59"/>
<location filename="../src/mainwindow.cpp" line="60"/>
<source>Pause</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="60"/>
<location filename="../src/mainwindow.cpp" line="61"/>
<source>Resume</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="61"/>
<location filename="../src/mainwindow.cpp" line="62"/>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="381"/>
<location filename="../src/mainwindow.cpp" line="390"/>
<source>Save As</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="445"/>
<location filename="../src/mainwindow.cpp" line="460"/>
<source>%1Start downloading %2</source>
<translation>%1 %2</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="456"/>
<location filename="../src/mainwindow.cpp" line="471"/>
<source>%1Wait for previous download to complete!</source>
<translation>%1</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="478"/>
<location filename="../src/mainwindow.cpp" line="500"/>
<source>Open</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="482"/>
<location filename="../src/mainwindow.cpp" line="504"/>
<source>download finished.</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="482"/>
<location filename="../src/mainwindow.cpp" line="504"/>
<source>Show in file manager?</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="520"/>
<location filename="../src/mainwindow.cpp" line="542"/>
<source>%1Download canceled!</source>
<translation>%1</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="525"/>
<location filename="../src/mainwindow.cpp" line="547"/>
<source>%1Load error occurred!</source>
<translation>%1</translation>
</message>
<message>
<location filename="../webengineview.cpp" line="79"/>
<location filename="../src/webengineview.cpp" line="82"/>
<source>View</source>
<translation></translation>
</message>
</context>
<context>
<name>TitleBarMenu</name>
<message>
<location filename="../mainwindow.cpp" line="53"/>
<source>About</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="54"/>
<source>Exit</source>
<translation>退</translation>
</message>
</context>
</TS>