mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
export: support exporting PDF via wkhtmltopdf tool
This commit is contained in:
parent
3bee0365e9
commit
935bb4d3b4
@ -2,6 +2,7 @@
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QCoreApplication>
|
||||
#include <QProcess>
|
||||
|
||||
#ifndef QT_NO_PRINTER
|
||||
#include <QPrinter>
|
||||
@ -18,6 +19,7 @@
|
||||
#include "vnotefile.h"
|
||||
#include "vnote.h"
|
||||
#include "vexporter.h"
|
||||
#include "vlineedit.h"
|
||||
|
||||
extern VConfigManager *g_config;
|
||||
|
||||
@ -25,7 +27,7 @@ extern VNote *g_vnote;
|
||||
|
||||
QString VExportDialog::s_lastOutputFolder;
|
||||
|
||||
ExportFormat VExportDialog::s_lastExportFormat = ExportFormat::Markdown;
|
||||
ExportOption VExportDialog::s_opt;
|
||||
|
||||
#define LOGERR(x) do { QString msg = (x); \
|
||||
VUtils::addErrMsg(p_errMsg, msg); \
|
||||
@ -45,7 +47,8 @@ VExportDialog::VExportDialog(VNotebook *p_notebook,
|
||||
m_cart(p_cart),
|
||||
m_pageLayout(QPageLayout(QPageSize(QPageSize::A4),
|
||||
QPageLayout::Portrait,
|
||||
QMarginsF(0.3, 0.3, 0.3, 0.3))),
|
||||
QMarginsF(10, 16, 10, 10),
|
||||
QPageLayout::Millimeter)),
|
||||
m_inExport(false),
|
||||
m_askedToStop(false)
|
||||
{
|
||||
@ -56,6 +59,10 @@ VExportDialog::VExportDialog(VNotebook *p_notebook,
|
||||
setupUI();
|
||||
|
||||
m_exporter = new VExporter(this);
|
||||
connect(m_exporter, &VExporter::outputLog,
|
||||
this, [this](const QString &p_log) {
|
||||
appendLogLine(p_log);
|
||||
});
|
||||
|
||||
initUIFields(p_renderer);
|
||||
|
||||
@ -68,6 +75,8 @@ void VExportDialog::setupUI()
|
||||
m_srcCB = VUtils::getComboBox();
|
||||
m_srcCB->setToolTip(tr("Choose notes to export"));
|
||||
m_srcCB->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
|
||||
connect(m_srcCB, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(handleCurrentSrcChanged(int)));
|
||||
|
||||
// Target format.
|
||||
m_formatCB = VUtils::getComboBox();
|
||||
@ -97,12 +106,12 @@ void VExportDialog::setupUI()
|
||||
m_outputEdit = new VLineEdit(s_lastOutputFolder);
|
||||
connect(m_outputEdit, &QLineEdit::textChanged,
|
||||
this, &VExportDialog::handleInputChanged);
|
||||
m_browseBtn = new QPushButton(tr("&Browse"));
|
||||
connect(m_browseBtn, &QPushButton::clicked,
|
||||
this, &VExportDialog::handleBrowseBtnClicked);
|
||||
QPushButton *browseBtn = new QPushButton(tr("&Browse"));
|
||||
connect(browseBtn, &QPushButton::clicked,
|
||||
this, &VExportDialog::handleOutputBrowseBtnClicked);
|
||||
QHBoxLayout *outputLayout = new QHBoxLayout();
|
||||
outputLayout->addWidget(m_outputEdit);
|
||||
outputLayout->addWidget(m_browseBtn);
|
||||
outputLayout->addWidget(browseBtn);
|
||||
|
||||
m_basicBox = new QGroupBox(tr("Information"));
|
||||
|
||||
@ -150,10 +159,12 @@ void VExportDialog::setupUI()
|
||||
m_basicBox->setLayout(basicLayout);
|
||||
|
||||
// Settings box.
|
||||
m_generalSettings = setupGeneralAdvancedSettings();
|
||||
m_htmlSettings = setupHTMLAdvancedSettings();
|
||||
m_pdfSettings = setupPDFAdvancedSettings();
|
||||
|
||||
QVBoxLayout *advLayout = new QVBoxLayout();
|
||||
advLayout->addWidget(m_generalSettings);
|
||||
advLayout->addWidget(m_htmlSettings);
|
||||
advLayout->addWidget(m_pdfSettings);
|
||||
|
||||
@ -190,8 +201,75 @@ QWidget *VExportDialog::setupPDFAdvancedSettings()
|
||||
layoutLayout->addWidget(layoutBtn);
|
||||
layoutLayout->addStretch();
|
||||
|
||||
// Use wkhtmltopdf.
|
||||
m_wkhtmltopdfCB = new QCheckBox(tr("Use wkhtmltopdf"));
|
||||
m_wkhtmltopdfCB->setToolTip(tr("Use wkhtmltopdf tool to generate PDF (wkhtmltopdf needed to be installed)"));
|
||||
connect(m_wkhtmltopdfCB, &QCheckBox::stateChanged,
|
||||
this, [this](int p_state) {
|
||||
bool checked = p_state == Qt::Checked;
|
||||
m_wkPathEdit->setEnabled(checked);
|
||||
m_wkPathBrowseBtn->setEnabled(checked);
|
||||
m_wkBackgroundCB->setEnabled(checked);
|
||||
m_wkTableOfContentsCB->setEnabled(checked);
|
||||
m_wkPageNumberCB->setEnabled(checked);
|
||||
m_wkExtraArgsEdit->setEnabled(checked);
|
||||
});
|
||||
|
||||
QPushButton *wkBtn = new QPushButton(tr("Download wkhtmltopdf"));
|
||||
connect(wkBtn, &QPushButton::clicked,
|
||||
this, [this]() {
|
||||
QString url("https://wkhtmltopdf.org/downloads.html");
|
||||
QDesktopServices::openUrl(QUrl(url));
|
||||
});
|
||||
|
||||
QHBoxLayout *wkLayout = new QHBoxLayout();
|
||||
wkLayout->addWidget(m_wkhtmltopdfCB);
|
||||
wkLayout->addStretch();
|
||||
wkLayout->addWidget(wkBtn);
|
||||
|
||||
// wkhtmltopdf Path.
|
||||
m_wkPathEdit = new VLineEdit();
|
||||
m_wkPathEdit->setToolTip(tr("Tell VNote where to find wkhtmlpdf tool"));
|
||||
m_wkPathEdit->setEnabled(m_wkhtmltopdfCB->isChecked());
|
||||
|
||||
m_wkPathBrowseBtn = new QPushButton(tr("&Browse"));
|
||||
m_wkPathBrowseBtn->setEnabled(m_wkhtmltopdfCB->isChecked());
|
||||
connect(m_wkPathBrowseBtn, &QPushButton::clicked,
|
||||
this, &VExportDialog::handleWkPathBrowseBtnClicked);
|
||||
|
||||
QHBoxLayout *wkPathLayout = new QHBoxLayout();
|
||||
wkPathLayout->addWidget(m_wkPathEdit);
|
||||
wkPathLayout->addWidget(m_wkPathBrowseBtn);
|
||||
|
||||
// wkhtmltopdf enable background.
|
||||
m_wkBackgroundCB = new QCheckBox(tr("Enable background"));
|
||||
m_wkBackgroundCB->setToolTip(tr("Enable background when printing"));
|
||||
m_wkBackgroundCB->setEnabled(m_wkhtmltopdfCB->isChecked());
|
||||
|
||||
// wkhtmltopdf enable table of contents.
|
||||
m_wkTableOfContentsCB = new QCheckBox(tr("Enable Table Of Contents"));
|
||||
m_wkTableOfContentsCB->setToolTip(tr("Add a table of contents to the document"));
|
||||
m_wkTableOfContentsCB->setEnabled(m_wkhtmltopdfCB->isChecked());
|
||||
|
||||
// wkhtmltopdf page number.
|
||||
m_wkPageNumberCB = VUtils::getComboBox();
|
||||
m_wkPageNumberCB->setToolTip(tr("Append page number as footer"));
|
||||
m_wkPageNumberCB->setEnabled(m_wkhtmltopdfCB->isChecked());
|
||||
|
||||
// wkhtmltopdf extra argumnets.
|
||||
m_wkExtraArgsEdit = new VLineEdit();
|
||||
m_wkExtraArgsEdit->setToolTip(tr("Additional arguments passed to wkhtmltopdf"));
|
||||
m_wkExtraArgsEdit->setPlaceholderText(tr("Use \" to enclose arguments containing space"));
|
||||
m_wkExtraArgsEdit->setEnabled(m_wkhtmltopdfCB->isChecked());
|
||||
|
||||
QFormLayout *advLayout = new QFormLayout();
|
||||
advLayout->addRow(tr("Page layout:"), layoutLayout);
|
||||
advLayout->addRow(wkLayout);
|
||||
advLayout->addRow(tr("wkhtmltopdf path:"), wkPathLayout);
|
||||
advLayout->addRow(m_wkBackgroundCB);
|
||||
advLayout->addRow(m_wkTableOfContentsCB);
|
||||
advLayout->addRow(tr("Page number:"), m_wkPageNumberCB);
|
||||
advLayout->addRow(tr("Additional arguments:"), m_wkExtraArgsEdit);
|
||||
|
||||
advLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
@ -206,14 +284,12 @@ QWidget *VExportDialog::setupHTMLAdvancedSettings()
|
||||
// Embed CSS styles.
|
||||
m_embedStyleCB = new QCheckBox(tr("Embed CSS styles"), this);
|
||||
m_embedStyleCB->setToolTip(tr("Embed CSS styles in HTML file"));
|
||||
m_embedStyleCB->setChecked(true);
|
||||
|
||||
// Complete HTML.
|
||||
m_completeHTMLCB = new QCheckBox(tr("Complete page"), this);
|
||||
m_completeHTMLCB->setToolTip(tr("Export the whole web page along with pictures "
|
||||
"which may not keep the HTML link structure of "
|
||||
"the original page"));
|
||||
m_completeHTMLCB->setChecked(true);
|
||||
|
||||
// Mime HTML.
|
||||
m_mimeHTMLCB = new QCheckBox(tr("MIME HTML"), this);
|
||||
@ -238,6 +314,24 @@ QWidget *VExportDialog::setupHTMLAdvancedSettings()
|
||||
return wid;
|
||||
}
|
||||
|
||||
QWidget *VExportDialog::setupGeneralAdvancedSettings()
|
||||
{
|
||||
// Include subfolders.
|
||||
m_subfolderCB = new QCheckBox(tr("Process subfolders"));
|
||||
m_subfolderCB->setToolTip(tr("Process subfolders recursively"));
|
||||
m_subfolderCB->setChecked(true);
|
||||
|
||||
QFormLayout *advLayout = new QFormLayout();
|
||||
advLayout->addRow(m_subfolderCB);
|
||||
|
||||
advLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
QWidget *wid = new QWidget();
|
||||
wid->setLayout(advLayout);
|
||||
|
||||
return wid;
|
||||
}
|
||||
|
||||
void VExportDialog::initUIFields(MarkdownConverterType p_renderer)
|
||||
{
|
||||
// Notes to export.
|
||||
@ -248,7 +342,7 @@ void VExportDialog::initUIFields(MarkdownConverterType p_renderer)
|
||||
|
||||
if (m_directory) {
|
||||
m_srcCB->addItem(tr("Current Folder (%1)").arg(m_directory->getName()),
|
||||
(int)ExportSource::CurrentDirectory);
|
||||
(int)ExportSource::CurrentFolder);
|
||||
}
|
||||
|
||||
if (m_notebook) {
|
||||
@ -265,7 +359,7 @@ void VExportDialog::initUIFields(MarkdownConverterType p_renderer)
|
||||
m_formatCB->addItem(tr("Markdown"), (int)ExportFormat::Markdown);
|
||||
m_formatCB->addItem(tr("HTML"), (int)ExportFormat::HTML);
|
||||
m_formatCB->addItem(tr("PDF"), (int)ExportFormat::PDF);
|
||||
m_formatCB->setCurrentIndex(m_formatCB->findData((int)s_lastExportFormat));
|
||||
m_formatCB->setCurrentIndex(m_formatCB->findData((int)s_opt.m_format));
|
||||
|
||||
// Markdown renderer.
|
||||
m_rendererCB->addItem(tr("Hoedown"), MarkdownConverterType::Hoedown);
|
||||
@ -281,8 +375,11 @@ void VExportDialog::initUIFields(MarkdownConverterType p_renderer)
|
||||
m_renderBgCB->addItem(bgColors[i].m_name, bgColors[i].m_name);
|
||||
}
|
||||
|
||||
m_renderBgCB->setCurrentIndex(
|
||||
m_renderBgCB->findData(g_config->getCurRenderBackgroundColor()));
|
||||
if (s_opt.m_renderBg.isEmpty()) {
|
||||
s_opt.m_renderBg = g_config->getCurRenderBackgroundColor();
|
||||
}
|
||||
|
||||
m_renderBgCB->setCurrentIndex(m_renderBgCB->findData(s_opt.m_renderBg));
|
||||
|
||||
// Markdown rendering style.
|
||||
QList<QString> styles = g_config->getCssStyles();
|
||||
@ -301,6 +398,56 @@ void VExportDialog::initUIFields(MarkdownConverterType p_renderer)
|
||||
|
||||
m_renderCodeBlockStyleCB->setCurrentIndex(
|
||||
m_renderCodeBlockStyleCB->findData(g_config->getCodeBlockCssStyle()));
|
||||
|
||||
m_embedStyleCB->setChecked(s_opt.m_htmlOpt.m_embedCssStyle);
|
||||
|
||||
m_completeHTMLCB->setChecked(s_opt.m_htmlOpt.m_completeHTML);
|
||||
|
||||
m_mimeHTMLCB->setChecked(s_opt.m_htmlOpt.m_mimeHTML);
|
||||
|
||||
m_wkhtmltopdfCB->setChecked(s_opt.m_pdfOpt.m_wkhtmltopdf);
|
||||
|
||||
// wkhtmltopdf path.
|
||||
m_wkPathEdit->setText(g_config->getWkhtmltopdfPath());
|
||||
|
||||
m_wkBackgroundCB->setChecked(s_opt.m_pdfOpt.m_wkEnableBackground);
|
||||
|
||||
m_wkTableOfContentsCB->setChecked(s_opt.m_pdfOpt.m_wkEnableTableOfContents);
|
||||
|
||||
// wkhtmltopdf page number.
|
||||
m_wkPageNumberCB->addItem(tr("None"), (int)ExportPageNumber::None);
|
||||
m_wkPageNumberCB->addItem(tr("Left"), (int)ExportPageNumber::Left);
|
||||
m_wkPageNumberCB->addItem(tr("Center"), (int)ExportPageNumber::Center);
|
||||
m_wkPageNumberCB->addItem(tr("Right"), (int)ExportPageNumber::Right);
|
||||
m_wkPageNumberCB->setCurrentIndex(m_wkPageNumberCB->findData((int)s_opt.m_pdfOpt.m_wkPageNumber));
|
||||
|
||||
m_wkExtraArgsEdit->setText(g_config->getWkhtmltopdfArgs());
|
||||
}
|
||||
|
||||
bool VExportDialog::checkWkhtmltopdfExecutable(const QString &p_file)
|
||||
{
|
||||
QStringList args;
|
||||
args << "--version";
|
||||
int ret = QProcess::execute(p_file, args);
|
||||
switch (ret) {
|
||||
case -2:
|
||||
appendLogLine(tr("Fail to start wkhtmltopdf."));
|
||||
break;
|
||||
|
||||
case -1:
|
||||
appendLogLine(tr("wkhtmltopdf crashed."));
|
||||
break;
|
||||
|
||||
case 0:
|
||||
appendLogLine(tr("Use %1.").arg(p_file));
|
||||
break;
|
||||
|
||||
default:
|
||||
appendLogLine(tr("wkhtmltopdf returned %1.").arg(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
void VExportDialog::startExport()
|
||||
@ -315,45 +462,62 @@ void VExportDialog::startExport()
|
||||
|
||||
QString outputFolder = QDir::cleanPath(QDir(getOutputDirectory()).absolutePath());
|
||||
|
||||
ExportOption opt((ExportSource)m_srcCB->currentData().toInt(),
|
||||
(ExportFormat)m_formatCB->currentData().toInt(),
|
||||
(MarkdownConverterType)m_rendererCB->currentData().toInt(),
|
||||
m_renderBgCB->currentData().toString(),
|
||||
m_renderStyleCB->currentData().toString(),
|
||||
m_renderCodeBlockStyleCB->currentData().toString(),
|
||||
&m_pageLayout,
|
||||
ExportHTMLOption(m_embedStyleCB->isChecked(),
|
||||
m_completeHTMLCB->isChecked(),
|
||||
m_mimeHTMLCB->isChecked()));
|
||||
|
||||
s_lastExportFormat = opt.m_format;
|
||||
s_opt = ExportOption((ExportSource)m_srcCB->currentData().toInt(),
|
||||
(ExportFormat)m_formatCB->currentData().toInt(),
|
||||
(MarkdownConverterType)m_rendererCB->currentData().toInt(),
|
||||
m_renderBgCB->currentData().toString(),
|
||||
m_renderStyleCB->currentData().toString(),
|
||||
m_renderCodeBlockStyleCB->currentData().toString(),
|
||||
m_subfolderCB->isChecked(),
|
||||
ExportPDFOption(&m_pageLayout,
|
||||
m_wkhtmltopdfCB->isChecked(),
|
||||
QDir::toNativeSeparators(m_wkPathEdit->text()),
|
||||
m_wkBackgroundCB->isChecked(),
|
||||
m_wkTableOfContentsCB->isChecked(),
|
||||
(ExportPageNumber)m_wkPageNumberCB->currentData().toInt(),
|
||||
m_wkExtraArgsEdit->text()),
|
||||
ExportHTMLOption(m_embedStyleCB->isChecked(),
|
||||
m_completeHTMLCB->isChecked(),
|
||||
m_mimeHTMLCB->isChecked()));
|
||||
|
||||
m_consoleEdit->clear();
|
||||
appendLogLine(tr("Export to %1.").arg(outputFolder));
|
||||
|
||||
if (opt.m_format == ExportFormat::PDF
|
||||
|| opt.m_format == ExportFormat::HTML) {
|
||||
m_exporter->prepareExport(opt);
|
||||
if (s_opt.m_format == ExportFormat::PDF
|
||||
|| s_opt.m_format == ExportFormat::HTML) {
|
||||
m_exporter->prepareExport(s_opt);
|
||||
|
||||
if (s_opt.m_format == ExportFormat::PDF
|
||||
&& s_opt.m_pdfOpt.m_wkhtmltopdf) {
|
||||
g_config->setWkhtmltopdfPath(s_opt.m_pdfOpt.m_wkPath);
|
||||
g_config->setWkhtmltopdfArgs(s_opt.m_pdfOpt.m_wkExtraArgs);
|
||||
|
||||
if (!checkWkhtmltopdfExecutable(s_opt.m_pdfOpt.m_wkPath)) {
|
||||
m_inExport = false;
|
||||
m_exportBtn->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
QString msg;
|
||||
|
||||
switch ((int)opt.m_source) {
|
||||
case (int)ExportSource::CurrentNote:
|
||||
ret = doExport(m_file, opt, outputFolder, &msg);
|
||||
switch (s_opt.m_source) {
|
||||
case ExportSource::CurrentNote:
|
||||
ret = doExport(m_file, s_opt, outputFolder, &msg);
|
||||
break;
|
||||
|
||||
case (int)ExportSource::CurrentDirectory:
|
||||
ret = doExport(m_directory, opt, outputFolder, &msg);
|
||||
case ExportSource::CurrentFolder:
|
||||
ret = doExport(m_directory, s_opt, outputFolder, &msg);
|
||||
break;
|
||||
|
||||
case (int)ExportSource::CurrentNotebook:
|
||||
ret = doExport(m_notebook, opt, outputFolder, &msg);
|
||||
case ExportSource::CurrentNotebook:
|
||||
ret = doExport(m_notebook, s_opt, outputFolder, &msg);
|
||||
break;
|
||||
|
||||
case (int)ExportSource::Cart:
|
||||
ret = doExport(m_cart, opt, outputFolder, &msg);
|
||||
case ExportSource::Cart:
|
||||
ret = doExport(m_cart, s_opt, outputFolder, &msg);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -386,7 +550,7 @@ QString VExportDialog::getOutputDirectory() const
|
||||
return m_outputEdit->text();
|
||||
}
|
||||
|
||||
void VExportDialog::handleBrowseBtnClicked()
|
||||
void VExportDialog::handleOutputBrowseBtnClicked()
|
||||
{
|
||||
QString initPath = getOutputDirectory();
|
||||
if (!QFileInfo::exists(initPath)) {
|
||||
@ -405,6 +569,29 @@ void VExportDialog::handleBrowseBtnClicked()
|
||||
}
|
||||
}
|
||||
|
||||
void VExportDialog::handleWkPathBrowseBtnClicked()
|
||||
{
|
||||
QString initPath = m_wkPathEdit->text();
|
||||
if (!QFileInfo::exists(initPath)) {
|
||||
initPath = QCoreApplication::applicationDirPath();
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QString filter = tr("Executable (*.exe)");
|
||||
#else
|
||||
QString filter;
|
||||
#endif
|
||||
|
||||
QString filePath = QFileDialog::getOpenFileName(this,
|
||||
tr("Select wkhtmltopdf Executable"),
|
||||
initPath,
|
||||
filter);
|
||||
|
||||
if (!filePath.isEmpty()) {
|
||||
m_wkPathEdit->setText(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
void VExportDialog::handleInputChanged()
|
||||
{
|
||||
// Source.
|
||||
@ -492,13 +679,15 @@ int VExportDialog::doExport(VDirectory *p_directory,
|
||||
ret += doExport(file, p_opt, outputPath, p_errMsg);
|
||||
}
|
||||
|
||||
// Export subfolder.
|
||||
for (auto const & dir : p_directory->getSubDirs()) {
|
||||
if (!checkUserAction()) {
|
||||
goto exit;
|
||||
}
|
||||
// Export subfolders.
|
||||
if (p_opt.m_processSubfolders) {
|
||||
for (auto const & dir : p_directory->getSubDirs()) {
|
||||
if (!checkUserAction()) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret += doExport(dir, p_opt, outputPath, p_errMsg);
|
||||
ret += doExport(dir, p_opt, outputPath, p_errMsg);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
@ -731,8 +920,9 @@ void VExportDialog::handleLayoutBtnClicked()
|
||||
return;
|
||||
}
|
||||
|
||||
m_pageLayout.setUnits(QPageLayout::Millimeter);
|
||||
m_pageLayout.setPageSize(printer.pageLayout().pageSize());
|
||||
m_pageLayout.setMargins(printer.pageLayout().margins());
|
||||
m_pageLayout.setMargins(printer.pageLayout().margins(QPageLayout::Millimeter));
|
||||
m_pageLayout.setOrientation(printer.pageLayout().orientation());
|
||||
|
||||
updatePageLayoutLabel();
|
||||
@ -741,8 +931,6 @@ void VExportDialog::handleLayoutBtnClicked()
|
||||
|
||||
void VExportDialog::updatePageLayoutLabel()
|
||||
{
|
||||
qDebug() << "page layout margins:" << m_pageLayout.margins();
|
||||
|
||||
m_layoutLabel->setText(QString("%1, %2").arg(m_pageLayout.pageSize().name())
|
||||
.arg(m_pageLayout.orientation() == QPageLayout::Portrait ?
|
||||
tr("Portrait") : tr("Landscape")));
|
||||
@ -771,3 +959,21 @@ void VExportDialog::handleCurrentFormatChanged(int p_index)
|
||||
m_pdfSettings->setVisible(pdfEnabled);
|
||||
m_htmlSettings->setVisible(htmlEnabled);
|
||||
}
|
||||
|
||||
void VExportDialog::handleCurrentSrcChanged(int p_index)
|
||||
{
|
||||
bool subfolderEnabled = false;
|
||||
|
||||
if (p_index >= 0) {
|
||||
switch (m_srcCB->currentData().toInt()) {
|
||||
case (int)ExportSource::CurrentFolder:
|
||||
subfolderEnabled = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_subfolderCB->setVisible(subfolderEnabled);
|
||||
}
|
||||
|
@ -19,12 +19,13 @@ class VFile;
|
||||
class VCart;
|
||||
class VExporter;
|
||||
class QCheckBox;
|
||||
class VLineEdit;
|
||||
|
||||
|
||||
enum class ExportSource
|
||||
{
|
||||
CurrentNote = 0,
|
||||
CurrentDirectory,
|
||||
CurrentFolder,
|
||||
CurrentNotebook,
|
||||
Cart
|
||||
};
|
||||
@ -38,8 +39,24 @@ enum class ExportFormat
|
||||
};
|
||||
|
||||
|
||||
enum class ExportPageNumber
|
||||
{
|
||||
None = 0,
|
||||
Left,
|
||||
Center,
|
||||
Right
|
||||
};
|
||||
|
||||
|
||||
struct ExportHTMLOption
|
||||
{
|
||||
ExportHTMLOption()
|
||||
: m_embedCssStyle(true),
|
||||
m_completeHTML(true),
|
||||
m_mimeHTML(false)
|
||||
{
|
||||
}
|
||||
|
||||
ExportHTMLOption(bool p_embedCssStyle,
|
||||
bool p_completeHTML,
|
||||
bool p_mimeHTML)
|
||||
@ -55,15 +72,62 @@ struct ExportHTMLOption
|
||||
};
|
||||
|
||||
|
||||
struct ExportPDFOption
|
||||
{
|
||||
ExportPDFOption()
|
||||
: m_layout(NULL),
|
||||
m_wkhtmltopdf(false),
|
||||
m_wkEnableBackground(true),
|
||||
m_wkEnableTableOfContents(false),
|
||||
m_wkPageNumber(ExportPageNumber::None)
|
||||
{
|
||||
}
|
||||
|
||||
ExportPDFOption(QPageLayout *p_layout,
|
||||
bool p_wkhtmltopdf,
|
||||
const QString &p_wkPath,
|
||||
bool p_wkEnableBackground,
|
||||
bool p_wkEnableTableOfContents,
|
||||
ExportPageNumber p_wkPageNumber,
|
||||
const QString &p_wkExtraArgs)
|
||||
: m_layout(p_layout),
|
||||
m_wkhtmltopdf(p_wkhtmltopdf),
|
||||
m_wkPath(p_wkPath),
|
||||
m_wkEnableBackground(p_wkEnableBackground),
|
||||
m_wkEnableTableOfContents(p_wkEnableTableOfContents),
|
||||
m_wkPageNumber(p_wkPageNumber),
|
||||
m_wkExtraArgs(p_wkExtraArgs)
|
||||
{
|
||||
}
|
||||
|
||||
QPageLayout *m_layout;
|
||||
bool m_wkhtmltopdf;
|
||||
QString m_wkPath;
|
||||
bool m_wkEnableBackground;
|
||||
bool m_wkEnableTableOfContents;
|
||||
ExportPageNumber m_wkPageNumber;
|
||||
QString m_wkExtraArgs;
|
||||
};
|
||||
|
||||
|
||||
struct ExportOption
|
||||
{
|
||||
ExportOption()
|
||||
: m_source(ExportSource::CurrentNote),
|
||||
m_format(ExportFormat::Markdown),
|
||||
m_renderer(MarkdownConverterType::MarkdownIt),
|
||||
m_processSubfolders(false)
|
||||
{
|
||||
}
|
||||
|
||||
ExportOption(ExportSource p_source,
|
||||
ExportFormat p_format,
|
||||
MarkdownConverterType p_renderer,
|
||||
const QString &p_renderBg,
|
||||
const QString &p_renderStyle,
|
||||
const QString &p_renderCodeBlockStyle,
|
||||
QPageLayout *p_layout,
|
||||
bool p_processSubfolders,
|
||||
const ExportPDFOption &p_pdfOpt,
|
||||
const ExportHTMLOption &p_htmlOpt)
|
||||
: m_source(p_source),
|
||||
m_format(p_format),
|
||||
@ -71,7 +135,8 @@ struct ExportOption
|
||||
m_renderBg(p_renderBg),
|
||||
m_renderStyle(p_renderStyle),
|
||||
m_renderCodeBlockStyle(p_renderCodeBlockStyle),
|
||||
m_layout(p_layout),
|
||||
m_processSubfolders(p_processSubfolders),
|
||||
m_pdfOpt(p_pdfOpt),
|
||||
m_htmlOpt(p_htmlOpt)
|
||||
{
|
||||
}
|
||||
@ -85,7 +150,11 @@ struct ExportOption
|
||||
|
||||
QString m_renderStyle;
|
||||
QString m_renderCodeBlockStyle;
|
||||
QPageLayout *m_layout;
|
||||
|
||||
// Whether process subfolders recursively when source is CurrentFolder.
|
||||
bool m_processSubfolders;
|
||||
|
||||
ExportPDFOption m_pdfOpt;
|
||||
|
||||
ExportHTMLOption m_htmlOpt;
|
||||
};
|
||||
@ -105,7 +174,9 @@ public:
|
||||
private slots:
|
||||
void startExport();
|
||||
|
||||
void handleBrowseBtnClicked();
|
||||
void handleOutputBrowseBtnClicked();
|
||||
|
||||
void handleWkPathBrowseBtnClicked();
|
||||
|
||||
void handleInputChanged();
|
||||
|
||||
@ -113,6 +184,8 @@ private slots:
|
||||
|
||||
void handleCurrentFormatChanged(int p_index);
|
||||
|
||||
void handleCurrentSrcChanged(int p_index);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
|
||||
@ -120,6 +193,8 @@ private:
|
||||
|
||||
QWidget *setupHTMLAdvancedSettings();
|
||||
|
||||
QWidget *setupGeneralAdvancedSettings();
|
||||
|
||||
void initUIFields(MarkdownConverterType p_renderer);
|
||||
|
||||
QString getOutputDirectory() const;
|
||||
@ -167,6 +242,8 @@ private:
|
||||
|
||||
void updatePageLayoutLabel();
|
||||
|
||||
bool checkWkhtmltopdfExecutable(const QString &p_file);
|
||||
|
||||
QComboBox *m_srcCB;
|
||||
|
||||
QComboBox *m_formatCB;
|
||||
@ -181,8 +258,6 @@ private:
|
||||
|
||||
VLineEdit *m_outputEdit;
|
||||
|
||||
QPushButton *m_browseBtn;
|
||||
|
||||
QGroupBox *m_basicBox;
|
||||
|
||||
QGroupBox *m_settingBox;
|
||||
@ -191,6 +266,8 @@ private:
|
||||
|
||||
QWidget *m_htmlSettings;
|
||||
|
||||
QWidget *m_generalSettings;
|
||||
|
||||
QPlainTextEdit *m_consoleEdit;
|
||||
|
||||
QDialogButtonBox *m_btnBox;
|
||||
@ -201,12 +278,28 @@ private:
|
||||
|
||||
QLabel *m_layoutLabel;
|
||||
|
||||
QCheckBox *m_wkhtmltopdfCB;
|
||||
|
||||
VLineEdit *m_wkPathEdit;
|
||||
|
||||
QPushButton *m_wkPathBrowseBtn;
|
||||
|
||||
QCheckBox *m_wkBackgroundCB;
|
||||
|
||||
QCheckBox *m_wkTableOfContentsCB;
|
||||
|
||||
QComboBox *m_wkPageNumberCB;
|
||||
|
||||
VLineEdit *m_wkExtraArgsEdit;
|
||||
|
||||
QCheckBox *m_embedStyleCB;
|
||||
|
||||
QCheckBox *m_completeHTMLCB;;
|
||||
|
||||
QCheckBox *m_mimeHTMLCB;
|
||||
|
||||
QCheckBox *m_subfolderCB;
|
||||
|
||||
VNotebook *m_notebook;
|
||||
|
||||
VDirectory *m_directory;
|
||||
@ -229,8 +322,7 @@ private:
|
||||
// Last output folder path.
|
||||
static QString s_lastOutputFolder;
|
||||
|
||||
// Last export format.
|
||||
static ExportFormat s_lastExportFormat;
|
||||
static ExportOption s_opt;
|
||||
};
|
||||
|
||||
#endif // VEXPORTDIALOG_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="CSS_PLACE_HOLDER">
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<polygon fill="#4D5765" points="128,192 256,320 384,192 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 548 B |
@ -226,6 +226,7 @@ button_icon_danger_fg=@danger_icon_fg
|
||||
combobox_border=@border_bg
|
||||
combobox_fg=@content_fg
|
||||
combobox_bg=@content_bg
|
||||
combobox_disabled_fg=@disabled_fg
|
||||
combobox_view_border=@border_bg
|
||||
combobox_view_selected_bg=@selected_bg
|
||||
combobox_view_selected_fg=@selected_fg
|
||||
@ -252,6 +253,7 @@ label_titlelabel_bg=@title_bg
|
||||
lineedit_border=@border_bg
|
||||
lineedit_fg=@edit_fg
|
||||
lineedit_bg=@edit_bg
|
||||
lineedit_disabled_fg=@disabled_fg
|
||||
lineedit_focus_bg=@edit_focus_bg
|
||||
lineedit_focus_border=@edit_focus_border
|
||||
lineedit_selection_fg=@edit_selection_fg
|
||||
|
@ -521,6 +521,10 @@ QComboBox {
|
||||
border: 1px solid @combobox_border;
|
||||
}
|
||||
|
||||
QComboBox:disabled {
|
||||
color: @combobox_disabled_fg;
|
||||
}
|
||||
|
||||
QComboBox:focus, QComboBox:on {
|
||||
background-color: @combobox_focus_bg;
|
||||
border: 2px solid @combobox_focus_border;
|
||||
@ -540,6 +544,12 @@ QComboBox::down-arrow {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
QComboBox::down-arrow:disabled {
|
||||
image: url(arrow_dropdown_disabled.svg);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
padding: 2px;
|
||||
border: 1px solid @combobox_view_border;
|
||||
@ -697,6 +707,10 @@ QLineEdit:focus {
|
||||
background: @lineedit_focus_bg;
|
||||
}
|
||||
|
||||
QLineEdit:disabled {
|
||||
color: @lineedit_disabled_fg;
|
||||
}
|
||||
|
||||
QLineEdit[VimCommandLine="true"] {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
|
9
src/resources/themes/v_pure/arrow_dropdown_disabled.svg
Normal file
9
src/resources/themes/v_pure/arrow_dropdown_disabled.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<polygon fill="#C0C0C0" points="128,192 256,320 384,192 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 548 B |
@ -220,6 +220,7 @@ buttonmenuitem_decoration_text_fg=@master_dark_bg
|
||||
combobox_border=@border_bg
|
||||
combobox_fg=@content_fg
|
||||
combobox_bg=@content_bg
|
||||
combobox_disabled_fg=@disabled_fg
|
||||
combobox_view_border=@border_bg
|
||||
combobox_view_selected_bg=@selected_bg
|
||||
combobox_view_selected_fg=@selected_fg
|
||||
@ -246,6 +247,7 @@ label_titlelabel_bg=@title_bg
|
||||
lineedit_border=@border_bg
|
||||
lineedit_fg=@edit_fg
|
||||
lineedit_bg=@edit_bg
|
||||
lineedit_disabled_fg=@disabled_fg
|
||||
lineedit_focus_bg=@edit_focus_bg
|
||||
lineedit_focus_border=@edit_focus_border
|
||||
lineedit_selection_fg=@edit_selection_fg
|
||||
|
@ -521,6 +521,10 @@ QComboBox {
|
||||
border: 1px solid @combobox_border;
|
||||
}
|
||||
|
||||
QComboBox:disabled {
|
||||
color: @combobox_disabled_fg;
|
||||
}
|
||||
|
||||
QComboBox:focus, QComboBox:on {
|
||||
background-color: @combobox_focus_bg;
|
||||
border: 2px solid @combobox_focus_border;
|
||||
@ -540,6 +544,12 @@ QComboBox::down-arrow {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
QComboBox::down-arrow:disabled {
|
||||
image: url(arrow_dropdown_disabled.svg);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
padding: 2px;
|
||||
border: 1px solid @combobox_view_border;
|
||||
@ -697,6 +707,10 @@ QLineEdit:focus {
|
||||
background: @lineedit_focus_bg;
|
||||
}
|
||||
|
||||
QLineEdit:disabled {
|
||||
color: @lineedit_disabled_fg;
|
||||
}
|
||||
|
||||
QLineEdit[VimCommandLine="true"] {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
|
@ -4,6 +4,6 @@
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<polygon points="128,192 256,320 384,192 "/>
|
||||
<polygon points="128,192 256,320 384,192 " fill="#333333"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 533 B After Width: | Height: | Size: 548 B |
9
src/resources/themes/v_white/arrow_dropdown_disabled.svg
Normal file
9
src/resources/themes/v_white/arrow_dropdown_disabled.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<polygon points="128,192 256,320 384,192 " fill="#C0C0C0"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 548 B |
@ -193,6 +193,7 @@ buttonmenuitem_decoration_text_fg=#00796B
|
||||
combobox_border=@border_bg
|
||||
combobox_fg=@content_fg
|
||||
combobox_bg=@content_bg
|
||||
combobox_disabled_fg=@disabled_fg
|
||||
combobox_view_border=@border_bg
|
||||
combobox_view_selected_bg=@selected_bg
|
||||
combobox_view_selected_fg=@selected_fg
|
||||
@ -210,6 +211,7 @@ label_titlelabel_bg=@title_bg
|
||||
lineedit_border=@border_bg
|
||||
lineedit_fg=@content_fg
|
||||
lineedit_bg=@content_bg
|
||||
lineedit_disabled_fg=@disabled_fg
|
||||
lineedit_selection_fg=@selection_fg
|
||||
lineedit_selection_bg=@selection_bg
|
||||
|
||||
|
@ -453,6 +453,10 @@ QComboBox {
|
||||
border: 1px solid @combobox_border;
|
||||
}
|
||||
|
||||
QComboBox:disabled {
|
||||
color: @combobox_disabled_fg;
|
||||
}
|
||||
|
||||
QComboBox:focus {
|
||||
background-color: @combobox_focus_bg;
|
||||
}
|
||||
@ -471,6 +475,12 @@ QComboBox::down-arrow {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
QComboBox::down-arrow:disabled {
|
||||
image: url(arrow_dropdown_disabled.svg);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
padding: 2px;
|
||||
border: 1px solid @combobox_view_border;
|
||||
@ -602,6 +612,10 @@ QLineEdit {
|
||||
selection-background-color: @lineedit_selection_bg;
|
||||
}
|
||||
|
||||
QLineEdit:disabled {
|
||||
color: @lineedit_disabled_fg;
|
||||
}
|
||||
|
||||
QLineEdit[VimCommandLine="true"] {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
|
@ -201,6 +201,14 @@ single_click_close_previous_tab=true
|
||||
; Whether enable auto wildcard match in simple search like list and tree widgets
|
||||
enable_wildcard_in_simple_search=true
|
||||
|
||||
[export]
|
||||
; Path of the wkhtmltopdf tool
|
||||
wkhtmltopdf=wkhtmltopdf
|
||||
|
||||
; Additional arguments to wkhtmltopdf
|
||||
; Double quotes to enclose arguments with spaces
|
||||
wkhtmltopdfArgs=
|
||||
|
||||
[web]
|
||||
; Location and configuration for Mathjax
|
||||
mathjax_javascript=https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_HTMLorMML
|
||||
|
@ -454,6 +454,12 @@ public:
|
||||
bool getEnableAutoSave() const;
|
||||
void setEnableAutoSave(bool p_enabled);
|
||||
|
||||
QString getWkhtmltopdfPath() const;
|
||||
void setWkhtmltopdfPath(const QString &p_path);
|
||||
|
||||
QString getWkhtmltopdfArgs() const;
|
||||
void setWkhtmltopdfArgs(const QString &p_args);
|
||||
|
||||
private:
|
||||
// Look up a config from user and default settings.
|
||||
QVariant getConfigFromSettings(const QString §ion, const QString &key) const;
|
||||
@ -2083,4 +2089,26 @@ inline void VConfigManager::setEnableAutoSave(bool p_enabled)
|
||||
{
|
||||
setConfigToSettings("global", "enable_auto_save", p_enabled);
|
||||
}
|
||||
|
||||
inline QString VConfigManager::getWkhtmltopdfPath() const
|
||||
{
|
||||
return getConfigFromSettings("export",
|
||||
"wkhtmltopdf").toString();
|
||||
}
|
||||
|
||||
inline void VConfigManager::setWkhtmltopdfPath(const QString &p_file)
|
||||
{
|
||||
setConfigToSettings("export", "wkhtmltopdf", p_file);
|
||||
}
|
||||
|
||||
inline QString VConfigManager::getWkhtmltopdfArgs() const
|
||||
{
|
||||
return getConfigFromSettings("export",
|
||||
"wkhtmltopdfArgs").toString();
|
||||
}
|
||||
|
||||
inline void VConfigManager::setWkhtmltopdfArgs(const QString &p_file)
|
||||
{
|
||||
setConfigToSettings("export", "wkhtmltopdfArgs", p_file);
|
||||
}
|
||||
#endif // VCONFIGMANAGER_H
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <QWebChannel>
|
||||
#include <QWebEngineProfile>
|
||||
#include <QRegExp>
|
||||
#include <QProcess>
|
||||
|
||||
#include "vconfigmanager.h"
|
||||
#include "vfile.h"
|
||||
@ -27,6 +28,11 @@ VExporter::VExporter(QWidget *p_parent)
|
||||
{
|
||||
}
|
||||
|
||||
static QString marginToStrMM(qreal p_margin)
|
||||
{
|
||||
return QString("%1mm").arg(p_margin);
|
||||
}
|
||||
|
||||
void VExporter::prepareExport(const ExportOption &p_opt)
|
||||
{
|
||||
m_htmlTemplate = VUtils::generateHtmlTemplate(p_opt.m_renderer,
|
||||
@ -37,7 +43,100 @@ void VExporter::prepareExport(const ExportOption &p_opt)
|
||||
|
||||
m_exportHtmlTemplate = VUtils::generateExportHtmlTemplate(p_opt.m_renderBg);
|
||||
|
||||
m_pageLayout = *(p_opt.m_layout);
|
||||
m_pageLayout = *(p_opt.m_pdfOpt.m_layout);
|
||||
|
||||
prepareWKArguments(p_opt.m_pdfOpt);
|
||||
}
|
||||
|
||||
// From QProcess code.
|
||||
static QStringList parseCombinedArgString(const QString &program)
|
||||
{
|
||||
QStringList args;
|
||||
QString tmp;
|
||||
int quoteCount = 0;
|
||||
bool inQuote = false;
|
||||
|
||||
// handle quoting. tokens can be surrounded by double quotes
|
||||
// "hello world". three consecutive double quotes represent
|
||||
// the quote character itself.
|
||||
for (int i = 0; i < program.size(); ++i) {
|
||||
if (program.at(i) == QLatin1Char('"')) {
|
||||
++quoteCount;
|
||||
if (quoteCount == 3) {
|
||||
// third consecutive quote
|
||||
quoteCount = 0;
|
||||
tmp += program.at(i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (quoteCount) {
|
||||
if (quoteCount == 1)
|
||||
inQuote = !inQuote;
|
||||
quoteCount = 0;
|
||||
}
|
||||
if (!inQuote && program.at(i).isSpace()) {
|
||||
if (!tmp.isEmpty()) {
|
||||
args += tmp;
|
||||
tmp.clear();
|
||||
}
|
||||
} else {
|
||||
tmp += program.at(i);
|
||||
}
|
||||
}
|
||||
if (!tmp.isEmpty())
|
||||
args += tmp;
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
void VExporter::prepareWKArguments(const ExportPDFOption &p_opt)
|
||||
{
|
||||
m_wkArgs.clear();
|
||||
m_wkArgs << "--quiet";
|
||||
m_wkArgs << "--encoding" << "utf-8";
|
||||
m_wkArgs << "--page-size" << m_pageLayout.pageSize().key();
|
||||
m_wkArgs << "--orientation"
|
||||
<< (m_pageLayout.orientation() == QPageLayout::Portrait ? "Portrait" : "Landscape");
|
||||
|
||||
QMarginsF marginsMM = m_pageLayout.margins(QPageLayout::Millimeter);
|
||||
m_wkArgs << "--margin-bottom" << marginToStrMM(marginsMM.bottom());
|
||||
m_wkArgs << "--margin-left" << marginToStrMM(marginsMM.left());
|
||||
m_wkArgs << "--margin-right" << marginToStrMM(marginsMM.right());
|
||||
m_wkArgs << "--margin-top" << marginToStrMM(marginsMM.top());
|
||||
|
||||
m_wkArgs << (p_opt.m_wkEnableBackground ? "--background" : "--no-background");
|
||||
|
||||
QString footer;
|
||||
switch (p_opt.m_wkPageNumber) {
|
||||
case ExportPageNumber::Left:
|
||||
footer = "--footer-left";
|
||||
break;
|
||||
|
||||
case ExportPageNumber::Center:
|
||||
footer = "--footer-center";
|
||||
break;
|
||||
|
||||
case ExportPageNumber::Right:
|
||||
footer = "--footer-right";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!footer.isEmpty()) {
|
||||
m_wkArgs << footer << "[page]"
|
||||
<< "--footer-spacing" << QString::number(marginsMM.bottom() / 3, 'f', 2);
|
||||
}
|
||||
|
||||
// Append additional arguments.
|
||||
if (!p_opt.m_wkExtraArgs.isEmpty()) {
|
||||
m_wkArgs.append(parseCombinedArgString(p_opt.m_wkExtraArgs));
|
||||
}
|
||||
|
||||
if (p_opt.m_wkEnableTableOfContents) {
|
||||
m_wkArgs << "toc" << "--toc-text-size-shrink" << "1.0";
|
||||
}
|
||||
}
|
||||
|
||||
bool VExporter::exportPDF(VFile *p_file,
|
||||
@ -149,6 +248,81 @@ bool VExporter::exportToPDF(VWebView *p_webViewer,
|
||||
return pdfPrinted == 1;
|
||||
}
|
||||
|
||||
bool VExporter::exportToPDFViaWK(VDocument *p_webDocument,
|
||||
const ExportPDFOption &p_opt,
|
||||
const QString &p_filePath,
|
||||
QString *p_errMsg)
|
||||
{
|
||||
int pdfExported = 0;
|
||||
|
||||
connect(p_webDocument, &VDocument::htmlContentFinished,
|
||||
this, [&, this](const QString &p_headContent,
|
||||
const QString &p_styleContent,
|
||||
const QString &p_bodyContent) {
|
||||
if (p_bodyContent.isEmpty() || this->m_state == ExportState::Cancelled) {
|
||||
pdfExported = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(!p_filePath.isEmpty());
|
||||
QString htmlPath = p_filePath + ".vnote.html";
|
||||
|
||||
QFile file(htmlPath);
|
||||
if (!file.open(QFile::WriteOnly)) {
|
||||
pdfExported = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
QString resFolder = QFileInfo(htmlPath).completeBaseName() + "_files";
|
||||
QString resFolderPath = QDir(VUtils::basePathFromPath(htmlPath)).filePath(resFolder);
|
||||
|
||||
qDebug() << "temp HTML files folder" << resFolderPath;
|
||||
|
||||
QString html(m_exportHtmlTemplate);
|
||||
if (!p_styleContent.isEmpty()) {
|
||||
QString content(p_styleContent);
|
||||
fixStyleResources(resFolderPath, content);
|
||||
html.replace(HtmlHolder::c_styleHolder, content);
|
||||
}
|
||||
|
||||
if (!p_headContent.isEmpty()) {
|
||||
html.replace(HtmlHolder::c_headHolder, p_headContent);
|
||||
}
|
||||
|
||||
QString content(p_bodyContent);
|
||||
fixBodyResources(m_baseUrl, resFolderPath, content);
|
||||
html.replace(HtmlHolder::c_bodyHolder, content);
|
||||
|
||||
file.write(html.toUtf8());
|
||||
file.close();
|
||||
|
||||
// Convert vis wkhtmltopdf.
|
||||
if (!htmlToPDFViaWK(htmlPath, p_filePath, p_opt, p_errMsg)) {
|
||||
pdfExported = -1;
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
VUtils::deleteFile(htmlPath);
|
||||
VUtils::deleteDirectory(resFolderPath);
|
||||
|
||||
if (pdfExported == 0) {
|
||||
pdfExported = 1;
|
||||
}
|
||||
});
|
||||
|
||||
p_webDocument->getHtmlContentAsync();
|
||||
|
||||
while (pdfExported == 0) {
|
||||
VUtils::sleepWait(100);
|
||||
|
||||
if (m_state == ExportState::Cancelled) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pdfExported == 1;
|
||||
}
|
||||
|
||||
bool VExporter::exportViaWebView(VFile *p_file,
|
||||
const ExportOption &p_opt,
|
||||
const QString &p_outputFile,
|
||||
@ -195,9 +369,17 @@ bool VExporter::exportViaWebView(VFile *p_file,
|
||||
bool exportRet = false;
|
||||
switch (p_opt.m_format) {
|
||||
case ExportFormat::PDF:
|
||||
exportRet = exportToPDF(m_webViewer,
|
||||
p_outputFile,
|
||||
m_pageLayout);
|
||||
if (p_opt.m_pdfOpt.m_wkhtmltopdf) {
|
||||
exportRet = exportToPDFViaWK(m_webDocument,
|
||||
p_opt.m_pdfOpt,
|
||||
p_outputFile,
|
||||
p_errMsg);
|
||||
} else {
|
||||
exportRet = exportToPDF(m_webViewer,
|
||||
p_outputFile,
|
||||
m_pageLayout);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ExportFormat::HTML:
|
||||
@ -261,7 +443,6 @@ bool VExporter::exportToHTML(VDocument *p_webDocument,
|
||||
Q_ASSERT(!p_filePath.isEmpty());
|
||||
|
||||
QFile file(p_filePath);
|
||||
|
||||
if (!file.open(QFile::WriteOnly)) {
|
||||
htmlExported = -1;
|
||||
return;
|
||||
@ -421,3 +602,55 @@ void VExporter::handleDownloadRequested(QWebEngineDownloadItem *p_item)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static QString combineArgs(QStringList &p_args)
|
||||
{
|
||||
QString str;
|
||||
for (const QString &arg : p_args) {
|
||||
QString tmp;
|
||||
if (arg.contains(' ')) {
|
||||
tmp = '"' + arg + '"';
|
||||
} else {
|
||||
tmp = arg;
|
||||
}
|
||||
|
||||
if (str.isEmpty()) {
|
||||
str = tmp;
|
||||
} else {
|
||||
str = str + ' ' + tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool VExporter::htmlToPDFViaWK(const QString &p_htmlFile,
|
||||
const QString &p_filePath,
|
||||
const ExportPDFOption &p_opt,
|
||||
QString *p_errMsg)
|
||||
{
|
||||
// Note: system's locale settings (Language for non-Unicode programs) is important to wkhtmltopdf.
|
||||
// Input file could be encoded via QUrl::fromLocalFile(p_htmlFile).toString(QUrl::EncodeUnicode) to
|
||||
// handle non-ASCII path.
|
||||
QStringList args(m_wkArgs);
|
||||
args << QDir::toNativeSeparators(p_htmlFile);
|
||||
args << QDir::toNativeSeparators(p_filePath);
|
||||
QString cmd = p_opt.m_wkPath + " " + combineArgs(args);
|
||||
emit outputLog(cmd);
|
||||
int ret = QProcess::execute(p_opt.m_wkPath, args);
|
||||
qDebug() << "wkhtmltopdf returned" << ret << cmd;
|
||||
switch (ret) {
|
||||
case -2:
|
||||
VUtils::addErrMsg(p_errMsg, tr("Fail to start wkhtmltopdf (%1).").arg(cmd));
|
||||
break;
|
||||
|
||||
case -1:
|
||||
VUtils::addErrMsg(p_errMsg, tr("wkhtmltopdf crashed (%1).").arg(cmd));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <QPageLayout>
|
||||
#include <QUrl>
|
||||
#include <QWebEngineDownloadItem>
|
||||
#include <QStringList>
|
||||
|
||||
#include "dialog/vexportdialog.h"
|
||||
|
||||
@ -14,6 +15,7 @@ class VDocument;
|
||||
|
||||
class VExporter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VExporter(QWidget *p_parent = nullptr);
|
||||
|
||||
@ -29,6 +31,10 @@ public:
|
||||
const QString &p_outputFile,
|
||||
QString *p_errMsg = NULL);
|
||||
|
||||
signals:
|
||||
// Request to output log.
|
||||
void outputLog(const QString &p_log);
|
||||
|
||||
private slots:
|
||||
void handleLogicsFinished();
|
||||
|
||||
@ -76,6 +82,11 @@ private:
|
||||
const QString &p_filePath,
|
||||
const QPageLayout &p_layout);
|
||||
|
||||
bool exportToPDFViaWK(VDocument *p_webDocument,
|
||||
const ExportPDFOption &p_opt,
|
||||
const QString &p_filePath,
|
||||
QString *p_errMsg = NULL);
|
||||
|
||||
bool exportToHTML(VDocument *p_webDocument,
|
||||
const ExportHTMLOption &p_opt,
|
||||
const QString &p_filePath);
|
||||
@ -84,6 +95,12 @@ private:
|
||||
const ExportHTMLOption &p_opt,
|
||||
const QString &p_filePath);
|
||||
|
||||
bool htmlToPDFViaWK(const QString &p_htmlFile,
|
||||
const QString &p_filePath,
|
||||
const ExportPDFOption &p_opt,
|
||||
QString *p_errMsg = NULL);
|
||||
|
||||
void prepareWKArguments(const ExportPDFOption &p_opt);
|
||||
|
||||
// Fix @p_html's resources like url("...") with "file" or "qrc" schema.
|
||||
// Copy the resource to @p_folder and fix the url string.
|
||||
@ -119,6 +136,9 @@ private:
|
||||
|
||||
// Download state used for MIME HTML.
|
||||
QWebEngineDownloadItem::DownloadState m_downloadState;
|
||||
|
||||
// Arguments for wkhtmltopdf.
|
||||
QStringList m_wkArgs;
|
||||
};
|
||||
|
||||
inline void VExporter::clearNoteState()
|
||||
|
@ -240,5 +240,8 @@
|
||||
<file>resources/themes/v_pure/v_pure_mermaid.css</file>
|
||||
<file>resources/themes/v_white/v_white_mermaid.css</file>
|
||||
<file>resources/themes/v_moonlight/v_moonlight_mermaid.css</file>
|
||||
<file>resources/themes/v_moonlight/arrow_dropdown_disabled.svg</file>
|
||||
<file>resources/themes/v_pure/arrow_dropdown_disabled.svg</file>
|
||||
<file>resources/themes/v_white/arrow_dropdown_disabled.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Loading…
x
Reference in New Issue
Block a user