|
|
@@ -1,42 +1,14 @@
|
|
|
-#include <QtWidgets>
|
|
|
-#include <QWebChannel>
|
|
|
-#include <QFileInfo>
|
|
|
-#include <QXmlStreamReader>
|
|
|
#include "vedittab.h"
|
|
|
-#include "vedit.h"
|
|
|
-#include "vdocument.h"
|
|
|
-#include "vnote.h"
|
|
|
-#include "utils/vutils.h"
|
|
|
-#include "vpreviewpage.h"
|
|
|
-#include "hgmarkdownhighlighter.h"
|
|
|
-#include "vconfigmanager.h"
|
|
|
-#include "vmarkdownconverter.h"
|
|
|
-#include "vnotebook.h"
|
|
|
-#include "vtoc.h"
|
|
|
-#include "vmdedit.h"
|
|
|
-#include "dialog/vfindreplacedialog.h"
|
|
|
-#include "veditarea.h"
|
|
|
-#include "vconstants.h"
|
|
|
-#include "vwebview.h"
|
|
|
+#include <QApplication>
|
|
|
+#include <QWheelEvent>
|
|
|
|
|
|
-extern VConfigManager vconfig;
|
|
|
-
|
|
|
-VEditTab::VEditTab(VFile *p_file, OpenFileMode p_mode, QWidget *p_parent)
|
|
|
- : QStackedWidget(p_parent), m_file(p_file), isEditMode(false),
|
|
|
- webPreviewer(NULL), document(p_file, this),
|
|
|
- mdConverterType(vconfig.getMdConverterType()), m_fileModified(false),
|
|
|
- m_editArea(NULL)
|
|
|
+VEditTab::VEditTab(VFile *p_file, VEditArea *p_editArea, QWidget *p_parent)
|
|
|
+ : QWidget(p_parent), m_file(p_file), m_isEditMode(false),
|
|
|
+ m_modified(false), m_editArea(p_editArea)
|
|
|
{
|
|
|
- tableOfContent.filePath = p_file->retrivePath();
|
|
|
- curHeader.filePath = p_file->retrivePath();
|
|
|
- Q_ASSERT(!m_file->isOpened());
|
|
|
- m_file->open();
|
|
|
- setupUI();
|
|
|
- if (p_mode == OpenFileMode::Edit) {
|
|
|
- showFileEditMode();
|
|
|
- } else {
|
|
|
- showFileReadMode();
|
|
|
- }
|
|
|
+ m_toc.filePath = m_file->retrivePath();
|
|
|
+ m_curHeader.filePath = m_file->retrivePath();
|
|
|
+
|
|
|
connect(qApp, &QApplication::focusChanged,
|
|
|
this, &VEditTab::handleFocusChanged);
|
|
|
}
|
|
|
@@ -48,667 +20,60 @@ VEditTab::~VEditTab()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void VEditTab::init(VEditArea *p_editArea)
|
|
|
-{
|
|
|
- m_editArea = p_editArea;
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::setupUI()
|
|
|
-{
|
|
|
- switch (m_file->getDocType()) {
|
|
|
- case DocType::Markdown:
|
|
|
- if (m_file->isModifiable()) {
|
|
|
- m_textEditor = new VMdEdit(m_file, &document, mdConverterType, this);
|
|
|
- connect(dynamic_cast<VMdEdit *>(m_textEditor), &VMdEdit::headersChanged,
|
|
|
- this, &VEditTab::updateTocFromHeaders);
|
|
|
- connect(dynamic_cast<VMdEdit *>(m_textEditor), &VMdEdit::statusChanged,
|
|
|
- this, &VEditTab::noticeStatusChanged);
|
|
|
- connect(m_textEditor, SIGNAL(curHeaderChanged(int, int)),
|
|
|
- this, SLOT(updateCurHeader(int, int)));
|
|
|
- connect(m_textEditor, &VEdit::textChanged,
|
|
|
- this, &VEditTab::handleTextChanged);
|
|
|
- connect(m_textEditor, &VEdit::saveAndRead,
|
|
|
- this, &VEditTab::saveAndRead);
|
|
|
- connect(m_textEditor, &VEdit::discardAndRead,
|
|
|
- this, &VEditTab::discardAndRead);
|
|
|
- m_textEditor->reloadFile();
|
|
|
- addWidget(m_textEditor);
|
|
|
- } else {
|
|
|
- m_textEditor = NULL;
|
|
|
- }
|
|
|
- setupMarkdownPreview();
|
|
|
- break;
|
|
|
-
|
|
|
- case DocType::Html:
|
|
|
- m_textEditor = new VEdit(m_file, this);
|
|
|
- connect(m_textEditor, &VEdit::textChanged,
|
|
|
- this, &VEditTab::handleTextChanged);
|
|
|
- connect(m_textEditor, &VEdit::saveAndRead,
|
|
|
- this, &VEditTab::saveAndRead);
|
|
|
- connect(m_textEditor, &VEdit::discardAndRead,
|
|
|
- this, &VEditTab::discardAndRead);
|
|
|
- connect(m_textEditor, &VEdit::editNote,
|
|
|
- this, &VEditTab::editFile);
|
|
|
- m_textEditor->reloadFile();
|
|
|
- addWidget(m_textEditor);
|
|
|
- webPreviewer = NULL;
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- qWarning() << "unknown doc type" << int(m_file->getDocType());
|
|
|
- Q_ASSERT(false);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::handleTextChanged()
|
|
|
-{
|
|
|
- Q_ASSERT(m_file->isModifiable());
|
|
|
- if (m_fileModified) {
|
|
|
- return;
|
|
|
- }
|
|
|
- noticeStatusChanged();
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::noticeStatusChanged()
|
|
|
-{
|
|
|
- m_fileModified = m_file->isModified();
|
|
|
- emit statusChanged();
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::showFileReadMode()
|
|
|
-{
|
|
|
- isEditMode = false;
|
|
|
- int outlineIndex = curHeader.m_outlineIndex;
|
|
|
- switch (m_file->getDocType()) {
|
|
|
- case DocType::Html:
|
|
|
- m_textEditor->setReadOnly(true);
|
|
|
- break;
|
|
|
-
|
|
|
- case DocType::Markdown:
|
|
|
- if (mdConverterType == MarkdownConverterType::Hoedown) {
|
|
|
- previewByConverter();
|
|
|
- } else {
|
|
|
- document.updateText();
|
|
|
- updateTocFromHtml(document.getToc());
|
|
|
- }
|
|
|
- setCurrentWidget(webPreviewer);
|
|
|
- clearSearchedWordHighlight();
|
|
|
- scrollPreviewToHeader(outlineIndex);
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- qWarning() << "unknown doc type" << int(m_file->getDocType());
|
|
|
- Q_ASSERT(false);
|
|
|
- }
|
|
|
- noticeStatusChanged();
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::scrollPreviewToHeader(int p_outlineIndex)
|
|
|
-{
|
|
|
- Q_ASSERT(p_outlineIndex >= 0);
|
|
|
- if (p_outlineIndex < tableOfContent.headers.size()) {
|
|
|
- QString anchor = tableOfContent.headers[p_outlineIndex].anchor;
|
|
|
- qDebug() << "scroll preview to" << p_outlineIndex << anchor;
|
|
|
- if (!anchor.isEmpty()) {
|
|
|
- document.scrollToAnchor(anchor.mid(1));
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::previewByConverter()
|
|
|
-{
|
|
|
- VMarkdownConverter mdConverter;
|
|
|
- QString toc;
|
|
|
- QString html = mdConverter.generateHtml(m_file->getContent(),
|
|
|
- vconfig.getMarkdownExtensions(),
|
|
|
- toc);
|
|
|
- document.setHtml(html);
|
|
|
- updateTocFromHtml(toc);
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::showFileEditMode()
|
|
|
-{
|
|
|
- if (!m_file->isModifiable()) {
|
|
|
- return;
|
|
|
- }
|
|
|
- isEditMode = true;
|
|
|
-
|
|
|
- // beginEdit() may change curHeader.
|
|
|
- int outlineIndex = curHeader.m_outlineIndex;
|
|
|
- m_textEditor->beginEdit();
|
|
|
- setCurrentWidget(m_textEditor);
|
|
|
- if (m_file->getDocType() == DocType::Markdown) {
|
|
|
- dynamic_cast<VMdEdit *>(m_textEditor)->scrollToHeader(outlineIndex);
|
|
|
- }
|
|
|
- m_textEditor->setFocus();
|
|
|
- noticeStatusChanged();
|
|
|
-}
|
|
|
-
|
|
|
-bool VEditTab::closeFile(bool p_forced)
|
|
|
-{
|
|
|
- if (p_forced && isEditMode) {
|
|
|
- // Discard buffer content
|
|
|
- m_textEditor->reloadFile();
|
|
|
- m_textEditor->endEdit();
|
|
|
- showFileReadMode();
|
|
|
- } else {
|
|
|
- readFile();
|
|
|
- }
|
|
|
- return !isEditMode;
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::editFile()
|
|
|
-{
|
|
|
- if (isEditMode || !m_file->isModifiable()) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- showFileEditMode();
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::readFile()
|
|
|
-{
|
|
|
- if (!isEditMode) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (m_textEditor && m_textEditor->isModified()) {
|
|
|
- // Prompt to save the changes
|
|
|
- int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"),
|
|
|
- tr("Note <span style=\"%1\">%2</span> has been modified.")
|
|
|
- .arg(vconfig.c_dataTextStyle).arg(m_file->getName()),
|
|
|
- tr("Do you want to save your changes?"),
|
|
|
- QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
|
|
|
- QMessageBox::Save, this);
|
|
|
- switch (ret) {
|
|
|
- case QMessageBox::Save:
|
|
|
- saveFile();
|
|
|
- // Fall through
|
|
|
- case QMessageBox::Discard:
|
|
|
- m_textEditor->reloadFile();
|
|
|
- break;
|
|
|
- case QMessageBox::Cancel:
|
|
|
- // Nothing to do if user cancel this action
|
|
|
- return;
|
|
|
- default:
|
|
|
- qWarning() << "wrong return value from QMessageBox:" << ret;
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (m_textEditor) {
|
|
|
- m_textEditor->endEdit();
|
|
|
- }
|
|
|
-
|
|
|
- showFileReadMode();
|
|
|
-}
|
|
|
-
|
|
|
-bool VEditTab::saveFile()
|
|
|
-{
|
|
|
- if (!isEditMode || !m_textEditor->isModified()) {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- bool ret;
|
|
|
- // Make sure the file already exists. Temporary deal with cases when user delete or move
|
|
|
- // a file.
|
|
|
- QString filePath = m_file->retrivePath();
|
|
|
- if (!QFile(filePath).exists()) {
|
|
|
- qWarning() << filePath << "being written has been removed";
|
|
|
- VUtils::showMessage(QMessageBox::Warning, tr("Warning"), tr("Fail to save note."),
|
|
|
- tr("File <span style=\"%1\">%2</span> being written has been removed.")
|
|
|
- .arg(vconfig.c_dataTextStyle).arg(filePath),
|
|
|
- QMessageBox::Ok, QMessageBox::Ok, this);
|
|
|
- return false;
|
|
|
- }
|
|
|
- m_textEditor->saveFile();
|
|
|
- ret = m_file->save();
|
|
|
- if (!ret) {
|
|
|
- VUtils::showMessage(QMessageBox::Warning, tr("Warning"), tr("Fail to save note."),
|
|
|
- tr("Fail to write to disk when saving a note. Please try it again."),
|
|
|
- QMessageBox::Ok, QMessageBox::Ok, this);
|
|
|
- m_textEditor->setModified(true);
|
|
|
- }
|
|
|
- noticeStatusChanged();
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::saveAndRead()
|
|
|
-{
|
|
|
- saveFile();
|
|
|
- readFile();
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::discardAndRead()
|
|
|
-{
|
|
|
- readFile();
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::setupMarkdownPreview()
|
|
|
-{
|
|
|
- const QString &jsHolder = c_htmlJSHolder;
|
|
|
- const QString &extraHolder = c_htmlExtraHolder;
|
|
|
-
|
|
|
- webPreviewer = new VWebView(m_file, this);
|
|
|
- connect(webPreviewer, &VWebView::editNote,
|
|
|
- this, &VEditTab::editFile);
|
|
|
-
|
|
|
- VPreviewPage *page = new VPreviewPage(webPreviewer);
|
|
|
- webPreviewer->setPage(page);
|
|
|
- webPreviewer->setZoomFactor(vconfig.getWebZoomFactor());
|
|
|
-
|
|
|
- QWebChannel *channel = new QWebChannel(webPreviewer);
|
|
|
- channel->registerObject(QStringLiteral("content"), &document);
|
|
|
- connect(&document, &VDocument::tocChanged,
|
|
|
- this, &VEditTab::updateTocFromHtml);
|
|
|
- connect(&document, SIGNAL(headerChanged(const QString&)),
|
|
|
- this, SLOT(updateCurHeader(const QString &)));
|
|
|
- connect(&document, &VDocument::keyPressed,
|
|
|
- this, &VEditTab::handleWebKeyPressed);
|
|
|
- page->setWebChannel(channel);
|
|
|
-
|
|
|
- QString jsFile, extraFile;
|
|
|
- switch (mdConverterType) {
|
|
|
- case MarkdownConverterType::Marked:
|
|
|
- jsFile = "qrc" + VNote::c_markedJsFile;
|
|
|
- extraFile = "<script src=\"qrc" + VNote::c_markedExtraFile + "\"></script>\n";
|
|
|
- break;
|
|
|
-
|
|
|
- case MarkdownConverterType::Hoedown:
|
|
|
- jsFile = "qrc" + VNote::c_hoedownJsFile;
|
|
|
- // Use Marked to highlight code blocks.
|
|
|
- extraFile = "<script src=\"qrc" + VNote::c_markedExtraFile + "\"></script>\n";
|
|
|
- break;
|
|
|
-
|
|
|
- case MarkdownConverterType::MarkdownIt:
|
|
|
- jsFile = "qrc" + VNote::c_markdownitJsFile;
|
|
|
- extraFile = "<script src=\"qrc" + VNote::c_markdownitExtraFile + "\"></script>\n" +
|
|
|
- "<script src=\"qrc" + VNote::c_markdownitAnchorExtraFile + "\"></script>\n" +
|
|
|
- "<script src=\"qrc" + VNote::c_markdownitTaskListExtraFile + "\"></script>\n";
|
|
|
- break;
|
|
|
-
|
|
|
- case MarkdownConverterType::Showdown:
|
|
|
- jsFile = "qrc" + VNote::c_showdownJsFile;
|
|
|
- extraFile = "<script src=\"qrc" + VNote::c_showdownExtraFile + "\"></script>\n" +
|
|
|
- "<script src=\"qrc" + VNote::c_showdownAnchorExtraFile + "\"></script>\n";
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- Q_ASSERT(false);
|
|
|
- }
|
|
|
-
|
|
|
- if (vconfig.getEnableMermaid()) {
|
|
|
- extraFile += "<link rel=\"stylesheet\" type=\"text/css\" href=\"qrc" + VNote::c_mermaidCssFile +
|
|
|
- "\"/>\n" + "<script src=\"qrc" + VNote::c_mermaidApiJsFile + "\"></script>\n" +
|
|
|
- "<script>var VEnableMermaid = true;</script>\n";
|
|
|
- }
|
|
|
-
|
|
|
- if (vconfig.getEnableMathjax()) {
|
|
|
- extraFile += "<script type=\"text/x-mathjax-config\">"
|
|
|
- "MathJax.Hub.Config({\n"
|
|
|
- " tex2jax: {inlineMath: [['$','$'], ['\\\\(','\\\\)']]},\n"
|
|
|
- " showProcessingMessages: false,\n"
|
|
|
- " messageStyle: \"none\"});\n"
|
|
|
- "</script>\n"
|
|
|
- "<script type=\"text/javascript\" async src=\"" + VNote::c_mathjaxJsFile + "\"></script>\n" +
|
|
|
- "<script>var VEnableMathjax = true;</script>\n";
|
|
|
- }
|
|
|
-
|
|
|
- if (vconfig.getEnableImageCaption()) {
|
|
|
- extraFile += "<script>var VEnableImageCaption = true;</script>\n";
|
|
|
- }
|
|
|
-
|
|
|
- QString htmlTemplate = VNote::s_markdownTemplate;
|
|
|
- htmlTemplate.replace(jsHolder, jsFile);
|
|
|
- if (!extraFile.isEmpty()) {
|
|
|
- htmlTemplate.replace(extraHolder, extraFile);
|
|
|
- }
|
|
|
-
|
|
|
- webPreviewer->setHtml(htmlTemplate, m_file->getBaseUrl());
|
|
|
- addWidget(webPreviewer);
|
|
|
-}
|
|
|
-
|
|
|
void VEditTab::focusTab()
|
|
|
{
|
|
|
- currentWidget()->setFocus();
|
|
|
+ focusChild();
|
|
|
emit getFocused();
|
|
|
}
|
|
|
|
|
|
-void VEditTab::handleFocusChanged(QWidget * /* old */, QWidget *now)
|
|
|
-{
|
|
|
- if (isChild(now)) {
|
|
|
- if (now == this) {
|
|
|
- // When VEditTab get focus, it should focus to current widget.
|
|
|
- currentWidget()->setFocus();
|
|
|
- }
|
|
|
- emit getFocused();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::updateTocFromHtml(const QString &tocHtml)
|
|
|
+bool VEditTab::isEditMode() const
|
|
|
{
|
|
|
- if (isEditMode) {
|
|
|
- return;
|
|
|
- }
|
|
|
- tableOfContent.type = VHeaderType::Anchor;
|
|
|
- QVector<VHeader> &headers = tableOfContent.headers;
|
|
|
- headers.clear();
|
|
|
-
|
|
|
- if (!tocHtml.isEmpty()) {
|
|
|
- QXmlStreamReader xml(tocHtml);
|
|
|
- if (xml.readNextStartElement()) {
|
|
|
- if (xml.name() == "ul") {
|
|
|
- parseTocUl(xml, headers, 1);
|
|
|
- } else {
|
|
|
- qWarning() << "TOC HTML does not start with <ul>";
|
|
|
- }
|
|
|
- }
|
|
|
- if (xml.hasError()) {
|
|
|
- qWarning() << "fail to parse TOC in HTML";
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- tableOfContent.filePath = m_file->retrivePath();
|
|
|
- tableOfContent.valid = true;
|
|
|
-
|
|
|
- emit outlineChanged(tableOfContent);
|
|
|
+ return m_isEditMode;
|
|
|
}
|
|
|
|
|
|
-void VEditTab::updateTocFromHeaders(const QVector<VHeader> &headers)
|
|
|
+bool VEditTab::isModified() const
|
|
|
{
|
|
|
- if (!isEditMode) {
|
|
|
- return;
|
|
|
- }
|
|
|
- tableOfContent.type = VHeaderType::LineNumber;
|
|
|
- tableOfContent.headers = headers;
|
|
|
- tableOfContent.filePath = m_file->retrivePath();
|
|
|
- tableOfContent.valid = true;
|
|
|
-
|
|
|
- emit outlineChanged(tableOfContent);
|
|
|
+ return m_modified;
|
|
|
}
|
|
|
|
|
|
-void VEditTab::parseTocUl(QXmlStreamReader &xml, QVector<VHeader> &headers, int level)
|
|
|
+VFile *VEditTab::getFile() const
|
|
|
{
|
|
|
- Q_ASSERT(xml.isStartElement() && xml.name() == "ul");
|
|
|
-
|
|
|
- while (xml.readNextStartElement()) {
|
|
|
- if (xml.name() == "li") {
|
|
|
- parseTocLi(xml, headers, level);
|
|
|
- } else {
|
|
|
- qWarning() << "TOC HTML <ul> should contain <li>" << xml.name();
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ return m_file;
|
|
|
}
|
|
|
|
|
|
-void VEditTab::parseTocLi(QXmlStreamReader &xml, QVector<VHeader> &headers, int level)
|
|
|
+void VEditTab::handleFocusChanged(QWidget * /* p_old */, QWidget *p_now)
|
|
|
{
|
|
|
- Q_ASSERT(xml.isStartElement() && xml.name() == "li");
|
|
|
+ if (p_now == this) {
|
|
|
+ // When VEditTab get focus, it should focus to current widget.
|
|
|
+ focusChild();
|
|
|
|
|
|
- if (xml.readNextStartElement()) {
|
|
|
- if (xml.name() == "a") {
|
|
|
- QString anchor = xml.attributes().value("href").toString();
|
|
|
- QString name;
|
|
|
- if (xml.readNext()) {
|
|
|
- if (xml.tokenString() == "Characters") {
|
|
|
- name = xml.text().toString();
|
|
|
- } else if (!xml.isEndElement()) {
|
|
|
- qWarning() << "TOC HTML <a> should be ended by </a>" << xml.name();
|
|
|
- return;
|
|
|
- }
|
|
|
- VHeader header(level, name, anchor, -1);
|
|
|
- headers.append(header);
|
|
|
- } else {
|
|
|
- // Error
|
|
|
- return;
|
|
|
- }
|
|
|
- } else if (xml.name() == "ul") {
|
|
|
- // Such as header 3 under header 1 directly
|
|
|
- VHeader header(level, "[EMPTY]", "#", -1);
|
|
|
- headers.append(header);
|
|
|
- parseTocUl(xml, headers, level + 1);
|
|
|
- } else {
|
|
|
- qWarning() << "TOC HTML <li> should contain <a> or <ul>" << xml.name();
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- while (xml.readNext()) {
|
|
|
- if (xml.isEndElement()) {
|
|
|
- if (xml.name() == "li") {
|
|
|
- return;
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (xml.name() == "ul") {
|
|
|
- // Nested unordered list
|
|
|
- parseTocUl(xml, headers, level + 1);
|
|
|
- } else {
|
|
|
- return;
|
|
|
- }
|
|
|
+ emit getFocused();
|
|
|
+ } else if (isAncestorOf(p_now)) {
|
|
|
+ emit getFocused();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void VEditTab::requestUpdateCurHeader()
|
|
|
{
|
|
|
- emit curHeaderChanged(curHeader);
|
|
|
+ emit curHeaderChanged(m_curHeader);
|
|
|
}
|
|
|
|
|
|
void VEditTab::requestUpdateOutline()
|
|
|
{
|
|
|
- checkToc();
|
|
|
- emit outlineChanged(tableOfContent);
|
|
|
+ emit outlineChanged(m_toc);
|
|
|
}
|
|
|
|
|
|
-void VEditTab::scrollToAnchor(const VAnchor &anchor)
|
|
|
-{
|
|
|
- if (anchor == curHeader) {
|
|
|
- return;
|
|
|
- }
|
|
|
- curHeader = anchor;
|
|
|
- if (isEditMode) {
|
|
|
- if (anchor.lineNumber > -1) {
|
|
|
- m_textEditor->scrollToLine(anchor.lineNumber);
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (!anchor.anchor.isEmpty()) {
|
|
|
- document.scrollToAnchor(anchor.anchor.mid(1));
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::updateCurHeader(const QString &anchor)
|
|
|
+void VEditTab::wheelEvent(QWheelEvent *p_event)
|
|
|
{
|
|
|
- if (isEditMode || curHeader.anchor.mid(1) == anchor) {
|
|
|
- return;
|
|
|
- }
|
|
|
- curHeader = VAnchor(m_file->retrivePath(), "#" + anchor, -1);
|
|
|
- if (!anchor.isEmpty()) {
|
|
|
- if (checkToc()) {
|
|
|
- emit outlineChanged(tableOfContent);
|
|
|
- }
|
|
|
- const QVector<VHeader> &headers = tableOfContent.headers;
|
|
|
- for (int i = 0; i < headers.size(); ++i) {
|
|
|
- if (headers[i].anchor == curHeader.anchor) {
|
|
|
- curHeader.m_outlineIndex = i;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- emit curHeaderChanged(curHeader);
|
|
|
- }
|
|
|
-}
|
|
|
+ QPoint angle = p_event->angleDelta();
|
|
|
+ Qt::KeyboardModifiers modifiers = p_event->modifiers();
|
|
|
+ if (!angle.isNull() && (angle.y() != 0) && (modifiers & Qt::ControlModifier)) {
|
|
|
+ // Zoom in/out current tab.
|
|
|
+ zoom(angle.y() > 0);
|
|
|
|
|
|
-void VEditTab::updateCurHeader(int p_lineNumber, int p_outlineIndex)
|
|
|
-{
|
|
|
- if (!isEditMode || curHeader.lineNumber == p_lineNumber) {
|
|
|
+ p_event->accept();
|
|
|
return;
|
|
|
}
|
|
|
- if (checkToc()) {
|
|
|
- emit outlineChanged(tableOfContent);
|
|
|
- }
|
|
|
- curHeader = VAnchor(m_file->retrivePath(), "", p_lineNumber);
|
|
|
- curHeader.m_outlineIndex = p_outlineIndex;
|
|
|
- if (p_lineNumber > -1) {
|
|
|
- emit curHeaderChanged(curHeader);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::insertImage()
|
|
|
-{
|
|
|
- qDebug() << "insert image";
|
|
|
- if (!isEditMode) {
|
|
|
- return;
|
|
|
- }
|
|
|
- m_textEditor->insertImage();
|
|
|
-}
|
|
|
|
|
|
-void VEditTab::findText(const QString &p_text, uint p_options, bool p_peek,
|
|
|
- bool p_forward)
|
|
|
-{
|
|
|
- if (isEditMode || !webPreviewer) {
|
|
|
- if (p_peek) {
|
|
|
- m_textEditor->peekText(p_text, p_options);
|
|
|
- } else {
|
|
|
- m_textEditor->findText(p_text, p_options, p_forward);
|
|
|
- }
|
|
|
- } else {
|
|
|
- findTextInWebView(p_text, p_options, p_peek, p_forward);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::replaceText(const QString &p_text, uint p_options,
|
|
|
- const QString &p_replaceText, bool p_findNext)
|
|
|
-{
|
|
|
- if (isEditMode) {
|
|
|
- m_textEditor->replaceText(p_text, p_options, p_replaceText, p_findNext);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::replaceTextAll(const QString &p_text, uint p_options,
|
|
|
- const QString &p_replaceText)
|
|
|
-{
|
|
|
- if (isEditMode) {
|
|
|
- m_textEditor->replaceTextAll(p_text, p_options, p_replaceText);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::findTextInWebView(const QString &p_text, uint p_options,
|
|
|
- bool /* p_peek */, bool p_forward)
|
|
|
-{
|
|
|
- Q_ASSERT(webPreviewer);
|
|
|
- QWebEnginePage::FindFlags flags;
|
|
|
- if (p_options & FindOption::CaseSensitive) {
|
|
|
- flags |= QWebEnginePage::FindCaseSensitively;
|
|
|
- }
|
|
|
- if (!p_forward) {
|
|
|
- flags |= QWebEnginePage::FindBackward;
|
|
|
- }
|
|
|
- webPreviewer->findText(p_text, flags);
|
|
|
-}
|
|
|
-
|
|
|
-QString VEditTab::getSelectedText() const
|
|
|
-{
|
|
|
- if (isEditMode || !webPreviewer) {
|
|
|
- QTextCursor cursor = m_textEditor->textCursor();
|
|
|
- return cursor.selectedText();
|
|
|
- } else {
|
|
|
- return webPreviewer->selectedText();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::clearSearchedWordHighlight()
|
|
|
-{
|
|
|
- if (webPreviewer) {
|
|
|
- webPreviewer->findText("");
|
|
|
- }
|
|
|
- if (m_textEditor) {
|
|
|
- m_textEditor->clearSearchedWordHighlight();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-bool VEditTab::checkToc()
|
|
|
-{
|
|
|
- bool ret = false;
|
|
|
- if (tableOfContent.filePath != m_file->retrivePath()) {
|
|
|
- tableOfContent.filePath = m_file->retrivePath();
|
|
|
- ret = true;
|
|
|
- }
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::handleWebKeyPressed(int p_key, bool p_ctrl, bool /* p_shift */)
|
|
|
-{
|
|
|
- Q_ASSERT(webPreviewer);
|
|
|
- switch (p_key) {
|
|
|
- // Esc
|
|
|
- case 27:
|
|
|
- m_editArea->getFindReplaceDialog()->closeDialog();
|
|
|
- break;
|
|
|
-
|
|
|
- // Dash
|
|
|
- case 189:
|
|
|
- if (p_ctrl) {
|
|
|
- // Zoom out.
|
|
|
- zoomWebPage(false);
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- // Equal
|
|
|
- case 187:
|
|
|
- if (p_ctrl) {
|
|
|
- // Zoom in.
|
|
|
- zoomWebPage(true);
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- // 0
|
|
|
- case 48:
|
|
|
- if (p_ctrl) {
|
|
|
- // Recover zoom.
|
|
|
- webPreviewer->setZoomFactor(1);
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void VEditTab::wheelEvent(QWheelEvent *p_event)
|
|
|
-{
|
|
|
- if (!isEditMode && webPreviewer) {
|
|
|
- QPoint angle = p_event->angleDelta();
|
|
|
- Qt::KeyboardModifiers modifiers = p_event->modifiers();
|
|
|
- if (!angle.isNull() && (angle.y() != 0) && (modifiers & Qt::ControlModifier)) {
|
|
|
- zoomWebPage(angle.y() > 0);
|
|
|
- p_event->accept();
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
p_event->ignore();
|
|
|
}
|
|
|
-
|
|
|
-void VEditTab::zoomWebPage(bool p_zoomIn, qreal p_step)
|
|
|
-{
|
|
|
- Q_ASSERT(webPreviewer);
|
|
|
- qreal curFactor = webPreviewer->zoomFactor();
|
|
|
- qreal newFactor = p_zoomIn ? curFactor + p_step : curFactor - p_step;
|
|
|
- if (newFactor < c_webZoomFactorMin) {
|
|
|
- newFactor = c_webZoomFactorMin;
|
|
|
- } else if (newFactor > c_webZoomFactorMax) {
|
|
|
- newFactor = c_webZoomFactorMax;
|
|
|
- }
|
|
|
- webPreviewer->setZoomFactor(newFactor);
|
|
|
-}
|
|
|
-
|
|
|
-VWebView *VEditTab::getWebViewer() const
|
|
|
-{
|
|
|
- return webPreviewer;
|
|
|
-}
|
|
|
-
|
|
|
-MarkdownConverterType VEditTab::getMarkdownConverterType() const
|
|
|
-{
|
|
|
- return mdConverterType;
|
|
|
-}
|