vnote/src/vmathjaxinplacepreviewhelper.cpp
Le Tan 968e74e1ca PreviewManager: refactor layout logics
- Bug fix: use cached image name in preview helpers;
- Only relayout necessary blocks;
2018-08-13 20:14:18 +08:00

250 lines
8.0 KiB
C++

#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::updateInplacePreview(const VEditor *p_editor,
const QTextDocument *p_doc,
const QPixmap &p_image,
const QString &p_imageName)
{
QTextBlock block = p_doc->findBlockByNumber(m_mathjaxBlock.m_blockNumber);
if (block.isValid()) {
VImageToPreview *preview = new VImageToPreview();
preview->m_startPos = block.position() + m_mathjaxBlock.m_index;
preview->m_endPos = preview->m_startPos + m_mathjaxBlock.m_length;
preview->m_blockPos = block.position();
preview->m_blockNumber = m_mathjaxBlock.m_blockNumber;
preview->m_padding = VPreviewManager::calculateBlockMargin(block,
p_editor->tabStopWidthW());
if (!p_imageName.isEmpty()) {
preview->m_name = p_imageName;
} else {
preview->m_name = QString::number(getImageIndex());
}
preview->m_isBlock = m_mathjaxBlock.m_previewedAsBlock;
preview->m_image = p_image;
m_inplacePreview.reset(preview);
} else {
m_inplacePreview.clear();
}
}
#define MATHJAX_IMAGE_CACHE_SIZE_DIFF 20
#define MATHJAX_IMAGE_CACHE_TIME_DIFF 5
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();
m_cache.clear();
}
updateInplacePreview();
}
}
void VMathJaxInplacePreviewHelper::updateMathjaxBlocks(const QVector<VMathjaxBlock> &p_blocks)
{
if (!m_enabled) {
return;
}
++m_timeStamp;
m_mathjaxBlocks.clear();
m_mathjaxBlocks.reserve(p_blocks.size());
bool manualUpdate = true;
for (int i = 0; i < p_blocks.size(); ++i) {
const VMathjaxBlock &vmb = p_blocks[i];
const QString &text = vmb.m_text;
bool cached = false;
m_mathjaxBlocks.append(MathjaxBlockPreviewInfo(vmb));
auto it = m_cache.find(text);
if (it != m_cache.end()) {
QSharedPointer<MathjaxImageCacheEntry> &entry = it.value();
entry->m_ts = m_timeStamp;
cached = true;
m_mathjaxBlocks.last().updateInplacePreview(m_editor,
m_doc,
entry->m_image,
entry->m_imageName);
}
if (!cached || !m_mathjaxBlocks.last().inplacePreviewReady()) {
manualUpdate = false;
processForInplacePreview(m_mathjaxBlocks.size() - 1);
}
}
if (manualUpdate) {
updateInplacePreview();
}
clearObsoleteCache();
}
void VMathJaxInplacePreviewHelper::processForInplacePreview(int p_idx)
{
MathjaxBlockPreviewInfo &mb = m_mathjaxBlocks[p_idx];
const VMathjaxBlock &vmb = mb.mathjaxBlock();
if (vmb.m_text.isEmpty()) {
updateInplacePreview();
} else {
if (!textToHtmlViaWebView(vmb.m_text, p_idx, m_timeStamp)) {
updateInplacePreview();
}
}
}
bool VMathJaxInplacePreviewHelper::textToHtmlViaWebView(const QString &p_text,
int p_id,
int p_timeStamp)
{
if (!m_document->isReadyToTextToHtml()) {
qDebug() << "web side is not ready to convert text to HTML";
return false;
}
m_document->textToHtmlAsync(m_documentID, p_id, p_timeStamp, p_text, false);
return true;
}
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];
// Update the cache.
QSharedPointer<MathjaxImageCacheEntry> entry(new MathjaxImageCacheEntry(p_timeStamp,
p_data,
p_format));
m_cache.insert(mb.mathjaxBlock().m_text, entry);
mb.updateInplacePreview(m_editor, m_doc, entry->m_image, QString());
if (mb.inplacePreview()) {
entry->m_imageName = mb.inplacePreview()->m_name;
}
updateInplacePreview();
}
void VMathJaxInplacePreviewHelper::textToHtmlFinished(int p_identitifer,
int p_id,
int p_timeStamp,
const QString &p_html)
{
if (m_documentID != p_identitifer || m_timeStamp != (TimeStamp)p_timeStamp) {
return;
}
Q_ASSERT(p_html.startsWith("<"));
m_mathJaxHelper->previewMathJaxFromHtml(m_mathJaxID,
p_id,
p_timeStamp,
p_html);
}
void VMathJaxInplacePreviewHelper::clearObsoleteCache()
{
if (m_cache.size() - m_mathjaxBlocks.size() <= MATHJAX_IMAGE_CACHE_SIZE_DIFF) {
return;
}
for (auto it = m_cache.begin(); it != m_cache.end();) {
if (m_timeStamp - it.value()->m_ts > MATHJAX_IMAGE_CACHE_TIME_DIFF) {
it.value().clear();
it = m_cache.erase(it);
} else {
++it;
}
}
}