diff --git a/src/dialog/vexportdialog.cpp b/src/dialog/vexportdialog.cpp index 6c5abc28..781df008 100644 --- a/src/dialog/vexportdialog.cpp +++ b/src/dialog/vexportdialog.cpp @@ -215,9 +215,20 @@ QWidget *VExportDialog::setupHTMLAdvancedSettings() "the original page")); 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(); advLayout->addRow(m_embedStyleCB); advLayout->addRow(m_completeHTMLCB); + advLayout->addRow(m_mimeHTMLCB); advLayout->setContentsMargins(0, 0, 0, 0); @@ -311,8 +322,9 @@ void VExportDialog::startExport() m_renderStyleCB->currentData().toString(), m_renderCodeBlockStyleCB->currentData().toString(), &m_pageLayout, - m_embedStyleCB->isChecked(), - m_completeHTMLCB->isChecked()); + ExportHTMLOption(m_embedStyleCB->isChecked(), + m_completeHTMLCB->isChecked(), + m_mimeHTMLCB->isChecked())); s_lastExportFormat = opt.m_format; @@ -683,7 +695,7 @@ int VExportDialog::doExportHTML(VFile *p_file, } // Get output file. - QString suffix = ".html"; + QString suffix = p_opt.m_htmlOpt.m_mimeHTML ? ".mht" : ".html"; QString name = VUtils::getFileNameWithSequence(p_outputFolder, QFileInfo(p_file->getName()).completeBaseName() + suffix); QString outputPath = QDir(p_outputFolder).filePath(name); diff --git a/src/dialog/vexportdialog.h b/src/dialog/vexportdialog.h index e91629f8..49e2f13c 100644 --- a/src/dialog/vexportdialog.h +++ b/src/dialog/vexportdialog.h @@ -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 { ExportOption(ExportSource p_source, @@ -47,8 +64,7 @@ struct ExportOption const QString &p_renderStyle, const QString &p_renderCodeBlockStyle, QPageLayout *p_layout, - bool p_embedCssStyle, - bool p_completeHTML) + const ExportHTMLOption &p_htmlOpt) : m_source(p_source), m_format(p_format), m_renderer(p_renderer), @@ -56,8 +72,7 @@ struct ExportOption m_renderStyle(p_renderStyle), m_renderCodeBlockStyle(p_renderCodeBlockStyle), m_layout(p_layout), - m_embedCssStyle(p_embedCssStyle), - m_completeHTML(p_completeHTML) + m_htmlOpt(p_htmlOpt) { } @@ -72,8 +87,7 @@ struct ExportOption QString m_renderCodeBlockStyle; QPageLayout *m_layout; - bool m_embedCssStyle; - bool m_completeHTML; + ExportHTMLOption m_htmlOpt; }; @@ -191,6 +205,8 @@ private: QCheckBox *m_completeHTMLCB;; + QCheckBox *m_mimeHTMLCB; + VNotebook *m_notebook; VDirectory *m_directory; diff --git a/src/resources/themes/v_moonlight/v_moonlight.palette b/src/resources/themes/v_moonlight/v_moonlight.palette index 3c3c2397..964d391a 100644 --- a/src/resources/themes/v_moonlight/v_moonlight.palette +++ b/src/resources/themes/v_moonlight/v_moonlight.palette @@ -7,7 +7,7 @@ mdhl_file=v_moonlight.mdhl css_file=v_moonlight.css codeblock_css_file=v_moonlight_codeblock.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 ; 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 ; CheckBox. +checkbox_disabled_fg=@disabled_fg checkbox_indicator_hover_bg=@hover_bg checkbox_indicator_pressed_bg=@pressed_bg diff --git a/src/resources/themes/v_moonlight/v_moonlight.qss b/src/resources/themes/v_moonlight/v_moonlight.qss index 9c1641e3..d915d0d9 100644 --- a/src/resources/themes/v_moonlight/v_moonlight.qss +++ b/src/resources/themes/v_moonlight/v_moonlight.qss @@ -1114,6 +1114,10 @@ QCheckBox { spacing: 5px; } +QCheckBox:disabled { + color: @checkbox_disabled_fg; +} + QCheckBox::indicator { width: 20px; height: 20px; diff --git a/src/resources/themes/v_pure/v_pure.palette b/src/resources/themes/v_pure/v_pure.palette index 077e3b52..7b9cdc14 100644 --- a/src/resources/themes/v_pure/v_pure.palette +++ b/src/resources/themes/v_pure/v_pure.palette @@ -7,7 +7,7 @@ mdhl_file=v_pure.mdhl css_file=v_pure.css codeblock_css_file=v_pure_codeblock.css mermaid_css_file=v_pure_mermaid.css -version=4 +version=5 [phony] ; Abstract color attributes. @@ -322,6 +322,7 @@ editwindow_corner_icon_fg=@master_bg editwindow_corner_icon_inactive_fg=#D3D3D3 ; CheckBox. +checkbox_disabled_fg=@disabled_fg checkbox_indicator_hover_bg=@hover_bg checkbox_indicator_pressed_bg=@pressed_bg diff --git a/src/resources/themes/v_pure/v_pure.qss b/src/resources/themes/v_pure/v_pure.qss index 2b0d6bd2..13550aae 100644 --- a/src/resources/themes/v_pure/v_pure.qss +++ b/src/resources/themes/v_pure/v_pure.qss @@ -1117,6 +1117,10 @@ QCheckBox { spacing: 5px; } +QCheckBox:disabled { + color: @checkbox_disabled_fg; +} + QCheckBox::indicator { width: 20px; height: 20px; diff --git a/src/resources/themes/v_white/v_white.palette b/src/resources/themes/v_white/v_white.palette index 206fca5e..f9e96975 100644 --- a/src/resources/themes/v_white/v_white.palette +++ b/src/resources/themes/v_white/v_white.palette @@ -7,7 +7,7 @@ mdhl_file=v_white.mdhl css_file=v_white.css codeblock_css_file=v_white_codeblock.css mermaid_css_file=v_white_mermaid.css -version=4 +version=5 [phony] ; Abstract color attributes. @@ -287,6 +287,7 @@ editwindow_corner_icon_fg=@icon_fg editwindow_corner_icon_inactive_fg=#808080 ; CheckBox. +checkbox_disabled_fg=@disabled_fg checkbox_indicator_hover_bg=@hover_bg checkbox_indicator_pressed_bg=@pressed_bg diff --git a/src/resources/themes/v_white/v_white.qss b/src/resources/themes/v_white/v_white.qss index b37f7e25..a388995b 100644 --- a/src/resources/themes/v_white/v_white.qss +++ b/src/resources/themes/v_white/v_white.qss @@ -1003,6 +1003,10 @@ QCheckBox { spacing: 5px; } +QCheckBox:disabled { + color: @checkbox_disabled_fg; +} + QCheckBox::indicator { width: 20px; height: 20px; diff --git a/src/vexporter.cpp b/src/vexporter.cpp index 914323e4..7cee8ad2 100644 --- a/src/vexporter.cpp +++ b/src/vexporter.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "vconfigmanager.h" @@ -64,9 +65,10 @@ void VExporter::initWebViewer(VFile *p_file, const ExportOption &p_opt) VPreviewPage *page = new VPreviewPage(m_webViewer); m_webViewer->setPage(page); - connect(page, &VPreviewPage::loadFinished, this, &VExporter::handleLoadFinished); + connect(page->profile(), &QWebEngineProfile::downloadRequested, + this, &VExporter::handleDownloadRequested); m_webDocument = new VDocument(p_file, m_webViewer); connect(m_webDocument, &VDocument::logicsFinished, @@ -199,11 +201,16 @@ bool VExporter::exportViaWebView(VFile *p_file, break; case ExportFormat::HTML: - exportRet = exportToHTML(m_webViewer, - m_webDocument, - p_opt.m_embedCssStyle, - p_opt.m_completeHTML, - p_outputFile); + if (p_opt.m_htmlOpt.m_mimeHTML) { + exportRet = exportToMHTML(m_webViewer, + p_opt.m_htmlOpt, + p_outputFile); + } else { + exportRet = exportToHTML(m_webDocument, + p_opt.m_htmlOpt, + p_outputFile); + } + break; default: @@ -236,13 +243,10 @@ exit: return ret; } -bool VExporter::exportToHTML(VWebView *p_webViewer, - VDocument *p_webDocument, - bool p_embedCssStyle, - bool p_completeHTML, +bool VExporter::exportToHTML(VDocument *p_webDocument, + const ExportHTMLOption &p_opt, const QString &p_filePath) { - Q_UNUSED(p_webViewer); int htmlExported = 0; connect(p_webDocument, &VDocument::htmlContentFinished, @@ -269,7 +273,7 @@ bool VExporter::exportToHTML(VWebView *p_webViewer, qDebug() << "HTML files folder" << resFolderPath; QString html(m_exportHtmlTemplate); - if (!p_styleContent.isEmpty() && p_embedCssStyle) { + if (!p_styleContent.isEmpty() && p_opt.m_embedCssStyle) { QString content(p_styleContent); fixStyleResources(resFolderPath, content); html.replace(HtmlHolder::c_styleHolder, content); @@ -279,7 +283,7 @@ bool VExporter::exportToHTML(VWebView *p_webViewer, html.replace(HtmlHolder::c_headHolder, p_headContent); } - if (p_completeHTML) { + if (p_opt.m_completeHTML) { QString content(p_bodyContent); fixBodyResources(m_baseUrl, resFolderPath, content); html.replace(HtmlHolder::c_bodyHolder, content); @@ -389,3 +393,29 @@ QString VExporter::getResourceRelativePath(const QString &p_file) Q_ASSERT(idx > 0 && idx2 < idx); 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; + }); + } +} diff --git a/src/vexporter.h b/src/vexporter.h index 08e72845..07a96ff3 100644 --- a/src/vexporter.h +++ b/src/vexporter.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "dialog/vexportdialog.h" @@ -33,6 +34,8 @@ private slots: void handleLoadFinished(bool p_ok); + void handleDownloadRequested(QWebEngineDownloadItem *p_item); + private: enum class ExportState { @@ -73,12 +76,15 @@ private: const QString &p_filePath, const QPageLayout &p_layout); - bool exportToHTML(VWebView *p_webViewer, - VDocument *p_webDocument, - bool p_embedCssStyle, - bool p_completeHTML, + bool exportToHTML(VDocument *p_webDocument, + const ExportHTMLOption &p_opt, 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. // Copy the resource to @p_folder and fix the url string. static bool fixStyleResources(const QString &p_folder, @@ -110,6 +116,9 @@ private: NoteState m_noteState; ExportState m_state; + + // Download state used for MIME HTML. + QWebEngineDownloadItem::DownloadState m_downloadState; }; inline void VExporter::clearNoteState()