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 *.la
*.lai *.lai
*.so *.so
*.so.*
*.dll *.dll
*.dylib *.dylib
@ -28,6 +29,8 @@ ui_*.h
*.jsc *.jsc
Makefile* Makefile*
*build-* *build-*
*.qm
*.prl
# Qt unit tests # Qt unit tests
target_wrapper.* target_wrapper.*
@ -42,13 +45,21 @@ target_wrapper.*
# QtCreator CMake # QtCreator CMake
CMakeLists.txt.user* CMakeLists.txt.user*
# Qt qm files # QtCreator 4.8< compilation database
*.qm compile_commands.json
# Debian dpkg-buildpackage # QtCreator local machine specific files for imported projects
*creator.user*
*_qmlcache.qrc
# debian
debian/*.debhelper* debian/*.debhelper*
debian/files debian/files
debian/*.substvars debian/*.substvars
debian/spark-webapp-runtime debian/spark-webapp-runtime
# Others
build 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 spark-webapp-runtime (1.7.0-1) stable; urgency=medium
* Transmit web notification to system notification center * Transmit web notification to system notification center

33
debian/control vendored

@ -3,37 +3,24 @@ Maintainer: shenmo <shenmo@spark-app.store>
Section: utils Section: utils
Priority: optional Priority: optional
Build-Depends: Build-Depends:
debhelper (>= 9), debhelper (>= 11),
cmake (>= 3.12),
pkg-config, pkg-config,
qtchooser (>= 55-gc9562a1-1~), qtchooser (>= 55-gc9562a1-1~),
libqt5core5a, qt6-base-dev,
libqt5gui5, qt6-tools-dev,
libqt5widgets5, qt6-webengine-dev,
libqt5concurrent5, libdtkcommon-dev,
libqt5dbus5, libdtk6core-dev,
libqt5svg5-dev, libdtk6gui-dev,
qtwebengine5-dev, libdtk6widget-dev
qttools5-private-dev,
libdtkcore-dev (>= 5.0),
libdtkgui-dev (>= 5.0),
libdtkwidget-dev (>= 5.0)
Standards-Version: 1.0 Standards-Version: 1.0
Homepage: https://gitee.com/deepin-community-store/spark-web-app-runtime Homepage: https://gitee.com/deepin-community-store/spark-web-app-runtime
Package: spark-webapp-runtime Package: spark-webapp-runtime
Architecture: any Architecture: any
Depends:${shlibs:Depends}, ${misc:Depends}, Depends:${shlibs:Depends}, ${misc:Depends}
libqt5core5a,
libqt5gui5,
libqt5widgets5,
libqt5concurrent5,
libqt5dbus5,
libqt5svg5,
libqt5webenginewidgets5,
libdtkcore5,
libdtkgui5,
libdtkwidget5
Conflicts: store.spark-app.spark-webapp-runtime Conflicts: store.spark-app.spark-webapp-runtime
Provides: store.spark-app.spark-webapp-runtime Provides: store.spark-app.spark-webapp-runtime
Replaces: 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 #!/usr/bin/make -f
export QT_SELECT=5
include /usr/share/dpkg/default.mk include /usr/share/dpkg/default.mk
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH) export QT_SELECT = qt6
DH_AUTO_ARGS = --parallel --buildsystem=qmake 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. # Uncomment this to turn on verbose mode.
# export DH_VERBOSE=1 #export DH_VERBOSE = 1
%: %:
dh $@ --parallel dh $@ --parallel
override_dh_auto_clean:
rm -rf $(CURDIR)/build
override_dh_auto_configure: 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 \ #Ignore the dpkg-shlibdeps: warning (it uses none of the library's symbols)
-spec linux-g++ CONFIG+=qtquickcompiler \ #Qt Mutidedia lib will ref to network libraray.
-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.
override_dh_shlibdeps: override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--warnings=0 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 CONFIG += ordered
SUBDIRS += \ SUBDIRS += \
spark-webapp-runtime src/spark-webapp-runtime.pro
# Update translation files
CONFIG(release, debug|release) {
system(bash $${PWD}/translate_update.sh)
system(bash $${PWD}/translate_generation.sh)
}

@ -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: public:
Application(int &argc, char **argv); Application(int &argc, char **argv);
void handleAboutAction() override; void triggerAboutAction();
QStringList launchParams() const; QStringList launchParams() const;
void setMainWindow(MainWindow *window); void setMainWindow(MainWindow *window);
MainWindow *mainWindow(); MainWindow *mainWindow();
protected:
void handleAboutAction() override;
private: private:
void saveLaunchParams(int &argc, char **argv); void saveLaunchParams(int &argc, char **argv);
void initAboutDialog();
signals: signals:
void sigQuit(); void sigQuit();

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

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

@ -3,6 +3,7 @@
#include "webengineview.h" #include "webengineview.h"
#include "webenginepage.h" #include "webenginepage.h"
#include <DPlatformWindowHandle>
#include <DLog> #include <DLog>
#include <DWidgetUtil> #include <DWidgetUtil>
#include <DTitlebar> #include <DTitlebar>
@ -50,8 +51,8 @@ MainWindow::MainWindow(QString szTitle,
, m_clearCache(new QAction(QObject::tr("Clear Cache"), this)) , m_clearCache(new QAction(QObject::tr("Clear Cache"), this))
, t_menu(new QMenu(this)) , t_menu(new QMenu(this))
, t_show(new QAction(QObject::tr("Show MainWindow"), this)) , t_show(new QAction(QObject::tr("Show MainWindow"), this))
, t_about(new QAction(qApp->translate("TitleBarMenu", "About"), this)) , t_about(new QAction(qApp->translate("TitleBarMenu", QString("About").toUtf8().data()), this))
, t_exit(new QAction(qApp->translate("TitleBarMenu", "Exit"), this)) , t_exit(new QAction(qApp->translate("TitleBarMenu", QString("Exit").toUtf8().data()), this))
, downloadMessage(new DFloatingMessage(DFloatingMessage::ResidentType, this)) , downloadMessage(new DFloatingMessage(DFloatingMessage::ResidentType, this))
, downloadProgressWidget(new QWidget(downloadMessage)) , downloadProgressWidget(new QWidget(downloadMessage))
, progressBarLayout(new QHBoxLayout(downloadProgressWidget)) , 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) void MainWindow::setIcon(QString szIconPath)
{ {
if (!QFileInfo(szIconPath).exists()) { if (!QFile::exists(szIconPath)) {
return; return;
} }
@ -83,19 +97,13 @@ void MainWindow::setIcon(QString szIconPath)
setWindowIcon(QIcon(szIconPath)); setWindowIcon(QIcon(szIconPath));
m_tray->setIcon(QIcon(szIconPath)); m_tray->setIcon(QIcon(szIconPath));
DAboutDialog *aboutDialog = qobject_cast<Application *>(qApp)->aboutDialog(); qApp->setWindowIcon(QIcon::fromTheme(szIconPath));
if (aboutDialog) { qApp->setProductIcon(QIcon::fromTheme(szIconPath));
aboutDialog->setWindowIcon(QIcon::fromTheme(szIconPath));
aboutDialog->setProductIcon(QIcon::fromTheme(szIconPath));
}
} }
void MainWindow::setDescription(const QString &desc) void MainWindow::setDescription(const QString &desc)
{ {
DAboutDialog *aboutDialog = qobject_cast<Application *>(qApp)->aboutDialog(); qApp->setApplicationDescription(desc);
if (aboutDialog) {
aboutDialog->setDescription(desc);
}
} }
QString MainWindow::title() const QString MainWindow::title() const
@ -156,6 +164,7 @@ void MainWindow::initLog()
DLogManager::setlogFilePath(tmpDir() + "/" + "log"); DLogManager::setlogFilePath(tmpDir() + "/" + "log");
DLogManager::registerFileAppender(); DLogManager::registerFileAppender();
DLogManager::registerConsoleAppender(); DLogManager::registerConsoleAppender();
DLogManager::registerJournalAppender();
} }
void MainWindow::initTmpDir() void MainWindow::initTmpDir()
@ -242,7 +251,7 @@ void MainWindow::initDownloadProgressBar()
btnResume->setFixedSize(80, 32); btnResume->setFixedSize(80, 32);
btnCancel->setFixedSize(80, 32); btnCancel->setFixedSize(80, 32);
progressBarLayout->setMargin(0); progressBarLayout->setContentsMargins(0, 0, 0, 0);
progressBarLayout->setSpacing(0); progressBarLayout->setSpacing(0);
progressBarLayout->setAlignment(Qt::AlignCenter); progressBarLayout->setAlignment(Qt::AlignCenter);
progressBarLayout->addWidget(downloadProgressBar); progressBarLayout->addWidget(downloadProgressBar);
@ -251,7 +260,7 @@ void MainWindow::initDownloadProgressBar()
progressBarLayout->addWidget(btnResume); progressBarLayout->addWidget(btnResume);
progressBarLayout->addWidget(btnCancel); progressBarLayout->addWidget(btnCancel);
downloadMessage->setIcon(QIcon::fromTheme("deepin-download").pixmap(64, 64)); downloadMessage->setIcon(QIcon::fromTheme("deepin-download"));
downloadMessage->setWidget(downloadProgressWidget); downloadMessage->setWidget(downloadProgressWidget);
downloadMessage->hide(); downloadMessage->hide();
} }
@ -301,7 +310,7 @@ void MainWindow::initConnections()
fixSize(); fixSize();
}); });
connect(t_about, &QAction::triggered, this, [=]() { connect(t_about, &QAction::triggered, this, [=]() {
qobject_cast<Application *>(qApp)->handleAboutAction(); qobject_cast<Application *>(qApp)->triggerAboutAction();
}); });
connect(t_exit, &QAction::triggered, this, [=]() { connect(t_exit, &QAction::triggered, this, [=]() {
exit(0); exit(0);
@ -322,14 +331,14 @@ void MainWindow::fullScreen()
m_fixSize->setDisabled(true); m_fixSize->setDisabled(true);
m_menu->update(); m_menu->update();
showFullScreen(); 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 { } else {
if (!m_isFixedSize) { if (!m_isFixedSize) {
m_fixSize->setDisabled(false); // 命令行参数没有固定窗口大小时,窗口模式下允许手动选择固定窗口大小 m_fixSize->setDisabled(false); // 命令行参数没有固定窗口大小时,窗口模式下允许手动选择固定窗口大小
} }
m_menu->update(); m_menu->update();
showNormal(); 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); QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/" + fileName);
if (!saveFile.isEmpty()) { if (!saveFile.isEmpty()) {
// 判断上层目录是否可写入 // 判断上层目录是否可写入
if (QFileInfo(QFileInfo(saveFile).absolutePath()).isWritable()) { if (QFileInfo(QFileInfo(saveFile).absoluteDir().canonicalPath()).isWritable()) {
return saveFile; return saveFile;
} else { } else {
return saveAs(fileName); 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()) { if (mutex.tryLock()) {
QString fileName = QFileInfo(item->path()).fileName(); QString fileName = request->suggestedFileName();
QString filePath = saveAs(fileName); QString filePath = saveAs(fileName);
if (filePath.isEmpty()) { if (filePath.isEmpty()) {
mutex.unlock(); mutex.unlock();
return; return;
} }
item->setPath(filePath);
filePath = QFileInfo(item->path()).absoluteFilePath();
connect(item, &QWebEngineDownloadItem::downloadProgress, this, &MainWindow::on_downloadProgress); QFileInfo fileInfo(filePath);
connect(item, &QWebEngineDownloadItem::finished, this, [=]() { 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); on_downloadFinish(filePath);
}); });
connect(btnPause, &DPushButton::clicked, this, [=]() { connect(btnPause, &DPushButton::clicked, this, [=]() {
on_downloadPause(item); on_downloadPause(request);
}); });
connect(btnResume, &DPushButton::clicked, this, [=]() { connect(btnResume, &DPushButton::clicked, this, [=]() {
on_downloadResume(item); on_downloadResume(request);
}); });
connect(btnCancel, &DPushButton::clicked, this, [=]() { connect(btnCancel, &DPushButton::clicked, this, [=]() {
on_downloadCancel(item); on_downloadCancel(request);
}); });
DFloatingMessage *message = new DFloatingMessage(DFloatingMessage::TransientType); DFloatingMessage *message = new DFloatingMessage(DFloatingMessage::TransientType);
message->setIcon(QIcon::fromTheme("dialog-information").pixmap(64, 64)); message->setIcon(QIcon::fromTheme("dialog-information"));
message->setMessage(QString(QObject::tr("%1Start downloading %2")).arg(" ").arg(fileName)); message->setMessage(QObject::tr("%1Start downloading %2").arg(" ", fileName));
DMessageManager::instance()->sendMessage(this, message); DMessageManager::instance()->sendMessage(this, message);
item->accept(); request->accept();
// 重置 DownloadProgressBar 状态 // 重置 DownloadProgressBar 状态
isCanceled = false; isCanceled = false;
@ -453,14 +468,16 @@ void MainWindow::on_downloadStart(QWebEngineDownloadItem *item)
btnPause->show(); btnPause->show();
this->downloadMessage->show(); // 上一次下载完成后隐藏了进度条,这里要重新显示 this->downloadMessage->show(); // 上一次下载完成后隐藏了进度条,这里要重新显示
} else { } 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); QWebEngineDownloadRequest *request = qobject_cast<QWebEngineDownloadRequest *>(sender());
downloadProgressBar->setValue(value);
int value = int(double(request->receivedBytes()) / double(request->totalBytes()) * 100.0);
downloadProgressBar->setValue(qBound(downloadProgressBar->value(), value, 100));
downloadMessage->setMessage(" " + QString::number(value) + "%"); downloadMessage->setMessage(" " + QString::number(value) + "%");
@ -469,6 +486,11 @@ void MainWindow::on_downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
void MainWindow::on_downloadFinish(QString filePath) void MainWindow::on_downloadFinish(QString filePath)
{ {
QWebEngineDownloadRequest *request = qobject_cast<QWebEngineDownloadRequest *>(sender());
if (!request->isFinished()) {
return;
}
mutex.unlock(); // 解锁互斥量,允许下载新文件 mutex.unlock(); // 解锁互斥量,允许下载新文件
downloadMessage->hide(); downloadMessage->hide();
@ -478,8 +500,8 @@ void MainWindow::on_downloadFinish(QString filePath)
DPushButton *button = new DPushButton(QObject::tr("Open")); DPushButton *button = new DPushButton(QObject::tr("Open"));
DFloatingMessage *message = new DFloatingMessage(DFloatingMessage::ResidentType); DFloatingMessage *message = new DFloatingMessage(DFloatingMessage::ResidentType);
message->setIcon(QIcon::fromTheme("dialog-ok").pixmap(64, 64)); message->setIcon(QIcon::fromTheme("dialog-ok"));
message->setMessage(QString(" %1 %2 %3").arg(QFileInfo(filePath).fileName()).arg(QObject::tr("download finished.")).arg(QObject::tr("Show in file manager?"))); message->setMessage(QString(" %1 %2 %3").arg(QFileInfo(filePath).fileName(), QObject::tr("download finished."), QObject::tr("Show in file manager?")));
message->setWidget(button); message->setWidget(button);
DMessageManager::instance()->sendMessage(this, message); 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(); btnResume->show();
btnPause->hide(); 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(); btnResume->hide();
btnPause->show(); btnPause->show();
} }
void MainWindow::on_downloadCancel(QWebEngineDownloadItem *item) void MainWindow::on_downloadCancel(QWebEngineDownloadRequest *request)
{ {
isCanceled = true; // 取消下载 isCanceled = true; // 取消下载
item->cancel(); request->cancel();
mutex.unlock(); mutex.unlock();
downloadMessage->hide(); 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() 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, bool nHideButtons = false,
QWidget *parent = nullptr); QWidget *parent = nullptr);
~MainWindow(); ~MainWindow();
bool event(QEvent *event) override;
void setIcon(QString szIconPath); void setIcon(QString szIconPath);
void setDescription(const QString &desc); void setDescription(const QString &desc);
@ -70,12 +71,12 @@ public slots:
private slots: private slots:
void on_trayIconActivated(QSystemTrayIcon::ActivationReason reason); void on_trayIconActivated(QSystemTrayIcon::ActivationReason reason);
void on_downloadStart(QWebEngineDownloadItem *item); void on_downloadStart(QWebEngineDownloadRequest *request);
void on_downloadProgress(qint64 bytesReceived, qint64 bytesTotal); void on_receivedBytesChanged();
void on_downloadFinish(QString filePath); void on_downloadFinish(QString filePath);
void on_downloadPause(QWebEngineDownloadItem *item); void on_downloadPause(QWebEngineDownloadRequest *request);
void on_downloadResume(QWebEngineDownloadItem *item); void on_downloadResume(QWebEngineDownloadRequest *request);
void on_downloadCancel(QWebEngineDownloadItem *item); void on_downloadCancel(QWebEngineDownloadRequest *request);
void slotLoadErrorOccurred(); 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 greaterThan(QT_MAJOR_VERSION, 5): QT += widgets
@ -6,8 +6,8 @@ TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11 link_pkgconfig CONFIG += c++17 link_pkgconfig
PKGCONFIG += dtkcore dtkgui dtkwidget PKGCONFIG += dtk6core dtk6gui dtk6widget
HEADERS += \ HEADERS += \
mainwindow.h \ mainwindow.h \
@ -31,18 +31,7 @@ SOURCES += \
webengineurlrequestinterceptor.cpp webengineurlrequestinterceptor.cpp
RESOURCES += \ RESOURCES += \
resources/resources.qrc resources/resources.qrc
TRANSLATIONS += \ TRANSLATIONS += \
translations/spark-webapp-runtime_zh_CN.ts ../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

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(); DGuiApplicationHelper::ColorType themeType = DGuiApplicationHelper::instance()->themeType();
QString env = qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"); 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) * --blink-settings=preferredColorScheme=0 prefers-color-scheme=dark (>= 5.14)

@ -58,7 +58,7 @@ void Widget::initUI()
QWidget *spinnerWidget = new QWidget(this); QWidget *spinnerWidget = new QWidget(this);
QHBoxLayout *spinnerLayout = new QHBoxLayout(spinnerWidget); QHBoxLayout *spinnerLayout = new QHBoxLayout(spinnerWidget);
spinnerLayout->setMargin(0); spinnerLayout->setContentsMargins(0, 0, 0, 0);
spinnerLayout->setSpacing(0); spinnerLayout->setSpacing(0);
spinnerLayout->setAlignment(Qt::AlignCenter); spinnerLayout->setAlignment(Qt::AlignCenter);
spinnerLayout->addStretch(); 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"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS> <!DOCTYPE TS>
<TS version="2.1" language="zh_CN"> <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> <context>
<name>QObject</name> <name>QObject</name>
<message> <message>
<location filename="../application.cpp" line="90"/> <location filename="../src/application.cpp" line="28"/>
<location filename="../main.cpp" line="186"/> <location filename="../src/main.cpp" line="167"/>
<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="60"/> <location filename="../src/main.cpp" line="44"/>
<source>Description: %1</source> <source>Description: %1</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="66"/> <location filename="../src/main.cpp" line="50"/>
<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="71"/> <location filename="../src/main.cpp" line="55"/>
<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="78"/> <location filename="../src/main.cpp" line="62"/>
<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="85"/> <location filename="../src/main.cpp" line="69"/>
<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="92"/> <location filename="../src/main.cpp" line="76"/>
<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="99"/> <location filename="../src/main.cpp" line="83"/>
<source>Enable Tray Icon. Default is false.</source> <source>Enable Tray Icon. Default is false.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="103"/> <location filename="../src/main.cpp" line="87"/>
<source>Run in Fullscreen Mode. Default is false.</source> <source>Run in Fullscreen Mode. Default is false.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main.cpp" line="107"/> <location filename="../src/main.cpp" line="91"/>
<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="111"/> <location filename="../src/main.cpp" line="95"/>
<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="116"/> <location filename="../src/main.cpp" line="100"/>
<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="123"/> <location filename="../src/main.cpp" line="107"/>
<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="130"/> <location filename="../src/main.cpp" line="114"/>
<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="137"/> <location filename="../src/main.cpp" line="121"/>
<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="144"/> <location filename="../src/main.cpp" line="128"/>
<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="151"/> <location filename="../src/main.cpp" line="135"/>
<source>To use GPU instead of CPU to decoding. Default True.</source> <source>To use GPU instead of CPU to decoding. Default True.</source>
<translation>GPU渲染</translation> <translation>GPU渲染</translation>
</message> </message>
<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> <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="6"/> <location filename="../src/globaldefine.h" line="6"/>
<source>SparkWebAppRuntime</source> <source>SparkWebAppRuntime</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="47"/> <location filename="../src/mainwindow.cpp" line="48"/>
<source>Full Screen</source> <source>Full Screen</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="48"/> <location filename="../src/mainwindow.cpp" line="49"/>
<source>Fix Size</source> <source>Fix Size</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="49"/> <location filename="../src/mainwindow.cpp" line="50"/>
<source>Hide Buttons</source> <source>Hide Buttons</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="50"/> <location filename="../src/mainwindow.cpp" line="51"/>
<source>Clear Cache</source> <source>Clear Cache</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="52"/> <location filename="../src/mainwindow.cpp" line="53"/>
<source>Show MainWindow</source> <source>Show MainWindow</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="59"/> <location filename="../src/mainwindow.cpp" line="60"/>
<source>Pause</source> <source>Pause</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="60"/> <location filename="../src/mainwindow.cpp" line="61"/>
<source>Resume</source> <source>Resume</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="61"/> <location filename="../src/mainwindow.cpp" line="62"/>
<source>Cancel</source> <source>Cancel</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="381"/> <location filename="../src/mainwindow.cpp" line="390"/>
<source>Save As</source> <source>Save As</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="445"/> <location filename="../src/mainwindow.cpp" line="460"/>
<source>%1Start downloading %2</source> <source>%1Start downloading %2</source>
<translation>%1 %2</translation> <translation>%1 %2</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="456"/> <location filename="../src/mainwindow.cpp" line="471"/>
<source>%1Wait for previous download to complete!</source> <source>%1Wait for previous download to complete!</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="478"/> <location filename="../src/mainwindow.cpp" line="500"/>
<source>Open</source> <source>Open</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="482"/> <location filename="../src/mainwindow.cpp" line="504"/>
<source>download finished.</source> <source>download finished.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="482"/> <location filename="../src/mainwindow.cpp" line="504"/>
<source>Show in file manager?</source> <source>Show in file manager?</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="520"/> <location filename="../src/mainwindow.cpp" line="542"/>
<source>%1Download canceled!</source> <source>%1Download canceled!</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="525"/> <location filename="../src/mainwindow.cpp" line="547"/>
<source>%1Load error occurred!</source> <source>%1Load error occurred!</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../webengineview.cpp" line="79"/> <location filename="../src/webengineview.cpp" line="82"/>
<source>View</source> <source>View</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </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> </TS>