export: support MHTML format

This commit is contained in:
Le Tan 2018-03-01 20:19:20 +08:00
parent 28765bf4bb
commit bccc0b28db
10 changed files with 111 additions and 29 deletions

View File

@ -215,9 +215,20 @@ QWidget *VExportDialog::setupHTMLAdvancedSettings()
"the original page")); "the original page"));
m_completeHTMLCB->setChecked(true); m_completeHTMLCB->setChecked(true);
// Mime HTML.
m_mimeHTMLCB = new QCheckBox(tr("MIME HTML"), this);
m_mimeHTMLCB->setToolTip(tr("Export as a complete web page in MIME HTML format"));
connect(m_mimeHTMLCB, &QCheckBox::stateChanged,
this, [this](int p_state) {
bool checked = p_state == Qt::Checked;
m_embedStyleCB->setEnabled(!checked);
m_completeHTMLCB->setEnabled(!checked);
});
QFormLayout *advLayout = new QFormLayout(); QFormLayout *advLayout = new QFormLayout();
advLayout->addRow(m_embedStyleCB); advLayout->addRow(m_embedStyleCB);
advLayout->addRow(m_completeHTMLCB); advLayout->addRow(m_completeHTMLCB);
advLayout->addRow(m_mimeHTMLCB);
advLayout->setContentsMargins(0, 0, 0, 0); advLayout->setContentsMargins(0, 0, 0, 0);
@ -311,8 +322,9 @@ void VExportDialog::startExport()
m_renderStyleCB->currentData().toString(), m_renderStyleCB->currentData().toString(),
m_renderCodeBlockStyleCB->currentData().toString(), m_renderCodeBlockStyleCB->currentData().toString(),
&m_pageLayout, &m_pageLayout,
m_embedStyleCB->isChecked(), ExportHTMLOption(m_embedStyleCB->isChecked(),
m_completeHTMLCB->isChecked()); m_completeHTMLCB->isChecked(),
m_mimeHTMLCB->isChecked()));
s_lastExportFormat = opt.m_format; s_lastExportFormat = opt.m_format;
@ -683,7 +695,7 @@ int VExportDialog::doExportHTML(VFile *p_file,
} }
// Get output file. // Get output file.
QString suffix = ".html"; QString suffix = p_opt.m_htmlOpt.m_mimeHTML ? ".mht" : ".html";
QString name = VUtils::getFileNameWithSequence(p_outputFolder, QString name = VUtils::getFileNameWithSequence(p_outputFolder,
QFileInfo(p_file->getName()).completeBaseName() + suffix); QFileInfo(p_file->getName()).completeBaseName() + suffix);
QString outputPath = QDir(p_outputFolder).filePath(name); QString outputPath = QDir(p_outputFolder).filePath(name);

View File

@ -38,6 +38,23 @@ enum class ExportFormat
}; };
struct ExportHTMLOption
{
ExportHTMLOption(bool p_embedCssStyle,
bool p_completeHTML,
bool p_mimeHTML)
: m_embedCssStyle(p_embedCssStyle),
m_completeHTML(p_completeHTML),
m_mimeHTML(p_mimeHTML)
{
}
bool m_embedCssStyle;
bool m_completeHTML;
bool m_mimeHTML;
};
struct ExportOption struct ExportOption
{ {
ExportOption(ExportSource p_source, ExportOption(ExportSource p_source,
@ -47,8 +64,7 @@ struct ExportOption
const QString &p_renderStyle, const QString &p_renderStyle,
const QString &p_renderCodeBlockStyle, const QString &p_renderCodeBlockStyle,
QPageLayout *p_layout, QPageLayout *p_layout,
bool p_embedCssStyle, const ExportHTMLOption &p_htmlOpt)
bool p_completeHTML)
: m_source(p_source), : m_source(p_source),
m_format(p_format), m_format(p_format),
m_renderer(p_renderer), m_renderer(p_renderer),
@ -56,8 +72,7 @@ struct ExportOption
m_renderStyle(p_renderStyle), m_renderStyle(p_renderStyle),
m_renderCodeBlockStyle(p_renderCodeBlockStyle), m_renderCodeBlockStyle(p_renderCodeBlockStyle),
m_layout(p_layout), m_layout(p_layout),
m_embedCssStyle(p_embedCssStyle), m_htmlOpt(p_htmlOpt)
m_completeHTML(p_completeHTML)
{ {
} }
@ -72,8 +87,7 @@ struct ExportOption
QString m_renderCodeBlockStyle; QString m_renderCodeBlockStyle;
QPageLayout *m_layout; QPageLayout *m_layout;
bool m_embedCssStyle; ExportHTMLOption m_htmlOpt;
bool m_completeHTML;
}; };
@ -191,6 +205,8 @@ private:
QCheckBox *m_completeHTMLCB;; QCheckBox *m_completeHTMLCB;;
QCheckBox *m_mimeHTMLCB;
VNotebook *m_notebook; VNotebook *m_notebook;
VDirectory *m_directory; VDirectory *m_directory;

