mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
preview non-codeblock MathJax
This commit is contained in:
parent
9566e6f5d2
commit
aa5960f974
@ -87,7 +87,10 @@ HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &s
|
||||
m_completeTimer->setSingleShot(true);
|
||||
m_completeTimer->setInterval(completeWaitTime);
|
||||
connect(m_completeTimer, &QTimer::timeout,
|
||||
this, &HGMarkdownHighlighter::highlightCompleted);
|
||||
this, [this]() {
|
||||
updateMathjaxBlocks();
|
||||
emit highlightCompleted();
|
||||
});
|
||||
|
||||
connect(document, &QTextDocument::contentsChange,
|
||||
this, &HGMarkdownHighlighter::handleContentChange);
|
||||
@ -183,7 +186,7 @@ void HGMarkdownHighlighter::highlightBlock(const QString &text)
|
||||
setCurrentBlockState(HighlightBlockState::Verbatim);
|
||||
goto exit;
|
||||
} else if (m_enableMathjax) {
|
||||
highlightMathJax(curBlock, text);
|
||||
highlightMathJax(text);
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,11 +523,14 @@ static bool intersect(const QList<QPair<int, int>> &p_indices, int &p_start, int
|
||||
return false;
|
||||
}
|
||||
|
||||
void HGMarkdownHighlighter::highlightMathJax(const QTextBlock &p_block, const QString &p_text)
|
||||
void HGMarkdownHighlighter::highlightMathJax(const QString &p_text)
|
||||
{
|
||||
const int blockMarkLength = 2;
|
||||
const int inlineMarkLength = 1;
|
||||
|
||||
VTextBlockData *blockData = currentBlockData();
|
||||
Q_ASSERT(blockData);
|
||||
|
||||
int startIdx = 0;
|
||||
// Next position to search.
|
||||
int pos = 0;
|
||||
@ -532,8 +538,10 @@ void HGMarkdownHighlighter::highlightMathJax(const QTextBlock &p_block, const QS
|
||||
|
||||
QList<QPair<int, int>> blockIdices;
|
||||
|
||||
bool fromPreBlock = true;
|
||||
// Mathjax block formula.
|
||||
if (state != HighlightBlockState::MathjaxBlock) {
|
||||
fromPreBlock = false;
|
||||
startIdx = m_mathjaxBlockExp.indexIn(p_text);
|
||||
pos = startIdx + m_mathjaxBlockExp.matchedLength();
|
||||
startIdx = pos - blockMarkLength;
|
||||
@ -542,14 +550,56 @@ void HGMarkdownHighlighter::highlightMathJax(const QTextBlock &p_block, const QS
|
||||
while (startIdx >= 0) {
|
||||
int endIdx = m_mathjaxBlockExp.indexIn(p_text, pos);
|
||||
int mathLength = 0;
|
||||
MathjaxInfo info;
|
||||
if (endIdx == -1) {
|
||||
setCurrentBlockState(HighlightBlockState::MathjaxBlock);
|
||||
mathLength = p_text.length() - startIdx;
|
||||
pos = startIdx + mathLength;
|
||||
|
||||
info.m_previewedAsBlock = false;
|
||||
info.m_index = startIdx,
|
||||
info.m_length = mathLength;
|
||||
if (fromPreBlock) {
|
||||
VTextBlockData *preBlockData = previousBlockData();
|
||||
Q_ASSERT(preBlockData);
|
||||
const MathjaxInfo &preInfo = preBlockData->getPendingMathjax();
|
||||
info.m_text = preInfo.text() + "\n" + p_text.mid(startIdx, mathLength);
|
||||
} else {
|
||||
info.m_text = p_text.mid(startIdx, mathLength);
|
||||
}
|
||||
|
||||
blockData->setPendingMathjax(info);
|
||||
} else {
|
||||
// Found end marker of a formula.
|
||||
mathLength = endIdx - startIdx + m_mathjaxBlockExp.matchedLength();
|
||||
pos = startIdx + mathLength;
|
||||
|
||||
info.m_previewedAsBlock = false;
|
||||
info.m_index = startIdx;
|
||||
info.m_length = mathLength;
|
||||
if (fromPreBlock) {
|
||||
// A cross-block formula.
|
||||
if (pos >= p_text.length()) {
|
||||
info.m_previewedAsBlock = true;
|
||||
}
|
||||
|
||||
VTextBlockData *preBlockData = previousBlockData();
|
||||
Q_ASSERT(preBlockData);
|
||||
const MathjaxInfo &preInfo = preBlockData->getPendingMathjax();
|
||||
info.m_text = preInfo.text() + "\n" + p_text.mid(startIdx, mathLength);
|
||||
} else {
|
||||
// A formula within one block.
|
||||
if (pos >= p_text.length() && startIdx == 0) {
|
||||
info.m_previewedAsBlock = true;
|
||||
}
|
||||
|
||||
info.m_text = p_text.mid(startIdx, mathLength);
|
||||
}
|
||||
|
||||
blockData->addMathjax(info);
|
||||
}
|
||||
|
||||
pos = startIdx + mathLength;
|
||||
fromPreBlock = false;
|
||||
|
||||
blockIdices.append(QPair<int, int>(startIdx, pos));
|
||||
|
||||
@ -562,7 +612,9 @@ void HGMarkdownHighlighter::highlightMathJax(const QTextBlock &p_block, const QS
|
||||
// Mathjax inline formula.
|
||||
startIdx = 0;
|
||||
pos = 0;
|
||||
fromPreBlock = true;
|
||||
if (state != HighlightBlockState::MathjaxInline) {
|
||||
fromPreBlock = false;
|
||||
startIdx = m_mathjaxInlineExp.indexIn(p_text);
|
||||
pos = startIdx + m_mathjaxInlineExp.matchedLength();
|
||||
startIdx = pos - inlineMarkLength;
|
||||
@ -582,8 +634,47 @@ void HGMarkdownHighlighter::highlightMathJax(const QTextBlock &p_block, const QS
|
||||
// Check if it intersect with blocks.
|
||||
if (!intersect(blockIdices, startIdx, pos)) {
|
||||
// A valid inline mathjax.
|
||||
MathjaxInfo info;
|
||||
if (endIdx == -1) {
|
||||
setCurrentBlockState(HighlightBlockState::MathjaxInline);
|
||||
|
||||
info.m_previewedAsBlock = false;
|
||||
info.m_index = startIdx,
|
||||
info.m_length = mathLength;
|
||||
if (fromPreBlock) {
|
||||
VTextBlockData *preBlockData = previousBlockData();
|
||||
Q_ASSERT(preBlockData);
|
||||
const MathjaxInfo &preInfo = preBlockData->getPendingMathjax();
|
||||
info.m_text = preInfo.text() + "\n" + p_text.mid(startIdx, mathLength);
|
||||
} else {
|
||||
info.m_text = p_text.mid(startIdx, mathLength);
|
||||
}
|
||||
|
||||
blockData->setPendingMathjax(info);
|
||||
} else {
|
||||
info.m_previewedAsBlock = false;
|
||||
info.m_index = startIdx;
|
||||
info.m_length = mathLength;
|
||||
if (fromPreBlock) {
|
||||
// A cross-block formula.
|
||||
if (pos >= p_text.length()) {
|
||||
info.m_previewedAsBlock = true;
|
||||
}
|
||||
|
||||
VTextBlockData *preBlockData = previousBlockData();
|
||||
Q_ASSERT(preBlockData);
|
||||
const MathjaxInfo &preInfo = preBlockData->getPendingMathjax();
|
||||
info.m_text = preInfo.text() + "\n" + p_text.mid(startIdx, mathLength);
|
||||
} else {
|
||||
// A formula within one block.
|
||||
if (pos >= p_text.length() && startIdx == 0) {
|
||||
info.m_previewedAsBlock = true;
|
||||
}
|
||||
|
||||
info.m_text = p_text.mid(startIdx, mathLength);
|
||||
}
|
||||
|
||||
blockData->addMathjax(info);
|
||||
}
|
||||
|
||||
setFormat(startIdx, mathLength, m_mathjaxFormat);
|
||||
@ -599,6 +690,8 @@ void HGMarkdownHighlighter::highlightMathJax(const QTextBlock &p_block, const QS
|
||||
|
||||
startIdx = pos - inlineMarkLength;
|
||||
}
|
||||
|
||||
fromPreBlock = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -813,12 +906,8 @@ bool HGMarkdownHighlighter::updateCodeBlocks()
|
||||
}
|
||||
|
||||
m_numOfCodeBlockHighlightsToRecv = codeBlocks.size();
|
||||
if (m_numOfCodeBlockHighlightsToRecv > 0) {
|
||||
emit codeBlocksUpdated(codeBlocks);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
emit codeBlocksUpdated(codeBlocks);
|
||||
return m_numOfCodeBlockHighlightsToRecv > 0;
|
||||
}
|
||||
|
||||
static bool compHLUnitStyle(const HLUnitStyle &a, const HLUnitStyle &b)
|
||||
@ -977,3 +1066,29 @@ void HGMarkdownHighlighter::highlightHeaderFast(int p_blockNumber, const QString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HGMarkdownHighlighter::updateMathjaxBlocks()
|
||||
{
|
||||
if (!m_enableMathjax) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<VMathjaxBlock> blocks;
|
||||
QTextBlock bl = document->firstBlock();
|
||||
while (bl.isValid()) {
|
||||
VTextBlockData *data = static_cast<VTextBlockData *>(bl.userData());
|
||||
if (!data) {
|
||||
bl = bl.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
const QVector<MathjaxInfo> &info = data->getMathjax();
|
||||
for (auto const & it : info) {
|
||||
blocks.append(VMathjaxBlock(bl.blockNumber(), it));
|
||||
}
|
||||
|
||||
bl = bl.next();
|
||||
}
|
||||
|
||||
emit mathjaxBlocksUpdated(blocks);
|
||||
}
|
||||
|
@ -69,6 +69,52 @@ struct VCodeBlock
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct VMathjaxBlock
|
||||
{
|
||||
VMathjaxBlock()
|
||||
: m_blockNumber(-1),
|
||||
m_previewedAsBlock(false),
|
||||
m_index(-1),
|
||||
m_length(-1)
|
||||
{
|
||||
}
|
||||
|
||||
VMathjaxBlock(int p_blockNumber, const MathjaxInfo &p_info)
|
||||
: m_blockNumber(p_blockNumber),
|
||||
m_previewedAsBlock(p_info.m_previewedAsBlock),
|
||||
m_index(p_info.m_index),
|
||||
m_length(p_info.m_length),
|
||||
m_text(p_info.m_text)
|
||||
{
|
||||
}
|
||||
|
||||
bool equalContent(const VMathjaxBlock &p_block) const
|
||||
{
|
||||
return m_text == p_block.m_text;
|
||||
}
|
||||
|
||||
void updateNonContent(const VMathjaxBlock &p_block)
|
||||
{
|
||||
m_blockNumber = p_block.m_blockNumber;
|
||||
m_previewedAsBlock = p_block.m_previewedAsBlock;
|
||||
m_index = p_block.m_index;
|
||||
m_length = p_block.m_length;
|
||||
}
|
||||
|
||||
int m_blockNumber;
|
||||
|
||||
bool m_previewedAsBlock;
|
||||
|
||||
// Start index within the block.
|
||||
int m_index;
|
||||
|
||||
int m_length;
|
||||
|
||||
QString m_text;
|
||||
};
|
||||
|
||||
|
||||
// Highlight unit with global position and string style name.
|
||||
struct HLUnitPos
|
||||
{
|
||||
@ -169,6 +215,9 @@ signals:
|
||||
// Emitted when header regions have been fetched from a new parsing result.
|
||||
void headersUpdated(const QVector<VElementRegion> &p_headerRegions);
|
||||
|
||||
// Emitted when Mathjax blocks updated.
|
||||
void mathjaxBlocksUpdated(const QVector<VMathjaxBlock> &p_mathjaxBlocks);
|
||||
|
||||
protected:
|
||||
void highlightBlock(const QString &text) Q_DECL_OVERRIDE;
|
||||
|
||||
@ -272,7 +321,7 @@ private:
|
||||
|
||||
void highlightCodeBlock(const QTextBlock &p_block, const QString &p_text);
|
||||
|
||||
void highlightMathJax(const QTextBlock &p_block, const QString &p_text);
|
||||
void highlightMathJax(const QString &p_text);
|
||||
|
||||
// Highlight links using regular expression.
|
||||
// PEG Markdown Highlight treat URLs with spaces illegal. This function is
|
||||
@ -295,6 +344,8 @@ private:
|
||||
// Return false if there is none.
|
||||
bool updateCodeBlocks();
|
||||
|
||||
void updateMathjaxBlocks();
|
||||
|
||||
// Fetch all the HTML comment regions from parsing result.
|
||||
void initHtmlCommentRegionsFromResult();
|
||||
|
||||
|
@ -96,14 +96,14 @@ var highlightText = function(text, id, timeStamp) {
|
||||
content.highlightTextCB(html, id, timeStamp);
|
||||
}
|
||||
|
||||
var textToHtml = function(text) {
|
||||
var textToHtml = function(identifier, id, timeStamp, text, inlineStyle) {
|
||||
var html = marked(text);
|
||||
var container = textHtmlDiv;
|
||||
container.innerHTML = html;
|
||||
if (inlineStyle) {
|
||||
var container = textHtmlDiv;
|
||||
container.innerHTML = html;
|
||||
html = getHtmlWithInlineStyles(container);
|
||||
container.innerHTML = "";
|
||||
}
|
||||
|
||||
html = getHtmlWithInlineStyles(container);
|
||||
|
||||
container.innerHTML = "";
|
||||
|
||||
content.textToHtmlCB(text, html);
|
||||
content.textToHtmlCB(identifier, id, timeStamp, html);
|
||||
}
|
||||
|
@ -140,14 +140,14 @@ var highlightText = function(text, id, timeStamp) {
|
||||
content.highlightTextCB(html, id, timeStamp);
|
||||
};
|
||||
|
||||
var textToHtml = function(text) {
|
||||
var textToHtml = function(identifier, id, timeStamp, text, inlineStyle) {
|
||||
var html = mdit.render(text);
|
||||
var container = textHtmlDiv;
|
||||
container.innerHTML = html;
|
||||
if (inlineStyle) {
|
||||
var container = textHtmlDiv;
|
||||
container.innerHTML = html;
|
||||
html = getHtmlWithInlineStyles(container);
|
||||
container.innerHTML = "";
|
||||
}
|
||||
|
||||
html = getHtmlWithInlineStyles(container);
|
||||
|
||||
container.innerHTML = "";
|
||||
|
||||
content.textToHtmlCB(text, html);
|
||||
content.textToHtmlCB(identifier, id, timeStamp, html);
|
||||
};
|
||||
|
@ -84,14 +84,14 @@ var highlightText = function(text, id, timeStamp) {
|
||||
content.highlightTextCB(html, id, timeStamp);
|
||||
}
|
||||
|
||||
var textToHtml = function(text) {
|
||||
var textToHtml = function(identifier, id, timeStamp, text, inlineStyle) {
|
||||
var html = marked(text);
|
||||
var container = textHtmlDiv;
|
||||
container.innerHTML = html;
|
||||
if (inlineStyle) {
|
||||
var container = textHtmlDiv;
|
||||
container.innerHTML = html;
|
||||
html = getHtmlWithInlineStyles(container);
|
||||
container.innerHTML = "";
|
||||
}
|
||||
|
||||
html = getHtmlWithInlineStyles(container);
|
||||
|
||||
container.innerHTML = "";
|
||||
|
||||
content.textToHtmlCB(text, html);
|
||||
content.textToHtmlCB(identifier, id, timeStamp, html);
|
||||
}
|
||||
|
@ -17,29 +17,72 @@ new QWebChannel(qt.webChannelTransport,
|
||||
channelInitialized = true;
|
||||
});
|
||||
|
||||
var previewMathJax = function(identifier, id, timeStamp, text) {
|
||||
if (text.length == 0) {
|
||||
var timeStamps = new Map();
|
||||
|
||||
var htmlToElement = function(html) {
|
||||
var template = document.createElement('template');
|
||||
html = html.trim();
|
||||
template.innerHTML = html;
|
||||
return template.content.firstChild;
|
||||
};
|
||||
|
||||
var isEmptyMathJax = function(text) {
|
||||
return text.replace(/\$/g, '').trim().length == 0;
|
||||
};
|
||||
|
||||
var previewMathJax = function(identifier, id, timeStamp, text, isHtml) {
|
||||
timeStamps.set(identifier, timeStamp);
|
||||
|
||||
if (isEmptyMathJax(text)) {
|
||||
content.mathjaxResultReady(identifier, id, timeStamp, 'png', '');
|
||||
return;
|
||||
}
|
||||
|
||||
var p = null;
|
||||
if (isHtml) {
|
||||
p = htmlToElement(text);
|
||||
if (isEmptyMathJax(p.textContent)) {
|
||||
p = null;
|
||||
}
|
||||
} else {
|
||||
p = document.createElement('p');
|
||||
p.textContent = text;
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
content.mathjaxResultReady(identifier, id, timeStamp, 'png', '');
|
||||
return;
|
||||
}
|
||||
|
||||
var p = document.createElement('p');
|
||||
p.textContent = text;
|
||||
contentDiv.appendChild(p);
|
||||
|
||||
var isBlock = false;
|
||||
if (text.indexOf('$$') !== -1) {
|
||||
isBlock = true;
|
||||
}
|
||||
|
||||
try {
|
||||
MathJax.Hub.Queue(["Typeset",
|
||||
MathJax.Hub,
|
||||
p,
|
||||
postProcessMathJax.bind(undefined, identifier, id, timeStamp, p)]);
|
||||
[postProcessMathJax, identifier, id, timeStamp, p, isBlock]]);
|
||||
} catch (err) {
|
||||
console.log("err: " + err);
|
||||
content.mathjaxResultReady(identifier, id, timeStamp, 'png', '');
|
||||
contentDiv.removeChild(p);
|
||||
delete p;
|
||||
}
|
||||
};
|
||||
|
||||
var postProcessMathJax = function(identifier, id, timeStamp, container) {
|
||||
domtoimage.toPng(container, { height: container.clientHeight * 1.5 }).then(function (dataUrl) {
|
||||
var postProcessMathJax = function(identifier, id, timeStamp, container, isBlock) {
|
||||
if (timeStamps.get(identifier) != timeStamp) {
|
||||
contentDiv.removeChild(container);
|
||||
delete container;
|
||||
return;
|
||||
}
|
||||
|
||||
var hei = (isBlock ? container.clientHeight * 1.5 : container.clientHeight * 1.8) + 5;
|
||||
domtoimage.toPng(container, { height: hei }).then(function (dataUrl) {
|
||||
var png = dataUrl.substring(dataUrl.indexOf(',') + 1);
|
||||
content.mathjaxResultReady(identifier, id, timeStamp, 'png', png);
|
||||
|
||||
@ -47,6 +90,7 @@ var postProcessMathJax = function(identifier, id, timeStamp, container) {
|
||||
delete container;
|
||||
}).catch(function (err) {
|
||||
console.log("err: " + err);
|
||||
content.mathjaxResultReady(identifier, id, timeStamp, 'png', '');
|
||||
contentDiv.removeChild(container);
|
||||
delete container;
|
||||
});
|
||||
|
@ -137,7 +137,7 @@ var highlightText = function(text, id, timeStamp) {
|
||||
content.highlightTextCB(html, id, timeStamp);
|
||||
}
|
||||
|
||||
var textToHtml = function(text) {
|
||||
var textToHtml = function(identifier, id, timeStamp, text, inlineStyle) {
|
||||
var html = renderer.makeHtml(text);
|
||||
|
||||
var parser = new DOMParser();
|
||||
@ -148,12 +148,12 @@ var textToHtml = function(text) {
|
||||
|
||||
delete parser;
|
||||
|
||||
var container = textHtmlDiv;
|
||||
container.innerHTML = html;
|
||||
if (inlineStyle) {
|
||||
var container = textHtmlDiv;
|
||||
container.innerHTML = html;
|
||||
html = getHtmlWithInlineStyles(container);
|
||||
container.innerHTML = "";
|
||||
}
|
||||
|
||||
html = getHtmlWithInlineStyles(container);
|
||||
|
||||
container.innerHTML = "";
|
||||
|
||||
content.textToHtmlCB(text, html);
|
||||
content.textToHtmlCB(identifier, id, timeStamp, html);
|
||||
}
|
||||
|
@ -23,17 +23,17 @@ p {
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
h2 {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
@ -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=8
|
||||
version=9
|
||||
|
||||
; 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.
|
||||
|
@ -22,17 +22,17 @@ p {
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
h2 {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ mdhl_file=v_native.mdhl
|
||||
css_file=v_native.css
|
||||
codeblock_css_file=v_native_codeblock.css
|
||||
mermaid_css_file=v_native_mermaid.css
|
||||
version=8
|
||||
version=9
|
||||
|
||||
[phony]
|
||||
; Abstract color attributes.
|
||||
|
@ -23,17 +23,17 @@ p {
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
h2 {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
@ -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=8
|
||||
version=9
|
||||
|
||||
[phony]
|
||||
; Abstract color attributes.
|
||||
|
@ -130,7 +130,8 @@ SOURCES += main.cpp\
|
||||
vgraphvizhelper.cpp \
|
||||
vlivepreviewhelper.cpp \
|
||||
vmathjaxpreviewhelper.cpp \
|
||||
vmathjaxwebdocument.cpp
|
||||
vmathjaxwebdocument.cpp \
|
||||
vmathjaxinplacepreviewhelper.cpp
|
||||
|
||||
HEADERS += vmainwindow.h \
|
||||
vdirectorytree.h \
|
||||
@ -251,7 +252,8 @@ HEADERS += vmainwindow.h \
|
||||
vgraphvizhelper.h \
|
||||
vlivepreviewhelper.h \
|
||||
vmathjaxpreviewhelper.h \
|
||||
vmathjaxwebdocument.h
|
||||
vmathjaxwebdocument.h \
|
||||
vmathjaxinplacepreviewhelper.h
|
||||
|
||||
RESOURCES += \
|
||||
vnote.qrc \
|
||||
|
@ -535,6 +535,9 @@ qreal VUtils::calculateScaleFactor()
|
||||
factor = dpi / refDpi;
|
||||
if (factor < 1) {
|
||||
factor = 1;
|
||||
} else {
|
||||
// Keep only two digits after the dot.
|
||||
factor = (int)(factor * 100) / 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,8 @@ VDocument::VDocument(const VFile *v_file, QObject *p_parent)
|
||||
m_file(v_file),
|
||||
m_readyToHighlight(false),
|
||||
m_plantUMLHelper(NULL),
|
||||
m_graphvizHelper(NULL)
|
||||
m_graphvizHelper(NULL),
|
||||
m_nextID(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -83,9 +84,13 @@ void VDocument::highlightTextCB(const QString &p_html, int p_id, int p_timeStamp
|
||||
emit textHighlighted(p_html, p_id, p_timeStamp);
|
||||
}
|
||||
|
||||
void VDocument::textToHtmlAsync(const QString &p_text)
|
||||
void VDocument::textToHtmlAsync(int p_identitifer,
|
||||
int p_id,
|
||||
int p_timeStamp,
|
||||
const QString &p_text,
|
||||
bool p_inlineStyle)
|
||||
{
|
||||
emit requestTextToHtml(p_text);
|
||||
emit requestTextToHtml(p_identitifer, p_id, p_timeStamp, p_text, p_inlineStyle);
|
||||
}
|
||||
|
||||
void VDocument::getHtmlContentAsync()
|
||||
@ -93,9 +98,9 @@ void VDocument::getHtmlContentAsync()
|
||||
emit requestHtmlContent();
|
||||
}
|
||||
|
||||
void VDocument::textToHtmlCB(const QString &p_text, const QString &p_html)
|
||||
void VDocument::textToHtmlCB(int p_identitifer, int p_id, int p_timeStamp, const QString &p_html)
|
||||
{
|
||||
emit textToHtmlFinished(p_text, p_html);
|
||||
emit textToHtmlFinished(p_identitifer, p_id, p_timeStamp, p_html);
|
||||
}
|
||||
|
||||
void VDocument::noticeReadyToHighlightText()
|
||||
|
@ -34,7 +34,11 @@ public:
|
||||
void highlightTextAsync(const QString &p_text, int p_id, int p_timeStamp);
|
||||
|
||||
// Request to convert @p_text to HTML.
|
||||
void textToHtmlAsync(const QString &p_text);
|
||||
void textToHtmlAsync(int p_identitifer,
|
||||
int p_id,
|
||||
int p_timeStamp,
|
||||
const QString &p_text,
|
||||
bool p_inlineStyle);
|
||||
|
||||
void setFile(const VFile *p_file);
|
||||
|
||||
@ -61,6 +65,8 @@ public:
|
||||
// Set the content of the preview.
|
||||
void setPreviewContent(const QString &p_lang, const QString &p_html);
|
||||
|
||||
int registerIdentifier();
|
||||
|
||||
public slots:
|
||||
// Will be called in the HTML side
|
||||
|
||||
@ -82,7 +88,7 @@ public slots:
|
||||
|
||||
void noticeReadyToHighlightText();
|
||||
|
||||
void textToHtmlCB(const QString &p_text, const QString &p_html);
|
||||
void textToHtmlCB(int p_identitifer, int p_id, int p_timeStamp, const QString &p_html);
|
||||
|
||||
void noticeReadyToTextToHtml();
|
||||
|
||||
@ -130,9 +136,13 @@ signals:
|
||||
|
||||
void logicsFinished();
|
||||
|
||||
void requestTextToHtml(const QString &p_text);
|
||||
void requestTextToHtml(int p_identitifer,
|
||||
int p_id,
|
||||
int p_timeStamp,
|
||||
const QString &p_text,
|
||||
bool p_inlineStyle);
|
||||
|
||||
void textToHtmlFinished(const QString &p_text, const QString &p_html);
|
||||
void textToHtmlFinished(int p_identitifer, int p_id, int p_timeStamp, const QString &p_html);
|
||||
|
||||
void requestHtmlContent();
|
||||
|
||||
@ -186,6 +196,8 @@ private:
|
||||
VPlantUMLHelper *m_plantUMLHelper;
|
||||
|
||||
VGraphvizHelper *m_graphvizHelper;
|
||||
|
||||
int m_nextID;
|
||||
};
|
||||
|
||||
inline bool VDocument::isReadyToHighlight() const
|
||||
@ -203,4 +215,8 @@ inline const VWordCountInfo &VDocument::getWordCountInfo() const
|
||||
return m_wordCountInfo;
|
||||
}
|
||||
|
||||
inline int VDocument::registerIdentifier()
|
||||
{
|
||||
return ++m_nextID;
|
||||
}
|
||||
#endif // VDOCUMENT_H
|
||||
|
@ -39,13 +39,6 @@ CodeBlockPreviewInfo::CodeBlockPreviewInfo(const VCodeBlock &p_cb)
|
||||
{
|
||||
}
|
||||
|
||||
void CodeBlockPreviewInfo::clearImageData()
|
||||
{
|
||||
m_imgData.clear();
|
||||
m_imgDataBa.clear();
|
||||
m_inplacePreview.clear();
|
||||
}
|
||||
|
||||
void CodeBlockPreviewInfo::updateNonContent(const QTextDocument *p_doc,
|
||||
const VCodeBlock &p_cb)
|
||||
{
|
||||
@ -60,6 +53,7 @@ void CodeBlockPreviewInfo::updateNonContent(const QTextDocument *p_doc,
|
||||
m_inplacePreview->m_endPos = block.position() + block.length();
|
||||
m_inplacePreview->m_blockPos = block.position();
|
||||
m_inplacePreview->m_blockNumber = m_codeBlock.m_endBlock;
|
||||
// Padding is not changed since content is not changed.
|
||||
} else {
|
||||
m_inplacePreview->clear();
|
||||
}
|
||||
@ -143,7 +137,8 @@ void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlock
|
||||
m_cbIndex = -1;
|
||||
int cursorBlock = m_editor->textCursorW().block().blockNumber();
|
||||
int idx = 0;
|
||||
bool needUpdate = true;
|
||||
bool needUpdate = m_livePreviewEnabled;
|
||||
bool manualInplacePreview = m_inplacePreviewEnabled;
|
||||
for (auto const & vcb : p_codeBlocks) {
|
||||
if (!isPreviewLang(vcb.m_lang)) {
|
||||
continue;
|
||||
@ -165,6 +160,7 @@ void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlock
|
||||
if (m_inplacePreviewEnabled
|
||||
&& !m_codeBlocks[idx].inplacePreviewReady()) {
|
||||
processForInplacePreview(idx);
|
||||
manualInplacePreview = false;
|
||||
}
|
||||
|
||||
if (m_livePreviewEnabled
|
||||
@ -180,9 +176,17 @@ void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlock
|
||||
++idx;
|
||||
}
|
||||
|
||||
m_codeBlocks.resize(idx);
|
||||
if (idx == m_codeBlocks.size()) {
|
||||
manualInplacePreview = false;
|
||||
} else {
|
||||
m_codeBlocks.resize(idx);
|
||||
}
|
||||
|
||||
if (m_livePreviewEnabled && needUpdate) {
|
||||
if (manualInplacePreview) {
|
||||
updateInplacePreview();
|
||||
}
|
||||
|
||||
if (needUpdate) {
|
||||
updateLivePreview();
|
||||
}
|
||||
}
|
||||
@ -283,8 +287,12 @@ void VLivePreviewHelper::setLivePreviewEnabled(bool p_enabled)
|
||||
m_livePreviewEnabled = p_enabled;
|
||||
if (!m_livePreviewEnabled) {
|
||||
m_cbIndex = -1;
|
||||
m_codeBlocks.clear();
|
||||
m_document->previewCodeBlock(-1, "", "", true);
|
||||
|
||||
if (!m_inplacePreviewEnabled) {
|
||||
m_codeBlocks.clear();
|
||||
updateInplacePreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,13 +303,11 @@ void VLivePreviewHelper::setInplacePreviewEnabled(bool p_enabled)
|
||||
}
|
||||
|
||||
m_inplacePreviewEnabled = p_enabled;
|
||||
if (!m_livePreviewEnabled) {
|
||||
for (auto & cb : m_codeBlocks) {
|
||||
cb.clearImageData();
|
||||
}
|
||||
|
||||
updateInplacePreview();
|
||||
if (!m_inplacePreviewEnabled && !m_livePreviewEnabled) {
|
||||
m_codeBlocks.clear();
|
||||
}
|
||||
|
||||
updateInplacePreview();
|
||||
}
|
||||
|
||||
void VLivePreviewHelper::localAsyncResultReady(int p_id,
|
||||
@ -356,6 +362,7 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx)
|
||||
{
|
||||
CodeBlockPreviewInfo &cb = m_codeBlocks[p_idx];
|
||||
const VCodeBlock &vcb = cb.codeBlock();
|
||||
Q_ASSERT(!(cb.hasImageData() || cb.hasImageDataBa()));
|
||||
if (vcb.m_lang == "dot") {
|
||||
if (!m_graphvizHelper) {
|
||||
m_graphvizHelper = new VGraphvizHelper(this);
|
||||
@ -363,15 +370,10 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx)
|
||||
this, &VLivePreviewHelper::localAsyncResultReady);
|
||||
}
|
||||
|
||||
if (cb.hasImageData()) {
|
||||
cb.updateInplacePreview(m_editor, m_doc);
|
||||
updateInplacePreview();
|
||||
} else {
|
||||
m_graphvizHelper->processAsync(p_idx | LANG_PREFIX_GRAPHVIZ | TYPE_INPLACE_PREVIEW,
|
||||
m_timeStamp,
|
||||
"svg",
|
||||
removeFence(vcb.m_text));
|
||||
}
|
||||
m_graphvizHelper->processAsync(p_idx | LANG_PREFIX_GRAPHVIZ | TYPE_INPLACE_PREVIEW,
|
||||
m_timeStamp,
|
||||
"svg",
|
||||
removeFence(vcb.m_text));
|
||||
} else if (vcb.m_lang == "puml" && m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
|
||||
if (!m_plantUMLHelper) {
|
||||
m_plantUMLHelper = new VPlantUMLHelper(this);
|
||||
@ -379,15 +381,10 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx)
|
||||
this, &VLivePreviewHelper::localAsyncResultReady);
|
||||
}
|
||||
|
||||
if (cb.hasImageData()) {
|
||||
cb.updateInplacePreview(m_editor, m_doc);
|
||||
updateInplacePreview();
|
||||
} else {
|
||||
m_plantUMLHelper->processAsync(p_idx | LANG_PREFIX_PLANTUML | TYPE_INPLACE_PREVIEW,
|
||||
m_timeStamp,
|
||||
"svg",
|
||||
removeFence(vcb.m_text));
|
||||
}
|
||||
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_mathJaxHelper->previewDiagram(m_mathJaxID,
|
||||
|
@ -21,9 +21,15 @@ public:
|
||||
|
||||
explicit CodeBlockPreviewInfo(const VCodeBlock &p_cb);
|
||||
|
||||
void clearImageData();
|
||||
void clearImageData()
|
||||
{
|
||||
m_imgData.clear();
|
||||
m_imgDataBa.clear();
|
||||
m_inplacePreview.clear();
|
||||
}
|
||||
|
||||
void updateNonContent(const QTextDocument *p_doc, const VCodeBlock &p_cb);
|
||||
void updateNonContent(const QTextDocument *p_doc,
|
||||
const VCodeBlock &p_cb);
|
||||
|
||||
void updateInplacePreview(const VEditor *p_editor, const QTextDocument *p_doc);
|
||||
|
||||
@ -151,7 +157,6 @@ private slots:
|
||||
const QByteArray &p_data);
|
||||
|
||||
private:
|
||||
|
||||
bool isPreviewLang(const QString &p_lang) const;
|
||||
|
||||
// Get image data for this code block for inplace preview.
|
||||
|
242
src/vmathjaxinplacepreviewhelper.cpp
Normal file
242
src/vmathjaxinplacepreviewhelper.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
#include "vmathjaxinplacepreviewhelper.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "veditor.h"
|
||||
#include "vdocument.h"
|
||||
#include "vmainwindow.h"
|
||||
#include "veditarea.h"
|
||||
#include "vmathjaxpreviewhelper.h"
|
||||
|
||||
extern VMainWindow *g_mainWin;
|
||||
|
||||
MathjaxBlockPreviewInfo::MathjaxBlockPreviewInfo()
|
||||
{
|
||||
}
|
||||
|
||||
MathjaxBlockPreviewInfo::MathjaxBlockPreviewInfo(const VMathjaxBlock &p_mb)
|
||||
: m_mathjaxBlock(p_mb)
|
||||
{
|
||||
}
|
||||
|
||||
void MathjaxBlockPreviewInfo::updateNonContent(const QTextDocument *p_doc,
|
||||
const VEditor *p_editor,
|
||||
const VMathjaxBlock &p_mb)
|
||||
{
|
||||
m_mathjaxBlock.updateNonContent(p_mb);
|
||||
if (m_inplacePreview.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTextBlock block = p_doc->findBlockByNumber(m_mathjaxBlock.m_blockNumber);
|
||||
if (block.isValid()) {
|
||||
m_inplacePreview->m_startPos = block.position() + m_mathjaxBlock.m_index;
|
||||
m_inplacePreview->m_endPos = m_inplacePreview->m_startPos + m_mathjaxBlock.m_length;
|
||||
m_inplacePreview->m_blockPos = block.position();
|
||||
m_inplacePreview->m_blockNumber = m_mathjaxBlock.m_blockNumber;
|
||||
// Padding may changed.
|
||||
m_inplacePreview->m_padding = VPreviewManager::calculateBlockMargin(block,
|
||||
p_editor->tabStopWidthW());
|
||||
m_inplacePreview->m_isBlock = m_mathjaxBlock.m_previewedAsBlock;
|
||||
} else {
|
||||
m_inplacePreview->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void MathjaxBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor,
|
||||
const QTextDocument *p_doc)
|
||||
{
|
||||
QTextBlock block = p_doc->findBlockByNumber(m_mathjaxBlock.m_blockNumber);
|
||||
if (block.isValid()) {
|
||||
if (m_inplacePreview.isNull()) {
|
||||
m_inplacePreview.reset(new VImageToPreview());
|
||||
}
|
||||
|
||||
m_inplacePreview->m_startPos = block.position() + m_mathjaxBlock.m_index;
|
||||
m_inplacePreview->m_endPos = m_inplacePreview->m_startPos + m_mathjaxBlock.m_length;
|
||||
m_inplacePreview->m_blockPos = block.position();
|
||||
m_inplacePreview->m_blockNumber = m_mathjaxBlock.m_blockNumber;
|
||||
m_inplacePreview->m_padding = VPreviewManager::calculateBlockMargin(block,
|
||||
p_editor->tabStopWidthW());
|
||||
m_inplacePreview->m_name = QString::number(getImageIndex());
|
||||
m_inplacePreview->m_isBlock = m_mathjaxBlock.m_previewedAsBlock;
|
||||
|
||||
if (hasImageDataBa()) {
|
||||
m_inplacePreview->m_image.loadFromData(m_imgDataBa,
|
||||
m_imgFormat.toLocal8Bit().data());
|
||||
} else {
|
||||
m_inplacePreview->m_image = QPixmap();
|
||||
}
|
||||
} else {
|
||||
m_inplacePreview->clear();
|
||||
}
|
||||
}
|
||||
|
||||
VMathJaxInplacePreviewHelper::VMathJaxInplacePreviewHelper(VEditor *p_editor,
|
||||
VDocument *p_document,
|
||||
QObject *p_parent)
|
||||
: QObject(p_parent),
|
||||
m_editor(p_editor),
|
||||
m_document(p_document),
|
||||
m_doc(p_editor->documentW()),
|
||||
m_enabled(false),
|
||||
m_lastInplacePreviewSize(0),
|
||||
m_timeStamp(0)
|
||||
{
|
||||
m_mathJaxHelper = g_mainWin->getEditArea()->getMathJaxPreviewHelper();
|
||||
m_mathJaxID = m_mathJaxHelper->registerIdentifier();
|
||||
connect(m_mathJaxHelper, &VMathJaxPreviewHelper::mathjaxPreviewResultReady,
|
||||
this, &VMathJaxInplacePreviewHelper::mathjaxPreviewResultReady);
|
||||
|
||||
m_documentID = m_document->registerIdentifier();
|
||||
connect(m_document, &VDocument::textToHtmlFinished,
|
||||
this, &VMathJaxInplacePreviewHelper::textToHtmlFinished);
|
||||
}
|
||||
|
||||
void VMathJaxInplacePreviewHelper::setEnabled(bool p_enabled)
|
||||
{
|
||||
if (m_enabled != p_enabled) {
|
||||
m_enabled = p_enabled;
|
||||
|
||||
if (!m_enabled) {
|
||||
m_mathjaxBlocks.clear();
|
||||
}
|
||||
|
||||
updateInplacePreview();
|
||||
}
|
||||
}
|
||||
|
||||
void VMathJaxInplacePreviewHelper::updateMathjaxBlocks(const QVector<VMathjaxBlock> &p_blocks)
|
||||
{
|
||||
if (!m_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
++m_timeStamp;
|
||||
|
||||
int idx = 0;
|
||||
bool manualUpdate = true;
|
||||
for (auto const & vmb : p_blocks) {
|
||||
if (idx < m_mathjaxBlocks.size()) {
|
||||
MathjaxBlockPreviewInfo &mb = m_mathjaxBlocks[idx];
|
||||
if (mb.mathjaxBlock().equalContent(vmb)) {
|
||||
mb.updateNonContent(m_doc, m_editor, vmb);
|
||||
} else {
|
||||
mb.setMathjaxBlock(vmb);
|
||||
}
|
||||
} else {
|
||||
m_mathjaxBlocks.append(MathjaxBlockPreviewInfo(vmb));
|
||||
}
|
||||
|
||||
if (m_enabled
|
||||
&& !m_mathjaxBlocks[idx].inplacePreviewReady()) {
|
||||
manualUpdate = false;
|
||||
processForInplacePreview(idx);
|
||||
}
|
||||
|
||||
++idx;
|
||||
}
|
||||
|
||||
m_mathjaxBlocks.resize(idx);
|
||||
|
||||
if (manualUpdate) {
|
||||
updateInplacePreview();
|
||||
}
|
||||
}
|
||||
|
||||
void VMathJaxInplacePreviewHelper::processForInplacePreview(int p_idx)
|
||||
{
|
||||
MathjaxBlockPreviewInfo &mb = m_mathjaxBlocks[p_idx];
|
||||
const VMathjaxBlock &vmb = mb.mathjaxBlock();
|
||||
if (vmb.m_text.isEmpty()) {
|
||||
updateInplacePreview();
|
||||
} else {
|
||||
textToHtmlViaWebView(vmb.m_text, p_idx, m_timeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
void VMathJaxInplacePreviewHelper::textToHtmlViaWebView(const QString &p_text,
|
||||
int p_id,
|
||||
int p_timeStamp)
|
||||
{
|
||||
int maxRetry = 50;
|
||||
while (!m_document->isReadyToTextToHtml() && maxRetry > 0) {
|
||||
qDebug() << "wait for web side ready to convert text to HTML";
|
||||
VUtils::sleepWait(100);
|
||||
--maxRetry;
|
||||
}
|
||||
|
||||
if (maxRetry == 0) {
|
||||
qWarning() << "web side is not ready to convert text to HTML";
|
||||
return;
|
||||
}
|
||||
|
||||
m_document->textToHtmlAsync(m_documentID, p_id, p_timeStamp, p_text, false);
|
||||
}
|
||||
|
||||
void VMathJaxInplacePreviewHelper::updateInplacePreview()
|
||||
{
|
||||
QSet<int> blocks;
|
||||
QVector<QSharedPointer<VImageToPreview> > images;
|
||||
for (int i = 0; i < m_mathjaxBlocks.size(); ++i) {
|
||||
MathjaxBlockPreviewInfo &mb = m_mathjaxBlocks[i];
|
||||
if (mb.inplacePreviewReady()) {
|
||||
if (!mb.inplacePreview()->m_image.isNull()) {
|
||||
images.append(mb.inplacePreview());
|
||||
} else {
|
||||
blocks.insert(mb.inplacePreview()->m_blockNumber);
|
||||
}
|
||||
} else {
|
||||
blocks.insert(mb.mathjaxBlock().m_blockNumber);
|
||||
}
|
||||
}
|
||||
|
||||
if (images.isEmpty() && m_lastInplacePreviewSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit inplacePreviewMathjaxBlockUpdated(images);
|
||||
|
||||
m_lastInplacePreviewSize = images.size();
|
||||
|
||||
if (!blocks.isEmpty()) {
|
||||
emit checkBlocksForObsoletePreview(blocks.toList());
|
||||
}
|
||||
}
|
||||
|
||||
void VMathJaxInplacePreviewHelper::mathjaxPreviewResultReady(int p_identitifer,
|
||||
int p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_format,
|
||||
const QByteArray &p_data)
|
||||
{
|
||||
if (p_identitifer != m_mathJaxID || p_timeStamp != m_timeStamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_id >= m_mathjaxBlocks.size() || p_data.isEmpty()) {
|
||||
updateInplacePreview();
|
||||
return;
|
||||
}
|
||||
|
||||
MathjaxBlockPreviewInfo &mb = m_mathjaxBlocks[p_id];
|
||||
mb.setImageDataBa(p_format, p_data);
|
||||
mb.updateInplacePreview(m_editor, m_doc);
|
||||
updateInplacePreview();
|
||||
}
|
||||
|
||||
void VMathJaxInplacePreviewHelper::textToHtmlFinished(int p_identitifer,
|
||||
int p_id,
|
||||
int p_timeStamp,
|
||||
const QString &p_html)
|
||||
{
|
||||
if (m_documentID != p_identitifer || m_timeStamp != p_timeStamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(p_html.startsWith("<"));
|
||||
m_mathJaxHelper->previewMathJaxFromHtml(m_mathJaxID,
|
||||
p_id,
|
||||
p_timeStamp,
|
||||
p_html);
|
||||
}
|
147
src/vmathjaxinplacepreviewhelper.h
Normal file
147
src/vmathjaxinplacepreviewhelper.h
Normal file
@ -0,0 +1,147 @@
|
||||
#ifndef VMATHJAXINPLACEPREVIEWHELPER_H
|
||||
#define VMATHJAXINPLACEPREVIEWHELPER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "hgmarkdownhighlighter.h"
|
||||
#include "vpreviewmanager.h"
|
||||
#include "vconstants.h"
|
||||
|
||||
class VEditor;
|
||||
class VDocument;
|
||||
class QTextDocument;
|
||||
class VMathJaxPreviewHelper;
|
||||
|
||||
class MathjaxBlockPreviewInfo
|
||||
{
|
||||
public:
|
||||
MathjaxBlockPreviewInfo();
|
||||
|
||||
explicit MathjaxBlockPreviewInfo(const VMathjaxBlock &p_mb);
|
||||
|
||||
void clearImageData()
|
||||
{
|
||||
m_imgDataBa.clear();
|
||||
m_inplacePreview.clear();
|
||||
}
|
||||
|
||||
void updateNonContent(const QTextDocument *p_doc,
|
||||
const VEditor *p_editor,
|
||||
const VMathjaxBlock &p_mb);
|
||||
|
||||
void updateInplacePreview(const VEditor *p_editor, const QTextDocument *p_doc);
|
||||
|
||||
VMathjaxBlock &mathjaxBlock()
|
||||
{
|
||||
return m_mathjaxBlock;
|
||||
}
|
||||
|
||||
const VMathjaxBlock &mathjaxBlock() const
|
||||
{
|
||||
return m_mathjaxBlock;
|
||||
}
|
||||
|
||||
void setMathjaxBlock(const VMathjaxBlock &p_mb)
|
||||
{
|
||||
m_mathjaxBlock = p_mb;
|
||||
clearImageData();
|
||||
}
|
||||
|
||||
bool inplacePreviewReady() const
|
||||
{
|
||||
return !m_inplacePreview.isNull();
|
||||
}
|
||||
|
||||
void setImageDataBa(const QString &p_format, const QByteArray &p_data)
|
||||
{
|
||||
m_imgFormat = p_format;
|
||||
m_imgDataBa = p_data;
|
||||
}
|
||||
|
||||
bool hasImageDataBa() const
|
||||
{
|
||||
return !m_imgDataBa.isEmpty();
|
||||
}
|
||||
|
||||
const QSharedPointer<VImageToPreview> inplacePreview() const
|
||||
{
|
||||
return m_inplacePreview;
|
||||
}
|
||||
|
||||
private:
|
||||
static int getImageIndex()
|
||||
{
|
||||
static int index = 0;
|
||||
return ++index;
|
||||
}
|
||||
|
||||
VMathjaxBlock m_mathjaxBlock;
|
||||
|
||||
QByteArray m_imgDataBa;
|
||||
|
||||
QString m_imgFormat;
|
||||
|
||||
QSharedPointer<VImageToPreview> m_inplacePreview;
|
||||
};
|
||||
|
||||
class VMathJaxInplacePreviewHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VMathJaxInplacePreviewHelper(VEditor *p_editor,
|
||||
VDocument *p_document,
|
||||
QObject *p_parent = nullptr);
|
||||
|
||||
void setEnabled(bool p_enabled);
|
||||
|
||||
public slots:
|
||||
void updateMathjaxBlocks(const QVector<VMathjaxBlock> &p_blocks);
|
||||
|
||||
signals:
|
||||
void inplacePreviewMathjaxBlockUpdated(const QVector<QSharedPointer<VImageToPreview> > &p_images);
|
||||
|
||||
void checkBlocksForObsoletePreview(const QList<int> &p_blocks);
|
||||
|
||||
private slots:
|
||||
void mathjaxPreviewResultReady(int p_identitifer,
|
||||
int p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_format,
|
||||
const QByteArray &p_data);
|
||||
|
||||
void textToHtmlFinished(int p_identitifer, int p_id, int p_timeStamp, const QString &p_html);
|
||||
|
||||
private:
|
||||
void processForInplacePreview(int p_idx);
|
||||
|
||||
// Emit signal to update inplace preview.
|
||||
void updateInplacePreview();
|
||||
|
||||
void textToHtmlViaWebView(const QString &p_text,
|
||||
int p_id,
|
||||
int p_timeStamp);
|
||||
|
||||
VEditor *m_editor;
|
||||
|
||||
VDocument *m_document;
|
||||
|
||||
QTextDocument *m_doc;
|
||||
|
||||
bool m_enabled;
|
||||
|
||||
VMathJaxPreviewHelper *m_mathJaxHelper;
|
||||
|
||||
// Identification for VMathJaxPreviewHelper.
|
||||
int m_mathJaxID;
|
||||
|
||||
int m_lastInplacePreviewSize;
|
||||
|
||||
TimeStamp m_timeStamp;
|
||||
|
||||
// Sorted by m_blockNumber in ascending order.
|
||||
QVector<MathjaxBlockPreviewInfo> m_mathjaxBlocks;
|
||||
|
||||
int m_documentID;
|
||||
};
|
||||
|
||||
#endif // VMATHJAXINPLACEPREVIEWHELPER_H
|
@ -1,8 +1,8 @@
|
||||
#include "vmathjaxpreviewhelper.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QWebEngineView>
|
||||
#include <QWebChannel>
|
||||
#include <QApplication>
|
||||
|
||||
#include "utils/vutils.h"
|
||||
#include "vmathjaxwebdocument.h"
|
||||
@ -24,17 +24,31 @@ VMathJaxPreviewHelper::~VMathJaxPreviewHelper()
|
||||
void VMathJaxPreviewHelper::doInit()
|
||||
{
|
||||
Q_ASSERT(!m_initialized);
|
||||
Q_ASSERT(m_parentWidget);
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
QWidget *focusWid = QApplication::focusWidget();
|
||||
|
||||
m_webView = new QWebEngineView(m_parentWidget);
|
||||
connect(m_webView, &QWebEngineView::loadFinished,
|
||||
this, [this]() {
|
||||
m_webReady = true;
|
||||
});
|
||||
for (auto const & it : m_pendingFunc) {
|
||||
it();
|
||||
}
|
||||
|
||||
m_pendingFunc.clear();
|
||||
});
|
||||
m_webView->hide();
|
||||
m_webView->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
if (focusWid) {
|
||||
focusWid->setFocus();
|
||||
} else {
|
||||
m_parentWidget->setFocus();
|
||||
}
|
||||
|
||||
m_webDoc = new VMathJaxWebDocument(m_webView);
|
||||
connect(m_webDoc, &VMathJaxWebDocument::mathjaxPreviewResultReady,
|
||||
this, [this](int p_identifier,
|
||||
@ -61,10 +75,6 @@ void VMathJaxPreviewHelper::doInit()
|
||||
m_webView->page()->setWebChannel(channel);
|
||||
|
||||
m_webView->setHtml(VUtils::generateMathJaxPreviewTemplate(), QUrl("qrc:/resources"));
|
||||
|
||||
while (!m_webReady) {
|
||||
VUtils::sleepWait(100);
|
||||
}
|
||||
}
|
||||
|
||||
void VMathJaxPreviewHelper::previewMathJax(int p_identifier,
|
||||
@ -74,7 +84,39 @@ void VMathJaxPreviewHelper::previewMathJax(int p_identifier,
|
||||
{
|
||||
init();
|
||||
|
||||
m_webDoc->previewMathJax(p_identifier, p_id, p_timeStamp, p_text);
|
||||
if (!m_webReady) {
|
||||
auto func = std::bind(&VMathJaxWebDocument::previewMathJax,
|
||||
m_webDoc,
|
||||
p_identifier,
|
||||
p_id,
|
||||
p_timeStamp,
|
||||
p_text,
|
||||
false);
|
||||
m_pendingFunc.append(func);
|
||||
} else {
|
||||
m_webDoc->previewMathJax(p_identifier, p_id, p_timeStamp, p_text, false);
|
||||
}
|
||||
}
|
||||
|
||||
void VMathJaxPreviewHelper::previewMathJaxFromHtml(int p_identifier,
|
||||
int p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_html)
|
||||
{
|
||||
init();
|
||||
|
||||
if (!m_webReady) {
|
||||
auto func = std::bind(&VMathJaxWebDocument::previewMathJax,
|
||||
m_webDoc,
|
||||
p_identifier,
|
||||
p_id,
|
||||
p_timeStamp,
|
||||
p_html,
|
||||
true);
|
||||
m_pendingFunc.append(func);
|
||||
} else {
|
||||
m_webDoc->previewMathJax(p_identifier, p_id, p_timeStamp, p_html, true);
|
||||
}
|
||||
}
|
||||
|
||||
void VMathJaxPreviewHelper::previewDiagram(int p_identifier,
|
||||
@ -85,5 +127,16 @@ void VMathJaxPreviewHelper::previewDiagram(int p_identifier,
|
||||
{
|
||||
init();
|
||||
|
||||
m_webDoc->previewDiagram(p_identifier, p_id, p_timeStamp, p_lang, p_text);
|
||||
if (!m_webReady) {
|
||||
auto func = std::bind(&VMathJaxWebDocument::previewDiagram,
|
||||
m_webDoc,
|
||||
p_identifier,
|
||||
p_id,
|
||||
p_timeStamp,
|
||||
p_lang,
|
||||
p_text);
|
||||
m_pendingFunc.append(func);
|
||||
} else {
|
||||
m_webDoc->previewDiagram(p_identifier, p_id, p_timeStamp, p_lang, p_text);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define VMATHJAXPREVIEWHELPER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <functional>
|
||||
#include <QVector>
|
||||
|
||||
#include "vconstants.h"
|
||||
|
||||
@ -9,6 +11,8 @@ class QWebEngineView;
|
||||
class VMathJaxWebDocument;
|
||||
class QWidget;
|
||||
|
||||
typedef std::function<void(void)> PendingFunc;
|
||||
|
||||
class VMathJaxPreviewHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -26,6 +30,8 @@ public:
|
||||
// @p_text: raw text of the MathJax script.
|
||||
void previewMathJax(int p_identifier, int p_id, TimeStamp p_timeStamp, const QString &p_text);
|
||||
|
||||
void previewMathJaxFromHtml(int p_identitifer, int p_id, TimeStamp p_timeStamp, const QString &p_html);
|
||||
|
||||
// Preview @p_text and return PNG data asynchronously.
|
||||
// @p_identifier: identifier the caller registered;
|
||||
// @p_id: internal id for each caller;
|
||||
@ -66,6 +72,8 @@ private:
|
||||
VMathJaxWebDocument *m_webDoc;
|
||||
|
||||
bool m_webReady;
|
||||
|
||||
QVector<PendingFunc> m_pendingFunc;
|
||||
};
|
||||
|
||||
inline int VMathJaxPreviewHelper::registerIdentifier()
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "vmathjaxwebdocument.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
VMathJaxWebDocument::VMathJaxWebDocument(QObject *p_parent)
|
||||
: QObject(p_parent)
|
||||
{
|
||||
@ -10,9 +8,10 @@ VMathJaxWebDocument::VMathJaxWebDocument(QObject *p_parent)
|
||||
void VMathJaxWebDocument::previewMathJax(int p_identifier,
|
||||
int p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_text)
|
||||
const QString &p_text,
|
||||
bool p_isHtml)
|
||||
{
|
||||
emit requestPreviewMathJax(p_identifier, p_id, p_timeStamp, p_text);
|
||||
emit requestPreviewMathJax(p_identifier, p_id, p_timeStamp, p_text, p_isHtml);
|
||||
}
|
||||
|
||||
void VMathJaxWebDocument::mathjaxResultReady(int p_identifier,
|
||||
|
@ -11,7 +11,11 @@ class VMathJaxWebDocument : public QObject
|
||||
public:
|
||||
explicit VMathJaxWebDocument(QObject *p_parent = nullptr);
|
||||
|
||||
void previewMathJax(int p_identifier, int p_id, TimeStamp p_timeStamp, const QString &p_text);
|
||||
void previewMathJax(int p_identifier,
|
||||
int p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_text,
|
||||
bool p_isHtml);
|
||||
|
||||
void previewDiagram(int p_identifier,
|
||||
int p_id,
|
||||
@ -38,7 +42,8 @@ signals:
|
||||
void requestPreviewMathJax(int p_identifier,
|
||||
int p_id,
|
||||
unsigned long long p_timeStamp,
|
||||
const QString &p_text);
|
||||
const QString &p_text,
|
||||
bool p_isHtml);
|
||||
|
||||
void requestPreviewDiagram(int p_identifier,
|
||||
int p_id,
|
||||
|
@ -39,7 +39,8 @@ VMdEditor::VMdEditor(VFile *p_file,
|
||||
m_freshEdit(true),
|
||||
m_textToHtmlDialog(NULL),
|
||||
m_zoomDelta(0),
|
||||
m_editTab(NULL)
|
||||
m_editTab(NULL),
|
||||
m_copyTimeStamp(0)
|
||||
{
|
||||
Q_ASSERT(p_file->getDocType() == DocType::Markdown);
|
||||
|
||||
@ -1124,6 +1125,8 @@ void VMdEditor::updateInitAndInsertedImages(bool p_fileChanged, UpdateAction p_a
|
||||
|
||||
void VMdEditor::handleCopyAsAction(QAction *p_act)
|
||||
{
|
||||
++m_copyTimeStamp;
|
||||
|
||||
QTextCursor cursor = textCursor();
|
||||
Q_ASSERT(cursor.hasSelection());
|
||||
|
||||
@ -1134,7 +1137,7 @@ void VMdEditor::handleCopyAsAction(QAction *p_act)
|
||||
m_textToHtmlDialog = new VCopyTextAsHtmlDialog(text, p_act->data().toString(), this);
|
||||
|
||||
// For Hoedown, we use marked.js to convert the text to have a general interface.
|
||||
emit requestTextToHtml(text);
|
||||
emit requestTextToHtml(text, 0, m_copyTimeStamp);
|
||||
|
||||
m_textToHtmlDialog->exec();
|
||||
|
||||
@ -1142,11 +1145,13 @@ void VMdEditor::handleCopyAsAction(QAction *p_act)
|
||||
m_textToHtmlDialog = NULL;
|
||||
}
|
||||
|
||||
void VMdEditor::textToHtmlFinished(const QString &p_text,
|
||||
void VMdEditor::textToHtmlFinished(int p_id,
|
||||
int p_timeStamp,
|
||||
const QUrl &p_baseUrl,
|
||||
const QString &p_html)
|
||||
{
|
||||
if (m_textToHtmlDialog && m_textToHtmlDialog->getText() == p_text) {
|
||||
Q_UNUSED(p_id);
|
||||
if (m_textToHtmlDialog && p_timeStamp == m_copyTimeStamp) {
|
||||
m_textToHtmlDialog->setConvertedHtml(p_baseUrl, p_html);
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public:
|
||||
public slots:
|
||||
bool jumpTitle(bool p_forward, int p_relativeLevel, int p_repeat) Q_DECL_OVERRIDE;
|
||||
|
||||
void textToHtmlFinished(const QString &p_text, const QUrl &p_baseUrl, const QString &p_html);
|
||||
void textToHtmlFinished(int p_id, int p_timeStamp, const QUrl &p_baseUrl, const QString &p_html);
|
||||
|
||||
// Wrapper functions for QPlainTextEdit/QTextEdit.
|
||||
public:
|
||||
@ -194,7 +194,7 @@ signals:
|
||||
void statusChanged();
|
||||
|
||||
// Request to convert @p_text to Html.
|
||||
void requestTextToHtml(const QString &p_text);
|
||||
void requestTextToHtml(const QString &p_text, int p_id, int p_timeStamp);
|
||||
|
||||
protected:
|
||||
void updateFontAndPalette() Q_DECL_OVERRIDE;
|
||||
@ -274,6 +274,8 @@ private:
|
||||
int m_zoomDelta;
|
||||
|
||||
VEditTab *m_editTab;
|
||||
|
||||
int m_copyTimeStamp;
|
||||
};
|
||||
|
||||
inline HGMarkdownHighlighter *VMdEditor::getMarkdownHighlighter() const
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "vinsertselector.h"
|
||||
#include "vsnippetlist.h"
|
||||
#include "vlivepreviewhelper.h"
|
||||
#include "vmathjaxinplacepreviewhelper.h"
|
||||
|
||||
extern VMainWindow *g_mainWin;
|
||||
|
||||
@ -39,7 +40,8 @@ VMdTab::VMdTab(VFile *p_file, VEditArea *p_editArea,
|
||||
m_enableHeadingSequence(false),
|
||||
m_backupFileChecked(false),
|
||||
m_mode(Mode::InvalidMode),
|
||||
m_livePreviewHelper(NULL)
|
||||
m_livePreviewHelper(NULL),
|
||||
m_mathjaxPreviewHelper(NULL)
|
||||
{
|
||||
V_ASSERT(m_file->getDocType() == DocType::Markdown);
|
||||
|
||||
@ -412,6 +414,7 @@ void VMdTab::setupMarkdownViewer()
|
||||
page->setBackgroundColor(Qt::transparent);
|
||||
|
||||
m_document = new VDocument(m_file, m_webViewer);
|
||||
m_documentID = m_document->registerIdentifier();
|
||||
|
||||
QWebChannel *channel = new QWebChannel(m_webViewer);
|
||||
channel->registerObject(QStringLiteral("content"), m_document);
|
||||
@ -435,9 +438,13 @@ void VMdTab::setupMarkdownViewer()
|
||||
tabIsReady(TabReady::ReadMode);
|
||||
});
|
||||
connect(m_document, &VDocument::textToHtmlFinished,
|
||||
this, [this](const QString &p_text, const QString &p_html) {
|
||||
this, [this](int p_identitifer, int p_id, int p_timeStamp, const QString &p_html) {
|
||||
Q_ASSERT(m_editor);
|
||||
m_editor->textToHtmlFinished(p_text, m_webViewer->url(), p_html);
|
||||
if (m_documentID != p_identitifer) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_editor->textToHtmlFinished(p_id, p_timeStamp, m_webViewer->url(), p_html);
|
||||
});
|
||||
connect(m_document, &VDocument::wordCountInfoUpdated,
|
||||
this, [this]() {
|
||||
@ -526,6 +533,17 @@ void VMdTab::setupMarkdownEditor()
|
||||
connect(m_livePreviewHelper, &VLivePreviewHelper::checkBlocksForObsoletePreview,
|
||||
m_editor->getPreviewManager(), &VPreviewManager::checkBlocksForObsoletePreview);
|
||||
m_livePreviewHelper->setInplacePreviewEnabled(m_editor->getPreviewManager()->isPreviewEnabled());
|
||||
|
||||
m_mathjaxPreviewHelper = new VMathJaxInplacePreviewHelper(m_editor, m_document, this);
|
||||
connect(m_editor->getMarkdownHighlighter(), &HGMarkdownHighlighter::mathjaxBlocksUpdated,
|
||||
m_mathjaxPreviewHelper, &VMathJaxInplacePreviewHelper::updateMathjaxBlocks);
|
||||
connect(m_editor->getPreviewManager(), &VPreviewManager::previewEnabledChanged,
|
||||
m_mathjaxPreviewHelper, &VMathJaxInplacePreviewHelper::setEnabled);
|
||||
connect(m_mathjaxPreviewHelper, &VMathJaxInplacePreviewHelper::inplacePreviewMathjaxBlockUpdated,
|
||||
m_editor->getPreviewManager(), &VPreviewManager::updateMathjaxBlocks);
|
||||
connect(m_mathjaxPreviewHelper, &VMathJaxInplacePreviewHelper::checkBlocksForObsoletePreview,
|
||||
m_editor->getPreviewManager(), &VPreviewManager::checkBlocksForObsoletePreview);
|
||||
m_mathjaxPreviewHelper->setEnabled(m_editor->getPreviewManager()->isPreviewEnabled());
|
||||
}
|
||||
|
||||
void VMdTab::updateOutlineFromHtml(const QString &p_tocHtml)
|
||||
@ -1129,7 +1147,7 @@ void VMdTab::handleFileOrDirectoryChange(bool p_isFile, UpdateAction p_act)
|
||||
}
|
||||
}
|
||||
|
||||
void VMdTab::textToHtmlViaWebView(const QString &p_text)
|
||||
void VMdTab::textToHtmlViaWebView(const QString &p_text, int p_id, int p_timeStamp)
|
||||
{
|
||||
int maxRetry = 50;
|
||||
while (!m_document->isReadyToTextToHtml() && maxRetry > 0) {
|
||||
@ -1143,7 +1161,7 @@ void VMdTab::textToHtmlViaWebView(const QString &p_text)
|
||||
return;
|
||||
}
|
||||
|
||||
m_document->textToHtmlAsync(p_text);
|
||||
m_document->textToHtmlAsync(m_documentID, p_id, p_timeStamp, p_text, true);
|
||||
}
|
||||
|
||||
void VMdTab::handleVimCmdCommandCancelled()
|
||||
|
@ -17,6 +17,7 @@ class QTimer;
|
||||
class QWebEngineDownloadItem;
|
||||
class QSplitter;
|
||||
class VLivePreviewHelper;
|
||||
class VMathJaxInplacePreviewHelper;
|
||||
|
||||
class VMdTab : public VEditTab
|
||||
{
|
||||
@ -218,7 +219,7 @@ private:
|
||||
// updateStatus() with only cursor position information.
|
||||
void updateCursorStatus();
|
||||
|
||||
void textToHtmlViaWebView(const QString &p_text);
|
||||
void textToHtmlViaWebView(const QString &p_text, int p_id, int p_timeStamp);
|
||||
|
||||
bool executeVimCommandInWebView(const QString &p_cmd);
|
||||
|
||||
@ -253,6 +254,9 @@ private:
|
||||
QSharedPointer<WebViewState> m_previewWebViewState;
|
||||
|
||||
VLivePreviewHelper *m_livePreviewHelper;
|
||||
VMathJaxInplacePreviewHelper *m_mathjaxPreviewHelper;
|
||||
|
||||
int m_documentID;
|
||||
};
|
||||
|
||||
inline VMdEditor *VMdTab::getEditor()
|
||||
|
@ -258,9 +258,10 @@ QString VPreviewManager::imageResourceName(const ImageLinkInfo &p_link)
|
||||
return name;
|
||||
}
|
||||
|
||||
QString VPreviewManager::imageResourceNameFromCodeBlock(const QSharedPointer<VImageToPreview> &p_image)
|
||||
QString VPreviewManager::imageResourceNameForSource(PreviewSource p_source,
|
||||
const QSharedPointer<VImageToPreview> &p_image)
|
||||
{
|
||||
QString name = "CODE_BLOCK_" + p_image->m_name;
|
||||
QString name = QString::number((int)p_source) + "_" + p_image->m_name;
|
||||
if (m_editor->containsImage(name)) {
|
||||
return name;
|
||||
}
|
||||
@ -371,7 +372,7 @@ void VPreviewManager::updateBlockPreviewInfo(TS p_timeStamp,
|
||||
continue;
|
||||
}
|
||||
|
||||
QString name = imageResourceNameFromCodeBlock(img);
|
||||
QString name = imageResourceNameForSource(p_source, img);
|
||||
if (name.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
@ -420,7 +421,6 @@ void VPreviewManager::clearBlockObsoletePreviewInfo(long long p_timeStamp,
|
||||
QSet<int> affectedBlocks;
|
||||
QVector<int> obsoleteBlocks;
|
||||
const QSet<int> &blocks = m_highlighter->getPossiblePreviewBlocks();
|
||||
qDebug() << "possible preview blocks" << blocks;
|
||||
for (auto i : blocks) {
|
||||
QTextBlock block = m_document->findBlockByNumber(i);
|
||||
if (!block.isValid()) {
|
||||
@ -474,6 +474,21 @@ void VPreviewManager::updateCodeBlocks(const QVector<QSharedPointer<VImageToPrev
|
||||
clearObsoleteImages(ts, PreviewSource::CodeBlock);
|
||||
}
|
||||
|
||||
void VPreviewManager::updateMathjaxBlocks(const QVector<QSharedPointer<VImageToPreview> > &p_images)
|
||||
{
|
||||
if (!m_previewEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
TS ts = ++timeStamp(PreviewSource::MathjaxBlock);
|
||||
|
||||
updateBlockPreviewInfo(ts, PreviewSource::MathjaxBlock, p_images);
|
||||
|
||||
clearBlockObsoletePreviewInfo(ts, PreviewSource::MathjaxBlock);
|
||||
|
||||
clearObsoleteImages(ts, PreviewSource::MathjaxBlock);
|
||||
}
|
||||
|
||||
void VPreviewManager::checkBlocksForObsoletePreview(const QList<int> &p_blocks)
|
||||
{
|
||||
if (p_blocks.isEmpty()) {
|
||||
|
@ -80,6 +80,8 @@ public slots:
|
||||
|
||||
void updateCodeBlocks(const QVector<QSharedPointer<VImageToPreview> > &p_images);
|
||||
|
||||
void updateMathjaxBlocks(const QVector<QSharedPointer<VImageToPreview> > &p_images);
|
||||
|
||||
signals:
|
||||
// Request highlighter to update image links.
|
||||
void requestUpdateImageLinks();
|
||||
@ -168,7 +170,7 @@ private:
|
||||
// Returns empty if fail to add the image to the resource manager.
|
||||
QString imageResourceName(const ImageLinkInfo &p_link);
|
||||
|
||||
QString imageResourceNameFromCodeBlock(const QSharedPointer<VImageToPreview> &p_image);
|
||||
QString imageResourceNameForSource(PreviewSource p_source, const QSharedPointer<VImageToPreview> &p_image);
|
||||
|
||||
QHash<QString, long long> &imageCache(PreviewSource p_source);
|
||||
|
||||
|
@ -35,13 +35,11 @@ bool VTextBlockData::insertPreviewInfo(VPreviewInfo *p_info)
|
||||
*it = p_info;
|
||||
inserted = true;
|
||||
tsUpdated = true;
|
||||
qDebug() << "update eixsting image's timestamp" << p_info->m_imageInfo.toString();
|
||||
break;
|
||||
} else if (p_info->m_imageInfo.intersect(ele->m_imageInfo)) {
|
||||
// The new one intersect with an old one.
|
||||
// Remove the old one.
|
||||
Q_ASSERT(ele->m_timeStamp < p_info->m_timeStamp);
|
||||
qDebug() << "remove intersecting old image" << ele->m_imageInfo.toString();
|
||||
delete ele;
|
||||
it = m_previews.erase(it);
|
||||
} else {
|
||||
|
@ -9,6 +9,7 @@ enum class PreviewSource
|
||||
{
|
||||
ImageLink = 0,
|
||||
CodeBlock,
|
||||
MathjaxBlock,
|
||||
MaxNumberOfSources
|
||||
};
|
||||
|
||||
@ -133,7 +134,7 @@ struct MathjaxInfo
|
||||
{
|
||||
public:
|
||||
MathjaxInfo()
|
||||
: m_isBlock(false),
|
||||
: m_previewedAsBlock(false),
|
||||
m_index(-1),
|
||||
m_length(0)
|
||||
{
|
||||
@ -145,26 +146,41 @@ public:
|
||||
return m_index >= 0 && m_length > 0;
|
||||
}
|
||||
|
||||
bool isBlock() const
|
||||
bool previewedAsBlock() const
|
||||
{
|
||||
return m_isBlock;
|
||||
return m_previewedAsBlock;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_isBlock = false;
|
||||
m_previewedAsBlock = false;
|
||||
m_index = -1;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
// Inline or block formula.
|
||||
bool m_isBlock;
|
||||
const QString &text() const
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return QString("MathjaxInfo %1 (%2,%3) %4").arg(m_previewedAsBlock)
|
||||
.arg(m_index)
|
||||
.arg(m_length)
|
||||
.arg(m_text);
|
||||
}
|
||||
|
||||
// Whether it should be previewed as block or not.
|
||||
bool m_previewedAsBlock;
|
||||
|
||||
// Start index wihtin block, including the start mark.
|
||||
int m_index;
|
||||
|
||||
// Length of this mathjax, including the end mark.
|
||||
int m_length;
|
||||
|
||||
QString m_text;
|
||||
};
|
||||
|
||||
|
||||
@ -198,7 +214,7 @@ public:
|
||||
|
||||
void setPendingMathjax(const MathjaxInfo &p_info);
|
||||
|
||||
const QVector<MathjaxInfo> getMathjax() const;
|
||||
const QVector<MathjaxInfo> &getMathjax() const;
|
||||
|
||||
void addMathjax(const MathjaxInfo &p_info);
|
||||
|
||||
@ -250,7 +266,7 @@ inline void VTextBlockData::setPendingMathjax(const MathjaxInfo &p_info)
|
||||
m_pendingMathjax = p_info;
|
||||
}
|
||||
|
||||
inline const QVector<MathjaxInfo> VTextBlockData::getMathjax() const
|
||||
inline const QVector<MathjaxInfo> &VTextBlockData::getMathjax() const
|
||||
{
|
||||
return m_mathjax;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user