From 10e2bba7f6b3e00fee364002693be9d869416222 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Wed, 11 Apr 2018 19:53:42 +0800 Subject: [PATCH] support Mermaid and Flowchart.js preview Mermaid preview is disabled for some issues. --- src/resources/export_template.html | 2 +- src/resources/markdown_template.html | 2 +- src/resources/markdown_template.js | 4 +- src/resources/mathjax_preview.js | 118 +++++++++++++++++- src/resources/mathjax_preview_template.html | 4 + .../themes/v_moonlight/v_moonlight.css | 2 + src/resources/themes/v_native/v_native.css | 2 + src/resources/themes/v_pure/v_pure.css | 2 + src/resources/vnote.ini | 2 +- src/utils/vutils.cpp | 24 +++- src/vconstants.h | 4 +- src/vdocument.cpp | 4 +- src/vdocument.h | 10 +- src/vgraphvizhelper.cpp | 13 +- src/vgraphvizhelper.h | 6 +- src/vlivepreviewhelper.cpp | 78 ++++++++---- src/vlivepreviewhelper.h | 12 +- src/vmathjaxpreviewhelper.cpp | 35 +++++- src/vmathjaxpreviewhelper.h | 24 +++- src/vmathjaxwebdocument.cpp | 28 ++++- src/vmathjaxwebdocument.h | 35 +++++- src/vmdtab.cpp | 2 + src/vnote.cpp | 10 ++ src/vnotebook.cpp | 2 + src/vplantumlhelper.cpp | 16 ++- src/vplantumlhelper.h | 9 +- src/vpreviewmanager.cpp | 37 ++++++ src/vpreviewmanager.h | 4 + src/vtextblockdata.cpp | 3 +- 29 files changed, 418 insertions(+), 76 deletions(-) diff --git a/src/resources/export_template.html b/src/resources/export_template.html index b4858078..1e1b6a00 100644 --- a/src/resources/export_template.html +++ b/src/resources/export_template.html @@ -3,7 +3,7 @@ + diff --git a/src/resources/themes/v_moonlight/v_moonlight.css b/src/resources/themes/v_moonlight/v_moonlight.css index fbe2dc2b..b2ae00c6 100644 --- a/src/resources/themes/v_moonlight/v_moonlight.css +++ b/src/resources/themes/v_moonlight/v_moonlight.css @@ -171,6 +171,7 @@ div.mermaid-diagram { } div.flowchart-diagram { + padding: 0px 5px 0px 5px; margin: 16px 0px 16px 0px; width: fit-content; overflow: hidden; @@ -179,6 +180,7 @@ div.flowchart-diagram { } div.plantuml-diagram { + padding: 5px 5px 0px 5px; margin: 16px 0px 16px 0px; width: fit-content; overflow: hidden; diff --git a/src/resources/themes/v_native/v_native.css b/src/resources/themes/v_native/v_native.css index e6384320..2d53807d 100644 --- a/src/resources/themes/v_native/v_native.css +++ b/src/resources/themes/v_native/v_native.css @@ -174,12 +174,14 @@ div.mermaid-diagram { } div.flowchart-diagram { + padding: 0px 5px 0px 5px; margin: 16px 0px 16px 0px; width: fit-content; overflow: hidden; } div.plantuml-diagram { + padding: 5px 5px 0px 5px; margin: 16px 0px 16px 0px; width: fit-content; overflow: hidden; diff --git a/src/resources/themes/v_pure/v_pure.css b/src/resources/themes/v_pure/v_pure.css index b414fb90..1e4574d6 100644 --- a/src/resources/themes/v_pure/v_pure.css +++ b/src/resources/themes/v_pure/v_pure.css @@ -175,12 +175,14 @@ div.mermaid-diagram { } div.flowchart-diagram { + padding: 0px 5px 0px 5px; margin: 16px 0px 16px 0px; width: fit-content; overflow: hidden; } div.plantuml-diagram { + padding: 5px 5px 0px 5px; margin: 16px 0px 16px 0px; width: fit-content; overflow: hidden; diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 60e3567f..61fbed10 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -38,7 +38,7 @@ markdown_converter=2 enable_mermaid=false ; Enable MathJax -enable_mathjax=true +enable_mathjax=false ; Enable Flowchart.js enable_flowchart=false diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index 8520c9f1..144b0c44 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -818,19 +818,31 @@ QString VUtils::generateExportHtmlTemplate(const QString &p_renderBg, bool p_inc QString VUtils::generateMathJaxPreviewTemplate() { QString templ = VNote::generateMathJaxPreviewTemplate(); - 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")); - - templ.replace(HtmlHolder::c_JSHolder, mj); + templ.replace(HtmlHolder::c_JSHolder, g_config->getMathjaxJavascript()); QString extraFile; + + QString mathjaxScale = QString::number((int)(100 * VUtils::calculateScaleFactor())); + + /* + // Mermaid. + extraFile += "getMermaidCssStyleUrl() + "\"/>\n" + + "\n"; + */ + + // Flowchart. + extraFile += "\n" + + "\n"; + + // MathJax. extraFile += "\n"; diff --git a/src/vconstants.h b/src/vconstants.h index 69315849..c9c36baa 100644 --- a/src/vconstants.h +++ b/src/vconstants.h @@ -4,6 +4,8 @@ #include #include +typedef unsigned long long TimeStamp; + // Html: rich text file; // Markdown: Markdown text file; // List: Infinite list file like WorkFlowy; @@ -38,7 +40,7 @@ namespace HtmlHolder static const QString c_JSHolder = "JS_PLACE_HOLDER"; static const QString c_cssHolder = "CSS_PLACE_HOLDER"; static const QString c_codeBlockCssHolder = "HIGHLIGHTJS_CSS_PLACE_HOLDER"; - static const QString c_globalStyleHolder = "/* BACKGROUND_PLACE_HOLDER */"; + static const QString c_globalStyleHolder = "/* STYLE_GLOBAL_PLACE_HOLDER */"; static const QString c_extraHolder = ""; static const QString c_bodyHolder = ""; static const QString c_headHolder = ""; diff --git a/src/vdocument.cpp b/src/vdocument.cpp index ef0e3b14..af5df365 100644 --- a/src/vdocument.cpp +++ b/src/vdocument.cpp @@ -147,7 +147,7 @@ void VDocument::processPlantUML(int p_id, const QString &p_format, const QString this, &VDocument::plantUMLResultReady); } - m_plantUMLHelper->processAsync(p_id, p_format, p_text); + m_plantUMLHelper->processAsync(p_id, 0, p_format, p_text); } void VDocument::processGraphviz(int p_id, const QString &p_format, const QString &p_text) @@ -158,7 +158,7 @@ void VDocument::processGraphviz(int p_id, const QString &p_format, const QString this, &VDocument::graphvizResultReady); } - m_graphvizHelper->processAsync(p_id, p_format, p_text); + m_graphvizHelper->processAsync(p_id, 0, p_format, p_text); } void VDocument::setPreviewEnabled(bool p_enabled) diff --git a/src/vdocument.h b/src/vdocument.h index 651a0805..e60a273e 100644 --- a/src/vdocument.h +++ b/src/vdocument.h @@ -142,9 +142,15 @@ signals: void wordCountInfoUpdated(); - void plantUMLResultReady(int p_id, const QString &p_format, const QString &p_result); + void plantUMLResultReady(int p_id, + unsigned long long p_timeStamp, + const QString &p_format, + const QString &p_result); - void graphvizResultReady(int p_id, const QString &p_format, const QString &p_result); + void graphvizResultReady(int p_id, + unsigned long long p_timeStamp, + const QString &p_format, + const QString &p_result); void requestPreviewEnabled(bool p_enabled); diff --git a/src/vgraphvizhelper.cpp b/src/vgraphvizhelper.cpp index a26bc4b7..f8272372 100644 --- a/src/vgraphvizhelper.cpp +++ b/src/vgraphvizhelper.cpp @@ -9,6 +9,7 @@ extern VConfigManager *g_config; #define TaskIdProperty "GraphvizTaskId" #define TaskFormatProperty "GraphvizTaskFormat" +#define TaskTimeStampProperty "GraphvizTaskTimeStamp" VGraphvizHelper::VGraphvizHelper(QObject *p_parent) : QObject(p_parent) @@ -16,10 +17,11 @@ VGraphvizHelper::VGraphvizHelper(QObject *p_parent) prepareCommand(m_program, m_args); } -void VGraphvizHelper::processAsync(int p_id, const QString &p_format, const QString &p_text) +void VGraphvizHelper::processAsync(int p_id, TimeStamp p_timeStamp, const QString &p_format, const QString &p_text) { QProcess *process = new QProcess(this); process->setProperty(TaskIdProperty, p_id); + process->setProperty(TaskTimeStampProperty, p_timeStamp); process->setProperty(TaskFormatProperty, p_format); connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(handleProcessFinished(int, QProcess::ExitStatus))); @@ -51,7 +53,8 @@ void VGraphvizHelper::handleProcessFinished(int p_exitCode, QProcess::ExitStatus QProcess *process = static_cast(sender()); int id = process->property(TaskIdProperty).toInt(); QString format = process->property(TaskFormatProperty).toString(); - qDebug() << "process finished" << id << format << p_exitCode << p_exitStatus; + TimeStamp timeStamp = process->property(TaskTimeStampProperty).toULongLong(); + qDebug() << "process finished" << id << timeStamp << format << p_exitCode << p_exitStatus; bool failed = true; if (p_exitStatus == QProcess::NormalExit) { if (p_exitCode < 0) { @@ -60,9 +63,9 @@ void VGraphvizHelper::handleProcessFinished(int p_exitCode, QProcess::ExitStatus failed = false; QByteArray outBa = process->readAllStandardOutput(); if (format == "svg") { - emit resultReady(id, format, QString::fromLocal8Bit(outBa)); + emit resultReady(id, timeStamp, format, QString::fromLocal8Bit(outBa)); } else { - emit resultReady(id, format, QString::fromLocal8Bit(outBa.toBase64())); + emit resultReady(id, timeStamp, format, QString::fromLocal8Bit(outBa.toBase64())); } } } else { @@ -76,7 +79,7 @@ void VGraphvizHelper::handleProcessFinished(int p_exitCode, QProcess::ExitStatus qWarning() << "Graphviz stderr:" << errStr; } - emit resultReady(id, format, ""); + emit resultReady(id, timeStamp, format, ""); } process->deleteLater(); diff --git a/src/vgraphvizhelper.h b/src/vgraphvizhelper.h index ac49c12c..ae2b2bf8 100644 --- a/src/vgraphvizhelper.h +++ b/src/vgraphvizhelper.h @@ -6,18 +6,20 @@ #include #include +#include "vconstants.h" + class VGraphvizHelper : public QObject { Q_OBJECT public: explicit VGraphvizHelper(QObject *p_parent = nullptr); - void processAsync(int p_id, const QString &p_format, const QString &p_text); + void processAsync(int p_id, TimeStamp p_timeStamp, const QString &p_format, const QString &p_text); void prepareCommand(QString &p_cmd, QStringList &p_args) const; signals: - void resultReady(int p_id, const QString &p_format, const QString &p_result); + void resultReady(int p_id, TimeStamp p_timeStamp, const QString &p_format, const QString &p_result); private slots: void handleProcessFinished(int p_exitCode, QProcess::ExitStatus p_exitStatus); diff --git a/src/vlivepreviewhelper.cpp b/src/vlivepreviewhelper.cpp index 15488c37..b71c4a6b 100644 --- a/src/vlivepreviewhelper.cpp +++ b/src/vlivepreviewhelper.cpp @@ -42,6 +42,7 @@ CodeBlockPreviewInfo::CodeBlockPreviewInfo(const VCodeBlock &p_cb) void CodeBlockPreviewInfo::clearImageData() { m_imgData.clear(); + m_imgDataBa.clear(); m_inplacePreview.clear(); } @@ -64,7 +65,6 @@ void CodeBlockPreviewInfo::updateNonContent(const QTextDocument *p_doc, } } -// Update inplace preview according to m_imgData. void CodeBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor, const QTextDocument *p_doc) { @@ -100,12 +100,12 @@ VLivePreviewHelper::VLivePreviewHelper(VEditor *p_editor, m_livePreviewEnabled(false), m_inplacePreviewEnabled(false), m_graphvizHelper(NULL), - m_plantUMLHelper(NULL) + m_plantUMLHelper(NULL), + m_lastInplacePreviewSize(0), + m_timeStamp(0) { connect(m_editor->object(), &VEditorObject::cursorPositionChanged, this, &VLivePreviewHelper::handleCursorPositionChanged); - connect(m_document, &VDocument::codeBlockPreviewReady, - this, &VLivePreviewHelper::webAsyncResultReady); m_flowchartEnabled = g_config->getEnableFlowchart(); m_mermaidEnabled = g_config->getEnableMermaid(); @@ -117,6 +117,9 @@ VLivePreviewHelper::VLivePreviewHelper(VEditor *p_editor, m_mathJaxID = m_mathJaxHelper->registerIdentifier(); connect(m_mathJaxHelper, &VMathJaxPreviewHelper::mathjaxPreviewResultReady, this, &VLivePreviewHelper::mathjaxPreviewResultReady); + connect(m_mathJaxHelper, &VMathJaxPreviewHelper::diagramPreviewResultReady, + // The same handle logics. + this, &VLivePreviewHelper::mathjaxPreviewResultReady); } bool VLivePreviewHelper::isPreviewLang(const QString &p_lang) const @@ -134,6 +137,8 @@ void VLivePreviewHelper::updateCodeBlocks(const QVector &p_codeBlock return; } + ++m_timeStamp; + int lastIndex = m_cbIndex; m_cbIndex = -1; int cursorBlock = m_editor->textCursorW().block().blockNumber(); @@ -239,6 +244,7 @@ void VLivePreviewHelper::updateLivePreview() if (!cb.hasImageData()) { m_graphvizHelper->processAsync(m_cbIndex | LANG_PREFIX_GRAPHVIZ | TYPE_LIVE_PREVIEW, + m_timeStamp, "svg", removeFence(vcb.m_text)); } else { @@ -253,6 +259,7 @@ void VLivePreviewHelper::updateLivePreview() if (!cb.hasImageData()) { m_plantUMLHelper->processAsync(m_cbIndex | LANG_PREFIX_PLANTUML | TYPE_LIVE_PREVIEW, + m_timeStamp, "svg", removeFence(vcb.m_text)); } else { @@ -292,13 +299,20 @@ void VLivePreviewHelper::setInplacePreviewEnabled(bool p_enabled) for (auto & cb : m_codeBlocks) { cb.clearImageData(); } + + updateInplacePreview(); } } void VLivePreviewHelper::localAsyncResultReady(int p_id, + TimeStamp p_timeStamp, const QString &p_format, const QString &p_result) { + if (p_timeStamp != m_timeStamp) { + return; + } + Q_UNUSED(p_format); Q_ASSERT(p_format == "svg"); int idx = p_id & INDEX_MASK; @@ -354,6 +368,7 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx) updateInplacePreview(); } else { m_graphvizHelper->processAsync(p_idx | LANG_PREFIX_GRAPHVIZ | TYPE_INPLACE_PREVIEW, + m_timeStamp, "svg", removeFence(vcb.m_text)); } @@ -369,43 +384,66 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx) updateInplacePreview(); } else { m_plantUMLHelper->processAsync(p_idx | LANG_PREFIX_PLANTUML | TYPE_INPLACE_PREVIEW, + m_timeStamp, "svg", removeFence(vcb.m_text)); } } else if (vcb.m_lang == "flow" || vcb.m_lang == "flowchart") { - m_document->previewCodeBlock(p_idx, - vcb.m_lang, - removeFence(vcb.m_text), - false); + m_mathJaxHelper->previewDiagram(m_mathJaxID, + p_idx, + m_timeStamp, + vcb.m_lang, + removeFence(vcb.m_text)); } else if (vcb.m_lang == "mathjax") { m_mathJaxHelper->previewMathJax(m_mathJaxID, p_idx, + m_timeStamp, removeFence(vcb.m_text)); } } void VLivePreviewHelper::updateInplacePreview() { + QSet blocks; QVector > images; for (int i = 0; i < m_codeBlocks.size(); ++i) { CodeBlockPreviewInfo &cb = m_codeBlocks[i]; if (cb.inplacePreviewReady()) { // Generate the image. + bool valid = false; if (cb.hasImageData()) { cb.inplacePreview()->m_image.loadFromData(cb.imageData().toUtf8(), cb.imageFormat().toLocal8Bit().data()); images.append(cb.inplacePreview()); + valid = true; } else if (cb.hasImageDataBa()) { cb.inplacePreview()->m_image.loadFromData(cb.imageDataBa(), cb.imageFormat().toLocal8Bit().data()); images.append(cb.inplacePreview()); + valid = true; } + + if (!valid) { + blocks.insert(cb.inplacePreview()->m_blockNumber); + } + } else { + blocks.insert(cb.codeBlock().m_endBlock); } } + if (images.isEmpty() && m_lastInplacePreviewSize == 0) { + return; + } + emit inplacePreviewCodeBlockUpdated(images); + m_lastInplacePreviewSize = images.size(); + + if (!blocks.isEmpty()) { + emit checkBlocksForObsoletePreview(blocks.toList()); + } + // Clear image. for (int i = 0; i < m_codeBlocks.size(); ++i) { CodeBlockPreviewInfo &cb = m_codeBlocks[i]; @@ -416,28 +454,18 @@ void VLivePreviewHelper::updateInplacePreview() } } -void VLivePreviewHelper::webAsyncResultReady(int p_id, - const QString &p_lang, - const QString &p_result) -{ - Q_UNUSED(p_lang); - if (p_id >= m_codeBlocks.size() || p_result.isEmpty()) { - return; - } - - CodeBlockPreviewInfo &cb = m_codeBlocks[p_id]; - cb.setImageData(QStringLiteral("svg"), p_result); - cb.updateInplacePreview(m_editor, m_doc); - updateInplacePreview(); -} - void VLivePreviewHelper::mathjaxPreviewResultReady(int p_identitifer, int p_id, + TimeStamp p_timeStamp, const QString &p_format, const QByteArray &p_data) { - if (p_identitifer != m_mathJaxID - || (p_id >= m_codeBlocks.size() || p_data.isEmpty())) { + if (p_identitifer != m_mathJaxID || p_timeStamp != m_timeStamp) { + return; + } + + if (p_id >= m_codeBlocks.size() || p_data.isEmpty()) { + updateInplacePreview(); return; } diff --git a/src/vlivepreviewhelper.h b/src/vlivepreviewhelper.h index 3c609c68..f26b8445 100644 --- a/src/vlivepreviewhelper.h +++ b/src/vlivepreviewhelper.h @@ -6,6 +6,7 @@ #include "hgmarkdownhighlighter.h" #include "vpreviewmanager.h" +#include "vconstants.h" class VEditor; class VDocument; @@ -133,18 +134,19 @@ public: public slots: void updateCodeBlocks(const QVector &p_codeBlocks); - void webAsyncResultReady(int p_id, const QString &p_lang, const QString &p_result); - signals: void inplacePreviewCodeBlockUpdated(const QVector > &p_images); + void checkBlocksForObsoletePreview(const QList &p_blocks); + private slots: void handleCursorPositionChanged(); - void localAsyncResultReady(int p_id, const QString &p_format, const QString &p_result); + void localAsyncResultReady(int p_id, TimeStamp p_timeStamp, const QString &p_format, const QString &p_result); void mathjaxPreviewResultReady(int p_identitifer, int p_id, + TimeStamp p_timeStamp, const QString &p_format, const QByteArray &p_data); @@ -187,6 +189,10 @@ private: // Identification for VMathJaxPreviewHelper. int m_mathJaxID; + + int m_lastInplacePreviewSize; + + TimeStamp m_timeStamp; }; inline bool VLivePreviewHelper::isPreviewEnabled() const diff --git a/src/vmathjaxpreviewhelper.cpp b/src/vmathjaxpreviewhelper.cpp index 3ac4307e..6fd9ead9 100644 --- a/src/vmathjaxpreviewhelper.cpp +++ b/src/vmathjaxpreviewhelper.cpp @@ -24,6 +24,7 @@ VMathJaxPreviewHelper::~VMathJaxPreviewHelper() void VMathJaxPreviewHelper::doInit() { Q_ASSERT(!m_initialized); + m_initialized = true; m_webView = new QWebEngineView(m_parentWidget); connect(m_webView, &QWebEngineView::loadFinished, @@ -36,9 +37,23 @@ void VMathJaxPreviewHelper::doInit() m_webDoc = new VMathJaxWebDocument(m_webView); connect(m_webDoc, &VMathJaxWebDocument::mathjaxPreviewResultReady, - this, [this](int p_identifier, int p_id, const QString &p_format, const QString &p_data) { + this, [this](int p_identifier, + int p_id, + TimeStamp p_timeStamp, + const QString &p_format, + const QString &p_data) { QByteArray ba = QByteArray::fromBase64(p_data.toUtf8()); - emit mathjaxPreviewResultReady(p_identifier, p_id, p_format, ba); + emit mathjaxPreviewResultReady(p_identifier, p_id, p_timeStamp, p_format, ba); + }); + + connect(m_webDoc, &VMathJaxWebDocument::diagramPreviewResultReady, + this, [this](int p_identifier, + int p_id, + TimeStamp p_timeStamp, + const QString &p_format, + const QString &p_data) { + QByteArray ba = QByteArray::fromBase64(p_data.toUtf8()); + emit diagramPreviewResultReady(p_identifier, p_id, p_timeStamp, p_format, ba); }); QWebChannel *channel = new QWebChannel(m_webView); @@ -50,15 +65,25 @@ void VMathJaxPreviewHelper::doInit() while (!m_webReady) { VUtils::sleepWait(100); } - - m_initialized = true; } void VMathJaxPreviewHelper::previewMathJax(int p_identifier, int p_id, + TimeStamp p_timeStamp, const QString &p_text) { init(); - m_webDoc->previewMathJax(p_identifier, p_id, p_text); + m_webDoc->previewMathJax(p_identifier, p_id, p_timeStamp, p_text); +} + +void VMathJaxPreviewHelper::previewDiagram(int p_identifier, + int p_id, + TimeStamp p_timeStamp, + const QString &p_lang, + const QString &p_text) +{ + init(); + + m_webDoc->previewDiagram(p_identifier, p_id, p_timeStamp, p_lang, p_text); } diff --git a/src/vmathjaxpreviewhelper.h b/src/vmathjaxpreviewhelper.h index 60345653..0d798906 100644 --- a/src/vmathjaxpreviewhelper.h +++ b/src/vmathjaxpreviewhelper.h @@ -3,6 +3,8 @@ #include +#include "vconstants.h" + class QWebEngineView; class VMathJaxWebDocument; class QWidget; @@ -18,15 +20,33 @@ public: // Get an ID for identification. int registerIdentifier(); - // Preview @p_text and return SVG data asynchronously. + // Preview @p_text and return PNG data asynchronously. // @p_identifier: identifier the caller registered; // @p_id: internal id for each caller; // @p_text: raw text of the MathJax script. - void previewMathJax(int p_identifier, int p_id, const QString &p_text); + void previewMathJax(int p_identifier, int p_id, TimeStamp p_timeStamp, const QString &p_text); + + // Preview @p_text and return PNG data asynchronously. + // @p_identifier: identifier the caller registered; + // @p_id: internal id for each caller; + // @p_lang: language of the diagram; + // @p_text: raw text of the script. + void previewDiagram(int p_identifier, + int p_id, + TimeStamp p_timeStamp, + const QString &p_lang, + const QString &p_text); signals: void mathjaxPreviewResultReady(int p_identifier, int p_id, + TimeStamp p_timeStamp, + const QString &p_format, + const QByteArray &p_data); + + void diagramPreviewResultReady(int p_identifier, + int p_id, + TimeStamp p_timeStamp, const QString &p_format, const QByteArray &p_data); diff --git a/src/vmathjaxwebdocument.cpp b/src/vmathjaxwebdocument.cpp index a5599c15..63b4314b 100644 --- a/src/vmathjaxwebdocument.cpp +++ b/src/vmathjaxwebdocument.cpp @@ -9,15 +9,39 @@ VMathJaxWebDocument::VMathJaxWebDocument(QObject *p_parent) void VMathJaxWebDocument::previewMathJax(int p_identifier, int p_id, + TimeStamp p_timeStamp, const QString &p_text) { - emit requestPreviewMathJax(p_identifier, p_id, p_text); + emit requestPreviewMathJax(p_identifier, p_id, p_timeStamp, p_text); } void VMathJaxWebDocument::mathjaxResultReady(int p_identifier, int p_id, + unsigned long long p_timeStamp, const QString &p_format, const QString &p_data) { - emit mathjaxPreviewResultReady(p_identifier, p_id, p_format, p_data); + emit mathjaxPreviewResultReady(p_identifier, p_id, p_timeStamp, p_format, p_data); +} + +void VMathJaxWebDocument::diagramResultReady(int p_identifier, + int p_id, + unsigned long long p_timeStamp, + const QString &p_format, + const QString &p_data) +{ + emit diagramPreviewResultReady(p_identifier, p_id, p_timeStamp, p_format, p_data); +} + +void VMathJaxWebDocument::previewDiagram(int p_identifier, + int p_id, + TimeStamp p_timeStamp, + const QString &p_lang, + const QString &p_text) +{ + emit requestPreviewDiagram(p_identifier, + p_id, + p_timeStamp, + p_lang, + p_text); } diff --git a/src/vmathjaxwebdocument.h b/src/vmathjaxwebdocument.h index 687933ca..66995dd6 100644 --- a/src/vmathjaxwebdocument.h +++ b/src/vmathjaxwebdocument.h @@ -3,27 +3,58 @@ #include +#include "vconstants.h" + class VMathJaxWebDocument : public QObject { Q_OBJECT public: explicit VMathJaxWebDocument(QObject *p_parent = nullptr); - void previewMathJax(int p_identifier, int p_id, const QString &p_text); + void previewMathJax(int p_identifier, int p_id, TimeStamp p_timeStamp, const QString &p_text); + + void previewDiagram(int p_identifier, + int p_id, + TimeStamp p_timeStamp, + const QString &p_lang, + const QString &p_text); public slots: // Will be called in the HTML side void mathjaxResultReady(int p_identifier, int p_id, + unsigned long long p_timeStamp, + const QString &p_format, + const QString &p_data); + + void diagramResultReady(int p_identifier, + int p_id, + unsigned long long p_timeStamp, const QString &p_format, const QString &p_data); signals: - void requestPreviewMathJax(int p_identifier, int p_id, const QString &p_text); + void requestPreviewMathJax(int p_identifier, + int p_id, + unsigned long long p_timeStamp, + const QString &p_text); + + void requestPreviewDiagram(int p_identifier, + int p_id, + unsigned long long p_timeStamp, + const QString &p_lang, + const QString &p_text); void mathjaxPreviewResultReady(int p_identifier, int p_id, + TimeStamp p_timeStamp, + const QString &p_format, + const QString &p_data); + + void diagramPreviewResultReady(int p_identifier, + int p_id, + TimeStamp p_timeStamp, const QString &p_format, const QString &p_data); }; diff --git a/src/vmdtab.cpp b/src/vmdtab.cpp index 07583f3b..330bf1fc 100644 --- a/src/vmdtab.cpp +++ b/src/vmdtab.cpp @@ -523,6 +523,8 @@ void VMdTab::setupMarkdownEditor() m_livePreviewHelper, &VLivePreviewHelper::setInplacePreviewEnabled); connect(m_livePreviewHelper, &VLivePreviewHelper::inplacePreviewCodeBlockUpdated, m_editor->getPreviewManager(), &VPreviewManager::updateCodeBlocks); + connect(m_livePreviewHelper, &VLivePreviewHelper::checkBlocksForObsoletePreview, + m_editor->getPreviewManager(), &VPreviewManager::checkBlocksForObsoletePreview); m_livePreviewHelper->setInplacePreviewEnabled(m_editor->getPreviewManager()->isPreviewEnabled()); } diff --git a/src/vnote.cpp b/src/vnote.cpp index 50ee0df3..0232a4d4 100644 --- a/src/vnote.cpp +++ b/src/vnote.cpp @@ -174,7 +174,17 @@ QString VNote::generateMathJaxPreviewTemplate() const QString c_templatePath(":/resources/mathjax_preview_template.html"); QString templ = VUtils::readFileFromDisk(c_templatePath); g_palette->fillStyle(templ); + + QString cssStyle; + cssStyle += "div.flowchart-diagram { margin: 0px !important; " + " padding: 0px 5px 0px 5px !important; }\n" + "div.mermaid-diagram { margin: 0px !important; " + " padding: 0px 5px 0px 5px !important; }\n"; + + templ.replace(HtmlHolder::c_globalStyleHolder, cssStyle); + templ.replace(HtmlHolder::c_cssHolder, g_config->getCssStyleUrl()); + return templ; } diff --git a/src/vnotebook.cpp b/src/vnotebook.cpp index 95310130..c7b4a1be 100644 --- a/src/vnotebook.cpp +++ b/src/vnotebook.cpp @@ -182,6 +182,8 @@ VNotebook *VNotebook::createNotebook(const QString &p_name, if (!nb->writeToConfig()) { delete nb; return NULL; + } else { + nb->m_valid = true; } return nb; diff --git a/src/vplantumlhelper.cpp b/src/vplantumlhelper.cpp index 9b2e1104..3904526a 100644 --- a/src/vplantumlhelper.cpp +++ b/src/vplantumlhelper.cpp @@ -9,6 +9,7 @@ extern VConfigManager *g_config; #define TaskIdProperty "PlantUMLTaskId" #define TaskFormatProperty "PlantUMLTaskFormat" +#define TaskTimeStampProperty "PlantUMLTaskTimeStamp" VPlantUMLHelper::VPlantUMLHelper(QObject *p_parent) : QObject(p_parent) @@ -16,10 +17,14 @@ VPlantUMLHelper::VPlantUMLHelper(QObject *p_parent) prepareCommand(m_program, m_args); } -void VPlantUMLHelper::processAsync(int p_id, const QString &p_format, const QString &p_text) +void VPlantUMLHelper::processAsync(int p_id, + TimeStamp p_timeStamp, + const QString &p_format, + const QString &p_text) { QProcess *process = new QProcess(this); process->setProperty(TaskIdProperty, p_id); + process->setProperty(TaskTimeStampProperty, p_timeStamp); process->setProperty(TaskFormatProperty, p_format); connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(handleProcessFinished(int, QProcess::ExitStatus))); @@ -58,7 +63,8 @@ void VPlantUMLHelper::handleProcessFinished(int p_exitCode, QProcess::ExitStatus QProcess *process = static_cast(sender()); int id = process->property(TaskIdProperty).toInt(); QString format = process->property(TaskFormatProperty).toString(); - qDebug() << "process finished" << id << format << p_exitCode << p_exitStatus; + TimeStamp timeStamp = process->property(TaskTimeStampProperty).toULongLong(); + qDebug() << "process finished" << id << timeStamp << format << p_exitCode << p_exitStatus; bool failed = true; if (p_exitStatus == QProcess::NormalExit) { if (p_exitCode < 0) { @@ -67,9 +73,9 @@ void VPlantUMLHelper::handleProcessFinished(int p_exitCode, QProcess::ExitStatus failed = false; QByteArray outBa = process->readAllStandardOutput(); if (format == "svg") { - emit resultReady(id, format, QString::fromLocal8Bit(outBa)); + emit resultReady(id, timeStamp, format, QString::fromLocal8Bit(outBa)); } else { - emit resultReady(id, format, QString::fromLocal8Bit(outBa.toBase64())); + emit resultReady(id, timeStamp, format, QString::fromLocal8Bit(outBa.toBase64())); } } } else { @@ -83,7 +89,7 @@ void VPlantUMLHelper::handleProcessFinished(int p_exitCode, QProcess::ExitStatus qWarning() << "PlantUML stderr:" << errStr; } - emit resultReady(id, format, ""); + emit resultReady(id, timeStamp, format, ""); } process->deleteLater(); diff --git a/src/vplantumlhelper.h b/src/vplantumlhelper.h index fa733c5f..b4dd3219 100644 --- a/src/vplantumlhelper.h +++ b/src/vplantumlhelper.h @@ -6,18 +6,23 @@ #include #include +#include "vconstants.h" + class VPlantUMLHelper : public QObject { Q_OBJECT public: explicit VPlantUMLHelper(QObject *p_parent = nullptr); - void processAsync(int p_id, const QString &p_format, const QString &p_text); + void processAsync(int p_id, + TimeStamp p_timeStamp, + const QString &p_format, + const QString &p_text); void prepareCommand(QString &p_cmd, QStringList &p_args) const; signals: - void resultReady(int p_id, const QString &p_format, const QString &p_result); + void resultReady(int p_id, TimeStamp p_timeStamp, const QString &p_format, const QString &p_result); private slots: void handleProcessFinished(int p_exitCode, QProcess::ExitStatus p_exitStatus); diff --git a/src/vpreviewmanager.cpp b/src/vpreviewmanager.cpp index 3c74c617..a8b300da 100644 --- a/src/vpreviewmanager.cpp +++ b/src/vpreviewmanager.cpp @@ -473,3 +473,40 @@ void VPreviewManager::updateCodeBlocks(const QVector &p_blocks) +{ + if (p_blocks.isEmpty()) { + return; + } + + QSet affectedBlocks; + for (auto i : p_blocks) { + QTextBlock block = m_document->findBlockByNumber(i); + if (!block.isValid()) { + continue; + } + + VTextBlockData *blockData = dynamic_cast(block.userData()); + if (!blockData) { + continue; + } + + if (blockData->getPreviews().isEmpty()) { + continue; + } + + for (int i = 0; i < (int)PreviewSource::MaxNumberOfSources; ++i) { + if (blockData->getPreviews().isEmpty()) { + break; + } + + PreviewSource ps = static_cast(i); + if (blockData->clearObsoletePreview(timeStamp(ps), ps)) { + affectedBlocks.insert(i); + } + } + } + + m_editor->relayout(affectedBlocks); +} diff --git a/src/vpreviewmanager.h b/src/vpreviewmanager.h index 3e7d4808..d7a5e959 100644 --- a/src/vpreviewmanager.h +++ b/src/vpreviewmanager.h @@ -67,6 +67,10 @@ public: bool isPreviewEnabled() const; + // Check @p_blocks to see if there is any obsolete preview and clear them + // if there is any. + void checkBlocksForObsoletePreview(const QList &p_blocks); + // Calculate the block margin (prefix spaces) in pixels. static int calculateBlockMargin(const QTextBlock &p_block, int p_tabStopWidth); diff --git a/src/vtextblockdata.cpp b/src/vtextblockdata.cpp index 1dcb5344..430834b2 100644 --- a/src/vtextblockdata.cpp +++ b/src/vtextblockdata.cpp @@ -89,9 +89,8 @@ bool VTextBlockData::clearObsoletePreview(long long p_timeStamp, PreviewSource p bool deleted = false; for (auto it = m_previews.begin(); it != m_previews.end();) { VPreviewInfo *ele = *it; - if (ele->m_source == p_source - && ele->m_timeStamp < p_timeStamp) { + && ele->m_timeStamp != p_timeStamp) { // Remove it. qDebug() << "clear obsolete preview" << ele->m_imageInfo.toString(); delete ele;