mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
export: fix wkhtmltopdf
- MathJax works fine; - Mermaid does not work; - Flowchart.js works fine;
This commit is contained in:
parent
ada0b40d80
commit
635ac0a10b
@ -120,7 +120,7 @@ void VExportDialog::setupUI()
|
|||||||
|
|
||||||
m_consoleEdit = new QPlainTextEdit();
|
m_consoleEdit = new QPlainTextEdit();
|
||||||
m_consoleEdit->setReadOnly(true);
|
m_consoleEdit->setReadOnly(true);
|
||||||
m_consoleEdit->setLineWrapMode(QPlainTextEdit::NoWrap);
|
m_consoleEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth);
|
||||||
m_consoleEdit->setProperty("LineEdit", true);
|
m_consoleEdit->setProperty("LineEdit", true);
|
||||||
m_consoleEdit->setPlaceholderText(tr("Output logs will be shown here"));
|
m_consoleEdit->setPlaceholderText(tr("Output logs will be shown here"));
|
||||||
|
|
||||||
@ -148,6 +148,15 @@ void VExportDialog::setupUI()
|
|||||||
QDesktopServices::openUrl(url);
|
QDesktopServices::openUrl(url);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Progress bar.
|
||||||
|
m_proBar = new QProgressBar();
|
||||||
|
m_proBar->setRange(0, 0);
|
||||||
|
m_proBar->hide();
|
||||||
|
|
||||||
|
QHBoxLayout *btnLayout = new QHBoxLayout();
|
||||||
|
btnLayout->addWidget(m_proBar);
|
||||||
|
btnLayout->addWidget(m_btnBox);
|
||||||
|
|
||||||
QFormLayout *basicLayout = new QFormLayout();
|
QFormLayout *basicLayout = new QFormLayout();
|
||||||
basicLayout->addRow(tr("Notes to export:"), m_srcCB);
|
basicLayout->addRow(tr("Notes to export:"), m_srcCB);
|
||||||
basicLayout->addRow(tr("Target format:"), m_formatCB);
|
basicLayout->addRow(tr("Target format:"), m_formatCB);
|
||||||
@ -175,7 +184,7 @@ void VExportDialog::setupUI()
|
|||||||
mainLayout->addWidget(m_basicBox);
|
mainLayout->addWidget(m_basicBox);
|
||||||
mainLayout->addWidget(m_settingBox);
|
mainLayout->addWidget(m_settingBox);
|
||||||
mainLayout->addWidget(m_consoleEdit);
|
mainLayout->addWidget(m_consoleEdit);
|
||||||
mainLayout->addWidget(m_btnBox);
|
mainLayout->addLayout(btnLayout);
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
@ -258,8 +267,8 @@ QWidget *VExportDialog::setupPDFAdvancedSettings()
|
|||||||
|
|
||||||
// wkhtmltopdf extra argumnets.
|
// wkhtmltopdf extra argumnets.
|
||||||
m_wkExtraArgsEdit = new VLineEdit();
|
m_wkExtraArgsEdit = new VLineEdit();
|
||||||
m_wkExtraArgsEdit->setToolTip(tr("Additional arguments passed to wkhtmltopdf"));
|
m_wkExtraArgsEdit->setToolTip(tr("Additional global options passed to wkhtmltopdf"));
|
||||||
m_wkExtraArgsEdit->setPlaceholderText(tr("Use \" to enclose arguments containing space"));
|
m_wkExtraArgsEdit->setPlaceholderText(tr("Use \" to enclose options containing spaces"));
|
||||||
m_wkExtraArgsEdit->setEnabled(m_wkhtmltopdfCB->isChecked());
|
m_wkExtraArgsEdit->setEnabled(m_wkhtmltopdfCB->isChecked());
|
||||||
|
|
||||||
QGridLayout *advLayout = new QGridLayout();
|
QGridLayout *advLayout = new QGridLayout();
|
||||||
@ -286,7 +295,7 @@ QWidget *VExportDialog::setupPDFAdvancedSettings()
|
|||||||
advLayout->addWidget(new QLabel(tr("Page number:")), 5, 0);
|
advLayout->addWidget(new QLabel(tr("Page number:")), 5, 0);
|
||||||
advLayout->addWidget(m_wkPageNumberCB, 5, 1, 1, 2);
|
advLayout->addWidget(m_wkPageNumberCB, 5, 1, 1, 2);
|
||||||
|
|
||||||
advLayout->addWidget(new QLabel(tr("Additional global options:")), 6, 0);
|
advLayout->addWidget(new QLabel(tr("Additional options:")), 6, 0);
|
||||||
advLayout->addWidget(m_wkExtraArgsEdit, 6, 1, 1, 5);
|
advLayout->addWidget(m_wkExtraArgsEdit, 6, 1, 1, 5);
|
||||||
|
|
||||||
advLayout->setContentsMargins(0, 0, 0, 0);
|
advLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
@ -478,6 +487,7 @@ void VExportDialog::startExport()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_exportBtn->setEnabled(false);
|
m_exportBtn->setEnabled(false);
|
||||||
|
m_proBar->show();
|
||||||
m_askedToStop = false;
|
m_askedToStop = false;
|
||||||
m_inExport = true;
|
m_inExport = true;
|
||||||
|
|
||||||
@ -523,6 +533,7 @@ void VExportDialog::startExport()
|
|||||||
if (!checkWkhtmltopdfExecutable(s_opt.m_pdfOpt.m_wkPath)) {
|
if (!checkWkhtmltopdfExecutable(s_opt.m_pdfOpt.m_wkPath)) {
|
||||||
m_inExport = false;
|
m_inExport = false;
|
||||||
m_exportBtn->setEnabled(true);
|
m_exportBtn->setEnabled(true);
|
||||||
|
m_proBar->hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -616,6 +627,7 @@ exit:
|
|||||||
|
|
||||||
m_inExport = false;
|
m_inExport = false;
|
||||||
m_exportBtn->setEnabled(true);
|
m_exportBtn->setEnabled(true);
|
||||||
|
m_proBar->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString VExportDialog::getOutputDirectory() const
|
QString VExportDialog::getOutputDirectory() const
|
||||||
@ -686,7 +698,8 @@ void VExportDialog::handleInputChanged()
|
|||||||
|
|
||||||
void VExportDialog::appendLogLine(const QString &p_text)
|
void VExportDialog::appendLogLine(const QString &p_text)
|
||||||
{
|
{
|
||||||
m_consoleEdit->appendPlainText(p_text);
|
m_consoleEdit->appendPlainText(">>> " + p_text);
|
||||||
|
m_consoleEdit->ensureCursorVisible();
|
||||||
QCoreApplication::sendPostedEvents();
|
QCoreApplication::sendPostedEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ class VCart;
|
|||||||
class VExporter;
|
class VExporter;
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
class VLineEdit;
|
class VLineEdit;
|
||||||
|
class QProgressBar;
|
||||||
|
|
||||||
|
|
||||||
enum class ExportSource
|
enum class ExportSource
|
||||||
@ -336,6 +337,8 @@ private:
|
|||||||
|
|
||||||
VCart *m_cart;
|
VCart *m_cart;
|
||||||
|
|
||||||
|
QProgressBar *m_proBar;
|
||||||
|
|
||||||
QPageLayout m_pageLayout;
|
QPageLayout m_pageLayout;
|
||||||
|
|
||||||
// Whether we are exporting files.
|
// Whether we are exporting files.
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
/* STYLE_PLACE_HOLDER */
|
/* STYLE_PLACE_HOLDER */
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- EXTRA_PLACE_HOLDER -->
|
||||||
|
|
||||||
<!-- HEAD_PLACE_HOLDER -->
|
<!-- HEAD_PLACE_HOLDER -->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -44,6 +44,10 @@ if (typeof VEnableFlashAnchor == 'undefined') {
|
|||||||
VEnableFlashAnchor = false;
|
VEnableFlashAnchor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof VRemoveMathjaxScript == 'undefined') {
|
||||||
|
VRemoveMathjaxScript = false;
|
||||||
|
}
|
||||||
|
|
||||||
var getUrlScheme = function(url) {
|
var getUrlScheme = function(url) {
|
||||||
var idx = url.indexOf(':');
|
var idx = url.indexOf(':');
|
||||||
if (idx > -1) {
|
if (idx > -1) {
|
||||||
@ -1078,6 +1082,11 @@ var postProcessMathJax = function() {
|
|||||||
var all = MathJax.Hub.getAllJax();
|
var all = MathJax.Hub.getAllJax();
|
||||||
for (var i = 0; i < all.length; ++i) {
|
for (var i = 0; i < all.length; ++i) {
|
||||||
var node = all[i].SourceElement().parentNode;
|
var node = all[i].SourceElement().parentNode;
|
||||||
|
if (VRemoveMathjaxScript) {
|
||||||
|
// Remove the SourceElement.
|
||||||
|
node.removeChild(all[i].SourceElement());
|
||||||
|
}
|
||||||
|
|
||||||
if (node.tagName.toLowerCase() == 'code') {
|
if (node.tagName.toLowerCase() == 'code') {
|
||||||
var pre = node.parentNode;
|
var pre = node.parentNode;
|
||||||
var p = document.createElement('p');
|
var p = document.createElement('p');
|
||||||
|
@ -601,18 +601,22 @@ QString VUtils::generateHtmlTemplate(MarkdownConverterType p_conType,
|
|||||||
const QString &p_renderBg,
|
const QString &p_renderBg,
|
||||||
const QString &p_renderStyle,
|
const QString &p_renderStyle,
|
||||||
const QString &p_renderCodeBlockStyle,
|
const QString &p_renderCodeBlockStyle,
|
||||||
bool p_isPDF)
|
bool p_isPDF,
|
||||||
|
bool p_wkhtmltopdf)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT((p_isPDF && p_wkhtmltopdf) || !p_wkhtmltopdf);
|
||||||
|
|
||||||
QString templ = VNote::generateHtmlTemplate(g_config->getRenderBackgroundColor(p_renderBg),
|
QString templ = VNote::generateHtmlTemplate(g_config->getRenderBackgroundColor(p_renderBg),
|
||||||
g_config->getCssStyleUrl(p_renderStyle),
|
g_config->getCssStyleUrl(p_renderStyle),
|
||||||
g_config->getCodeBlockCssStyleUrl(p_renderCodeBlockStyle),
|
g_config->getCodeBlockCssStyleUrl(p_renderCodeBlockStyle),
|
||||||
p_isPDF);
|
p_isPDF);
|
||||||
|
|
||||||
return generateHtmlTemplate(templ, p_conType);
|
return generateHtmlTemplate(templ, p_conType, p_wkhtmltopdf);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString VUtils::generateHtmlTemplate(const QString &p_template,
|
QString VUtils::generateHtmlTemplate(const QString &p_template,
|
||||||
MarkdownConverterType p_conType)
|
MarkdownConverterType p_conType,
|
||||||
|
bool p_wkhtmltopdf)
|
||||||
{
|
{
|
||||||
QString jsFile, extraFile;
|
QString jsFile, extraFile;
|
||||||
switch (p_conType) {
|
switch (p_conType) {
|
||||||
@ -674,6 +678,14 @@ QString VUtils::generateHtmlTemplate(const QString &p_template,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (g_config->getEnableMathjax()) {
|
if (g_config->getEnableMathjax()) {
|
||||||
|
QString mj = g_config->getMathjaxJavascript();
|
||||||
|
if (p_wkhtmltopdf) {
|
||||||
|
// Chante MathJax to be rendered as SVG.
|
||||||
|
// If rendered as HTML, it will make the font of <code> messy.
|
||||||
|
QRegExp reg("(Mathjax\\.js\\?config=)\\S+", Qt::CaseInsensitive);
|
||||||
|
mj.replace(reg, QString("\\1%1").arg("TeX-MML-AM_SVG"));
|
||||||
|
}
|
||||||
|
|
||||||
extraFile += "<script type=\"text/x-mathjax-config\">"
|
extraFile += "<script type=\"text/x-mathjax-config\">"
|
||||||
"MathJax.Hub.Config({\n"
|
"MathJax.Hub.Config({\n"
|
||||||
" tex2jax: {inlineMath: [['$','$'], ['\\\\(','\\\\)']],\n"
|
" tex2jax: {inlineMath: [['$','$'], ['\\\\(','\\\\)']],\n"
|
||||||
@ -682,8 +694,12 @@ QString VUtils::generateHtmlTemplate(const QString &p_template,
|
|||||||
" showProcessingMessages: false,\n"
|
" showProcessingMessages: false,\n"
|
||||||
" messageStyle: \"none\"});\n"
|
" messageStyle: \"none\"});\n"
|
||||||
"</script>\n"
|
"</script>\n"
|
||||||
"<script type=\"text/javascript\" async src=\"" + g_config->getMathjaxJavascript() + "\"></script>\n" +
|
"<script type=\"text/javascript\" async src=\"" + mj + "\"></script>\n" +
|
||||||
"<script>var VEnableMathjax = true;</script>\n";
|
"<script>var VEnableMathjax = true;</script>\n";
|
||||||
|
|
||||||
|
if (p_wkhtmltopdf) {
|
||||||
|
extraFile += "<script>var VRemoveMathjaxScript = true;</script>\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_config->getEnableImageCaption()) {
|
if (g_config->getEnableImageCaption()) {
|
||||||
@ -710,9 +726,39 @@ QString VUtils::generateHtmlTemplate(const QString &p_template,
|
|||||||
return htmlTemplate;
|
return htmlTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString VUtils::generateExportHtmlTemplate(const QString &p_renderBg)
|
QString VUtils::generateExportHtmlTemplate(const QString &p_renderBg, bool p_includeMathJax)
|
||||||
{
|
{
|
||||||
return VNote::generateExportHtmlTemplate(g_config->getRenderBackgroundColor(p_renderBg));
|
QString templ = VNote::generateExportHtmlTemplate(g_config->getRenderBackgroundColor(p_renderBg));
|
||||||
|
QString extra;
|
||||||
|
if (p_includeMathJax) {
|
||||||
|
extra += "<script type=\"text/x-mathjax-config\">\n"
|
||||||
|
"MathJax.Hub.Config({\n"
|
||||||
|
"showProcessingMessages: false,\n"
|
||||||
|
"messageStyle: \"none\",\n"
|
||||||
|
"SVG: {\n"
|
||||||
|
"minScaleAdjust: 100,\n"
|
||||||
|
"styles: {\n"
|
||||||
|
"\".MathJax_SVG\": {\n"
|
||||||
|
"\"font-size\": \"2em !important\"\n"
|
||||||
|
"}\n"
|
||||||
|
"}\n"
|
||||||
|
"}\n"
|
||||||
|
"});\n"
|
||||||
|
"</script>\n";
|
||||||
|
|
||||||
|
QString mj = g_config->getMathjaxJavascript();
|
||||||
|
// Chante MathJax to be rendered as SVG.
|
||||||
|
QRegExp reg("(Mathjax\\.js\\?config=)\\S+", Qt::CaseInsensitive);
|
||||||
|
mj.replace(reg, QString("\\1%1").arg("TeX-MML-AM_SVG"));
|
||||||
|
|
||||||
|
extra += "<script type=\"text/javascript\" async src=\"" + mj + "\"></script>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extra.isEmpty()) {
|
||||||
|
templ.replace(HtmlHolder::c_extraHolder, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
return templ;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString VUtils::getFileNameWithSequence(const QString &p_directory,
|
QString VUtils::getFileNameWithSequence(const QString &p_directory,
|
||||||
|
@ -171,14 +171,16 @@ public:
|
|||||||
static QString generateHtmlTemplate(MarkdownConverterType p_conType);
|
static QString generateHtmlTemplate(MarkdownConverterType p_conType);
|
||||||
|
|
||||||
// @p_renderBg is the background name.
|
// @p_renderBg is the background name.
|
||||||
|
// @p_wkhtmltopdf: whether this template is used for wkhtmltopdf.
|
||||||
static QString generateHtmlTemplate(MarkdownConverterType p_conType,
|
static QString generateHtmlTemplate(MarkdownConverterType p_conType,
|
||||||
const QString &p_renderBg,
|
const QString &p_renderBg,
|
||||||
const QString &p_renderStyle,
|
const QString &p_renderStyle,
|
||||||
const QString &p_renderCodeBlockStyle,
|
const QString &p_renderCodeBlockStyle,
|
||||||
bool p_isPDF);
|
bool p_isPDF,
|
||||||
|
bool p_wkhtmltopdf = false);
|
||||||
|
|
||||||
// @p_renderBg is the background name.
|
// @p_renderBg is the background name.
|
||||||
static QString generateExportHtmlTemplate(const QString &p_renderBg);
|
static QString generateExportHtmlTemplate(const QString &p_renderBg, bool p_includeMathJax);
|
||||||
|
|
||||||
static QString generateSimpleHtmlTemplate(const QString &p_body);
|
static QString generateSimpleHtmlTemplate(const QString &p_body);
|
||||||
|
|
||||||
@ -356,7 +358,8 @@ private:
|
|||||||
const QString &p_path);
|
const QString &p_path);
|
||||||
|
|
||||||
static QString generateHtmlTemplate(const QString &p_template,
|
static QString generateHtmlTemplate(const QString &p_template,
|
||||||
MarkdownConverterType p_conType);
|
MarkdownConverterType p_conType,
|
||||||
|
bool p_wkhtmltopdf = false);
|
||||||
|
|
||||||
// <value, name>
|
// <value, name>
|
||||||
static QVector<QPair<QString, QString>> s_availableLanguages;
|
static QVector<QPair<QString, QString>> s_availableLanguages;
|
||||||
|
@ -43,9 +43,11 @@ void VExporter::prepareExport(const ExportOption &p_opt)
|
|||||||
p_opt.m_renderBg,
|
p_opt.m_renderBg,
|
||||||
p_opt.m_renderStyle,
|
p_opt.m_renderStyle,
|
||||||
p_opt.m_renderCodeBlockStyle,
|
p_opt.m_renderCodeBlockStyle,
|
||||||
isPdf);
|
isPdf,
|
||||||
|
isPdf && p_opt.m_pdfOpt.m_wkhtmltopdf);
|
||||||
|
|
||||||
m_exportHtmlTemplate = VUtils::generateExportHtmlTemplate(p_opt.m_renderBg);
|
m_exportHtmlTemplate = VUtils::generateExportHtmlTemplate(p_opt.m_renderBg,
|
||||||
|
isPdf && p_opt.m_pdfOpt.m_wkhtmltopdf);
|
||||||
|
|
||||||
m_pageLayout = *(p_opt.m_pdfOpt.m_layout);
|
m_pageLayout = *(p_opt.m_pdfOpt.m_layout);
|
||||||
|
|
||||||
@ -96,8 +98,6 @@ static QStringList parseCombinedArgString(const QString &program)
|
|||||||
void VExporter::prepareWKArguments(const ExportPDFOption &p_opt)
|
void VExporter::prepareWKArguments(const ExportPDFOption &p_opt)
|
||||||
{
|
{
|
||||||
m_wkArgs.clear();
|
m_wkArgs.clear();
|
||||||
m_wkArgs << "--quiet";
|
|
||||||
m_wkArgs << "--encoding" << "utf-8";
|
|
||||||
m_wkArgs << "--page-size" << m_pageLayout.pageSize().key();
|
m_wkArgs << "--page-size" << m_pageLayout.pageSize().key();
|
||||||
m_wkArgs << "--orientation"
|
m_wkArgs << "--orientation"
|
||||||
<< (m_pageLayout.orientation() == QPageLayout::Portrait ? "Portrait" : "Landscape");
|
<< (m_pageLayout.orientation() == QPageLayout::Portrait ? "Portrait" : "Landscape");
|
||||||
@ -108,8 +108,6 @@ void VExporter::prepareWKArguments(const ExportPDFOption &p_opt)
|
|||||||
m_wkArgs << "--margin-right" << marginToStrMM(marginsMM.right());
|
m_wkArgs << "--margin-right" << marginToStrMM(marginsMM.right());
|
||||||
m_wkArgs << "--margin-top" << marginToStrMM(marginsMM.top());
|
m_wkArgs << "--margin-top" << marginToStrMM(marginsMM.top());
|
||||||
|
|
||||||
m_wkArgs << (p_opt.m_wkEnableBackground ? "--background" : "--no-background");
|
|
||||||
|
|
||||||
QString footer;
|
QString footer;
|
||||||
switch (p_opt.m_wkPageNumber) {
|
switch (p_opt.m_wkPageNumber) {
|
||||||
case ExportPageNumber::Left:
|
case ExportPageNumber::Left:
|
||||||
@ -138,11 +136,20 @@ void VExporter::prepareWKArguments(const ExportPDFOption &p_opt)
|
|||||||
m_wkArgs << "--title" << p_opt.m_wkTitle;
|
m_wkArgs << "--title" << p_opt.m_wkTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append additional arguments.
|
m_wkArgs << "--encoding" << "utf-8";
|
||||||
|
m_wkArgs << (p_opt.m_wkEnableBackground ? "--background" : "--no-background");
|
||||||
|
|
||||||
|
// Delay for MathJax.
|
||||||
|
if (p_opt.m_wkhtmltopdf) {
|
||||||
|
m_wkArgs << "--javascript-delay" << "10000";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append additional global option.
|
||||||
if (!p_opt.m_wkExtraArgs.isEmpty()) {
|
if (!p_opt.m_wkExtraArgs.isEmpty()) {
|
||||||
m_wkArgs.append(parseCombinedArgString(p_opt.m_wkExtraArgs));
|
m_wkArgs.append(parseCombinedArgString(p_opt.m_wkExtraArgs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TOC option.
|
||||||
if (p_opt.m_wkEnableTableOfContents) {
|
if (p_opt.m_wkEnableTableOfContents) {
|
||||||
m_wkArgs << "toc" << "--toc-text-size-shrink" << "1.0";
|
m_wkArgs << "toc" << "--toc-text-size-shrink" << "1.0";
|
||||||
}
|
}
|
||||||
@ -658,8 +665,9 @@ bool VExporter::htmlsToPDFViaWK(const QList<QString> &p_htmlFiles,
|
|||||||
|
|
||||||
QString cmd = p_opt.m_wkPath + " " + combineArgs(args);
|
QString cmd = p_opt.m_wkPath + " " + combineArgs(args);
|
||||||
emit outputLog(cmd);
|
emit outputLog(cmd);
|
||||||
|
qDebug() << "wkhtmltopdf cmd:" << cmd;
|
||||||
int ret = QProcess::execute(p_opt.m_wkPath, args);
|
int ret = QProcess::execute(p_opt.m_wkPath, args);
|
||||||
qDebug() << "wkhtmltopdf returned" << ret << cmd;
|
qDebug() << "wkhtmltopdf returned" << ret;
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case -2:
|
case -2:
|
||||||
VUtils::addErrMsg(p_errMsg, tr("Fail to start wkhtmltopdf (%1).").arg(cmd));
|
VUtils::addErrMsg(p_errMsg, tr("Fail to start wkhtmltopdf (%1).").arg(cmd));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user