View File

@ -7,7 +7,7 @@ mdhl_file=v_moonlight.mdhl
css_file=v_moonlight.css css_file=v_moonlight.css
codeblock_css_file=v_moonlight_codeblock.css codeblock_css_file=v_moonlight_codeblock.css
mermaid_css_file=v_moonlight_mermaid.css mermaid_css_file=v_moonlight_mermaid.css
version=4 version=5
; This mapping will be used to translate colors when the content of HTML is copied ; This mapping will be used to translate colors when the content of HTML is copied
; without background. You could just specify the foreground colors mapping here. ; without background. You could just specify the foreground colors mapping here.
@ -329,6 +329,7 @@ editwindow_corner_icon_fg=@master_bg
editwindow_corner_icon_inactive_fg=@icon_fg editwindow_corner_icon_inactive_fg=@icon_fg
; CheckBox. ; CheckBox.
checkbox_disabled_fg=@disabled_fg
checkbox_indicator_hover_bg=@hover_bg checkbox_indicator_hover_bg=@hover_bg
checkbox_indicator_pressed_bg=@pressed_bg checkbox_indicator_pressed_bg=@pressed_bg

View File

@ -1114,6 +1114,10 @@ QCheckBox {
spacing: 5px; spacing: 5px;
} }
QCheckBox:disabled {
color: @checkbox_disabled_fg;
}
QCheckBox::indicator { QCheckBox::indicator {
width: 20px; width: 20px;
height: 20px; height: 20px;

View File

@ -7,7 +7,7 @@ mdhl_file=v_pure.mdhl
css_file=v_pure.css css_file=v_pure.css
codeblock_css_file=v_pure_codeblock.css codeblock_css_file=v_pure_codeblock.css
mermaid_css_file=v_pure_mermaid.css mermaid_css_file=v_pure_mermaid.css
version=4 version=5
[phony] [phony]
; Abstract color attributes. ; Abstract color attributes.
@ -322,6 +322,7 @@ editwindow_corner_icon_fg=@master_bg
editwindow_corner_icon_inactive_fg=#D3D3D3 editwindow_corner_icon_inactive_fg=#D3D3D3
; CheckBox. ; CheckBox.
checkbox_disabled_fg=@disabled_fg
checkbox_indicator_hover_bg=@hover_bg checkbox_indicator_hover_bg=@hover_bg
checkbox_indicator_pressed_bg=@pressed_bg checkbox_indicator_pressed_bg=@pressed_bg

View File

@ -1117,6 +1117,10 @@ QCheckBox {
spacing: 5px; spacing: 5px;
} }
QCheckBox:disabled {
color: @checkbox_disabled_fg;
}
QCheckBox::indicator { QCheckBox::indicator {
width: 20px; width: 20px;
height: 20px; height: 20px;

View File

@ -7,7 +7,7 @@ mdhl_file=v_white.mdhl
css_file=v_white.css css_file=v_white.css
codeblock_css_file=v_white_codeblock.css codeblock_css_file=v_white_codeblock.css
mermaid_css_file=v_white_mermaid.css mermaid_css_file=v_white_mermaid.css
version=4 version=5
[phony] [phony]
; Abstract color attributes. ; Abstract color attributes.
@ -287,6 +287,7 @@ editwindow_corner_icon_fg=@icon_fg
editwindow_corner_icon_inactive_fg=#808080 editwindow_corner_icon_inactive_fg=#808080
; CheckBox. ; CheckBox.
checkbox_disabled_fg=@disabled_fg
checkbox_indicator_hover_bg=@hover_bg checkbox_indicator_hover_bg=@hover_bg
checkbox_indicator_pressed_bg=@pressed_bg checkbox_indicator_pressed_bg=@pressed_bg

View File

@ -1003,6 +1003,10 @@ QCheckBox {
spacing: 5px; spacing: 5px;
} }
QCheckBox:disabled {
color: @checkbox_disabled_fg;
}
QCheckBox::indicator { QCheckBox::indicator {
width: 20px; width: 20px;
height: 20px; height: 20px;

View File

@ -3,6 +3,7 @@
#include <QDebug> #include <QDebug>
#include <QWidget> #include <QWidget>
#include <QWebChannel> #include <QWebChannel>
#include <QWebEngineProfile>
#include <QRegExp> #include <QRegExp>
#include "vconfigmanager.h" #include "vconfigmanager.h"
@ -64,9 +65,10 @@ void VExporter::initWebViewer(VFile *p_file, const ExportOption &p_opt)
VPreviewPage *page = new VPreviewPage(m_webViewer); VPreviewPage *page = new VPreviewPage(m_webViewer);
m_webViewer->setPage(page); m_webViewer->setPage(page);
connect(page, &VPreviewPage::loadFinished, connect(page, &VPreviewPage::loadFinished,
this, &VExporter::handleLoadFinished); this, &VExporter::handleLoadFinished);
connect(page->profile(), &QWebEngineProfile::downloadRequested,
this, &VExporter::handleDownloadRequested);
m_webDocument = new VDocument(p_file, m_webViewer); m_webDocument = new VDocument(p_file, m_webViewer);
connect(m_webDocument, &VDocument::logicsFinished, connect(m_webDocument, &VDocument::logicsFinished,
@ -199,11 +201,16 @@ bool VExporter::exportViaWebView(VFile *p_file,
break; break;
case ExportFormat::HTML: case ExportFormat::HTML:
exportRet = exportToHTML(m_webViewer, if (p_opt.m_htmlOpt.m_mimeHTML) {
m_webDocument, exportRet = exportToMHTML(m_webViewer,
p_opt.m_embedCssStyle, p_opt.m_htmlOpt,
p_opt.m_completeHTML, p_outputFile);
p_outputFile); } else {
exportRet = exportToHTML(m_webDocument,
p_opt.m_htmlOpt,
p_outputFile);
}
break; break;
default: default:
@ -236,13 +243,10 @@ exit:
return ret; return ret;
} }
bool VExporter::exportToHTML(VWebView *p_webViewer, bool VExporter::exportToHTML(VDocument *p_webDocument,
VDocument *p_webDocument, const ExportHTMLOption &p_opt,
bool p_embedCssStyle,
bool p_completeHTML,
const QString &p_filePath) const QString &p_filePath)
{ {
Q_UNUSED(p_webViewer);
int htmlExported = 0; int htmlExported = 0;
connect(p_webDocument, &VDocument::htmlContentFinished, connect(p_webDocument, &VDocument::htmlContentFinished,
@ -269,7 +273,7 @@ bool VExporter::exportToHTML(VWebView *p_webViewer,
qDebug() << "HTML files folder" << resFolderPath; qDebug() << "HTML files folder" << resFolderPath;
QString html(m_exportHtmlTemplate); QString html(m_exportHtmlTemplate);
if (!p_styleContent.isEmpty() && p_embedCssStyle) { if (!p_styleContent.isEmpty() && p_opt.m_embedCssStyle) {
QString content(p_styleContent); QString content(p_styleContent);
fixStyleResources(resFolderPath, content); fixStyleResources(resFolderPath, content);
html.replace(HtmlHolder::c_styleHolder, content); html.replace(HtmlHolder::c_styleHolder, content);
@ -279,7 +283,7 @@ bool VExporter::exportToHTML(VWebView *p_webViewer,
html.replace(HtmlHolder::c_headHolder, p_headContent); html.replace(HtmlHolder::c_headHolder, p_headContent);
} }
if (p_completeHTML) { if (p_opt.m_completeHTML) {
QString content(p_bodyContent); QString content(p_bodyContent);
fixBodyResources(m_baseUrl, resFolderPath, content); fixBodyResources(m_baseUrl, resFolderPath, content);
html.replace(HtmlHolder::c_bodyHolder, content); html.replace(HtmlHolder::c_bodyHolder, content);
@ -389,3 +393,29 @@ QString VExporter::getResourceRelativePath(const QString &p_file)
Q_ASSERT(idx > 0 && idx2 < idx); Q_ASSERT(idx > 0 && idx2 < idx);
return "." + p_file.mid(idx2); return "." + p_file.mid(idx2);
} }
bool VExporter::exportToMHTML(VWebView *p_webViewer,
const ExportHTMLOption &p_opt,
const QString &p_filePath)
{
m_downloadState = QWebEngineDownloadItem::DownloadRequested;
p_webViewer->page()->save(p_filePath, QWebEngineDownloadItem::MimeHtmlSaveFormat);
while (m_downloadState == QWebEngineDownloadItem::DownloadRequested
|| m_downloadState == QWebEngineDownloadItem::DownloadInProgress) {
VUtils::sleepWait(100);
}
return m_downloadState == QWebEngineDownloadItem::DownloadCompleted;
}
void VExporter::handleDownloadRequested(QWebEngineDownloadItem *p_item)
{
if (p_item->savePageFormat() == QWebEngineDownloadItem::MimeHtmlSaveFormat) {
connect(p_item, &QWebEngineDownloadItem::stateChanged,
this, [this](QWebEngineDownloadItem::DownloadState p_state) {
m_downloadState = p_state;
});
}
}

View File

@ -4,6 +4,7 @@
#include <QObject> #include <QObject>
#include <QPageLayout> #include <QPageLayout>
#include <QUrl> #include <QUrl>
#include <QWebEngineDownloadItem>
#include "dialog/vexportdialog.h" #include "dialog/vexportdialog.h"
@ -33,6 +34,8 @@ private slots:
void handleLoadFinished(bool p_ok); void handleLoadFinished(bool p_ok);
void handleDownloadRequested(QWebEngineDownloadItem *p_item);
private: private:
enum class ExportState enum class ExportState
{ {
@ -73,12 +76,15 @@ private:
const QString &p_filePath, const QString &p_filePath,
const QPageLayout &p_layout); const QPageLayout &p_layout);
bool exportToHTML(VWebView *p_webViewer, bool exportToHTML(VDocument *p_webDocument,
VDocument *p_webDocument, const ExportHTMLOption &p_opt,
bool p_embedCssStyle,
bool p_completeHTML,
const QString &p_filePath); const QString &p_filePath);
bool exportToMHTML(VWebView *p_webViewer,
const ExportHTMLOption &p_opt,
const QString &p_filePath);
// Fix @p_html's resources like url("...") with "file" or "qrc" schema. // Fix @p_html's resources like url("...") with "file" or "qrc" schema.
// Copy the resource to @p_folder and fix the url string. // Copy the resource to @p_folder and fix the url string.
static bool fixStyleResources(const QString &p_folder, static bool fixStyleResources(const QString &p_folder,
@ -110,6 +116,9 @@ private:
NoteState m_noteState; NoteState m_noteState;
ExportState m_state; ExportState m_state;
// Download state used for MIME HTML.
QWebEngineDownloadItem::DownloadState m_downloadState;
}; };
inline void VExporter::clearNoteState() inline void VExporter::clearNoteState()