#include "vmathjaxinplacepreviewhelper.h" #include #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 &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 &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 blocks; QVector > 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 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; } } }