소스 검색

export: support MHTML format

Le Tan 7 년 전
부모
커밋
bccc0b28db

+ 15 - 3
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);

+ 22 - 6
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;

+ 2 - 1
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
 

+ 4 - 0
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;

+ 2 - 1
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
 

+ 4 - 0
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;

+ 2 - 1
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
 

+ 4 - 0
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;

+ 43 - 13
src/vexporter.cpp

@@ -3,6 +3,7 @@
 #include <QDebug>
 #include <QWidget>
 #include <QWebChannel>
+#include <QWebEngineProfile>
 #include <QRegExp>
 
 #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;
+                });
+    }
+}

+ 13 - 4
src/vexporter.h

@@ -4,6 +4,7 @@
 #include <QObject>
 #include <QPageLayout>
 #include <QUrl>
+#include <QWebEngineDownloadItem>
 
 #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()