From a8849911508aa3eff63a9d6dbdaaa378909a9c90 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Sun, 11 Dec 2016 14:42:01 +0800 Subject: [PATCH] refactor: add VMdEdit to inherit VEdit for markdown edit Signed-off-by: Le Tan --- src/src.pro | 6 +- src/vedit.cpp | 254 +++----------------------------------- src/vedit.h | 59 ++------- src/vedittab.cpp | 81 +++++++----- src/vedittab.h | 10 +- src/vmainwindow.cpp | 1 + src/vmdedit.cpp | 211 +++++++++++++++++++++++++++++++ src/vmdedit.h | 51 ++++++++ src/vmdeditoperations.cpp | 9 +- 9 files changed, 357 insertions(+), 325 deletions(-) create mode 100644 src/vmdedit.cpp create mode 100644 src/vmdedit.h diff --git a/src/src.pro b/src/src.pro index 7d9ce289..05a2c8d1 100644 --- a/src/src.pro +++ b/src/src.pro @@ -47,7 +47,8 @@ SOURCES += main.cpp\ vfile.cpp \ vnotebookselector.cpp \ vnofocusitemdelegate.cpp \ - vavatar.cpp + vavatar.cpp \ + vmdedit.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -83,7 +84,8 @@ HEADERS += vmainwindow.h \ vfile.h \ vnotebookselector.h \ vnofocusitemdelegate.h \ - vavatar.h + vavatar.h \ + vmdedit.h RESOURCES += \ vnote.qrc diff --git a/src/vedit.cpp b/src/vedit.cpp index ef1ed064..865eddd8 100644 --- a/src/vedit.cpp +++ b/src/vedit.cpp @@ -3,107 +3,34 @@ #include "vedit.h" #include "vnote.h" #include "vconfigmanager.h" -#include "hgmarkdownhighlighter.h" -#include "vmdeditoperations.h" #include "vtoc.h" #include "utils/vutils.h" +#include "veditoperations.h" extern VConfigManager vconfig; VEdit::VEdit(VFile *p_file, QWidget *p_parent) - : QTextEdit(p_parent), m_file(p_file), mdHighlighter(NULL) + : QTextEdit(p_parent), m_file(p_file), m_editOps(NULL) { connect(document(), &QTextDocument::modificationChanged, (VFile *)m_file, &VFile::setModified); - - if (m_file->getDocType() == DocType::Markdown) { - setAcceptRichText(false); - mdHighlighter = new HGMarkdownHighlighter(vconfig.getMdHighlightingStyles(), - 500, document()); - connect(mdHighlighter, &HGMarkdownHighlighter::highlightCompleted, - this, &VEdit::generateEditOutline); - editOps = new VMdEditOperations(this, m_file); - } else { - editOps = NULL; - } - - updateTabSettings(); - updateFontAndPalette(); - connect(this, &VEdit::cursorPositionChanged, - this, &VEdit::updateCurHeader); } VEdit::~VEdit() { + qDebug() << "VEdit destruction"; if (m_file) { disconnect(document(), &QTextDocument::modificationChanged, (VFile *)m_file, &VFile::setModified); } - if (editOps) { - delete editOps; - editOps = NULL; - } -} - -void VEdit::updateFontAndPalette() -{ - switch (m_file->getDocType()) { - case DocType::Markdown: - setFont(vconfig.getMdEditFont()); - setPalette(vconfig.getMdEditPalette()); - break; - case DocType::Html: - setFont(vconfig.getBaseEditFont()); - setPalette(vconfig.getBaseEditPalette()); - break; - default: - qWarning() << "error: unknown doc type" << int(m_file->getDocType()); - return; - } -} - -void VEdit::updateTabSettings() -{ - switch (m_file->getDocType()) { - case DocType::Markdown: - if (vconfig.getTabStopWidth() > 0) { - QFontMetrics metrics(vconfig.getMdEditFont()); - setTabStopWidth(vconfig.getTabStopWidth() * metrics.width(' ')); - } - break; - case DocType::Html: - if (vconfig.getTabStopWidth() > 0) { - QFontMetrics metrics(vconfig.getBaseEditFont()); - setTabStopWidth(vconfig.getTabStopWidth() * metrics.width(' ')); - } - break; - default: - qWarning() << "error: unknown doc type" << int(m_file->getDocType()); - return; - } - - isExpandTab = vconfig.getIsExpandTab(); - if (isExpandTab && (vconfig.getTabStopWidth() > 0)) { - tabSpaces = QString(vconfig.getTabStopWidth(), ' '); + if (m_editOps) { + delete m_editOps; + m_editOps = NULL; } } void VEdit::beginEdit() { - updateTabSettings(); - updateFontAndPalette(); - switch (m_file->getDocType()) { - case DocType::Html: - setHtml(m_file->getContent()); - break; - case DocType::Markdown: - setFont(vconfig.getMdEditFont()); - setPlainText(m_file->getContent()); - initInitImages(); - break; - default: - qWarning() << "error: unknown doc type" << int(m_file->getDocType()); - } setReadOnly(false); setModified(false); } @@ -111,9 +38,6 @@ void VEdit::beginEdit() void VEdit::endEdit() { setReadOnly(true); - if (m_file->getDocType() == DocType::Markdown) { - clearUnusedImages(); - } } void VEdit::saveFile() @@ -121,176 +45,38 @@ void VEdit::saveFile() if (!document()->isModified()) { return; } - - switch (m_file->getDocType()) { - case DocType::Html: - m_file->setContent(toHtml()); - break; - case DocType::Markdown: - m_file->setContent(toPlainText()); - break; - default: - qWarning() << "error: unknown doc type" << int(m_file->getDocType()); - } + m_file->setContent(toHtml()); document()->setModified(false); } void VEdit::reloadFile() { - switch (m_file->getDocType()) { - case DocType::Html: - setHtml(m_file->getContent()); - break; - case DocType::Markdown: - setPlainText(m_file->getContent()); - break; - default: - qWarning() << "error: unknown doc type" << int(m_file->getDocType()); - } + setHtml(m_file->getContent()); setModified(false); } -void VEdit::keyPressEvent(QKeyEvent *event) +void VEdit::scrollToLine(int p_lineNumber) { - if ((event->key() == Qt::Key_Tab) && isExpandTab) { - QTextCursor cursor(document()); - cursor.setPosition(textCursor().position()); - cursor.insertText(tabSpaces); - return; - } - QTextEdit::keyPressEvent(event); -} - -bool VEdit::canInsertFromMimeData(const QMimeData *source) const -{ - return source->hasImage() || source->hasUrls() - || QTextEdit::canInsertFromMimeData(source); -} - -void VEdit::insertFromMimeData(const QMimeData *source) -{ - if (source->hasImage()) { - // Image data in the clipboard - if (editOps) { - bool ret = editOps->insertImageFromMimeData(source); - if (ret) { - return; - } - } - } else if (source->hasUrls()) { - // Paste an image file - if (editOps) { - bool ret = editOps->insertURLFromMimeData(source); - if (ret) { - return; - } - } - } - QTextEdit::insertFromMimeData(source); -} - -void VEdit::generateEditOutline() -{ - QTextDocument *doc = document(); - headers.clear(); - // Assume that each block contains only one line - // Only support # syntax for now - QRegExp headerReg("(#{1,6})\\s*(\\S.*)"); // Need to trim the spaces - for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next()) { - Q_ASSERT(block.lineCount() == 1); - if ((block.userState() == HighlightBlockState::BlockNormal) && - headerReg.exactMatch(block.text())) { - VHeader header(headerReg.cap(1).length(), - headerReg.cap(2).trimmed(), "", block.firstLineNumber()); - headers.append(header); - } - } - - emit headersChanged(headers); - updateCurHeader(); -} - -void VEdit::scrollToLine(int lineNumber) -{ - Q_ASSERT(lineNumber >= 0); + Q_ASSERT(p_lineNumber >= 0); // Move the cursor to the end first moveCursor(QTextCursor::End); - QTextCursor cursor(document()->findBlockByLineNumber(lineNumber)); + QTextCursor cursor(document()->findBlockByLineNumber(p_lineNumber)); cursor.movePosition(QTextCursor::EndOfBlock); setTextCursor(cursor); setFocus(); } -void VEdit::updateCurHeader() +bool VEdit::isModified() const { - int curHeader = 0; - QTextCursor cursor(this->textCursor()); - int curLine = cursor.block().firstLineNumber(); - for (int i = headers.size() - 1; i >= 0; --i) { - if (headers[i].lineNumber <= curLine) { - curHeader = headers[i].lineNumber; - break; - } + return document()->isModified(); +} + +void VEdit::setModified(bool p_modified) +{ + document()->setModified(p_modified); + if (m_file) { + m_file->setModified(p_modified); } - emit curHeaderChanged(curHeader); -} - -void VEdit::insertImage(const QString &name) -{ - m_insertedImages.append(name); -} - -void VEdit::initInitImages() -{ - m_initImages = VUtils::imagesFromMarkdownFile(m_file->retrivePath()); -} - -void VEdit::clearUnusedImages() -{ - QVector images = VUtils::imagesFromMarkdownFile(m_file->retrivePath()); - - if (!m_insertedImages.isEmpty()) { - QVector imageNames(images.size()); - for (int i = 0; i < imageNames.size(); ++i) { - imageNames[i] = VUtils::fileNameFromPath(images[i]); - } - - QDir dir = QDir(m_file->retriveImagePath()); - for (int i = 0; i < m_insertedImages.size(); ++i) { - QString name = m_insertedImages[i]; - int j; - for (j = 0; j < imageNames.size(); ++j) { - if (name == imageNames[j]) { - break; - } - } - - // Delete it - if (j == imageNames.size()) { - QString imagePath = dir.filePath(name); - QFile(imagePath).remove(); - qDebug() << "delete inserted image" << imagePath; - } - } - m_insertedImages.clear(); - } - - for (int i = 0; i < m_initImages.size(); ++i) { - QString imagePath = m_initImages[i]; - int j; - for (j = 0; j < images.size(); ++j) { - if (imagePath == images[j]) { - break; - } - } - - // Delete it - if (j == images.size()) { - QFile(imagePath).remove(); - qDebug() << "delete existing image" << imagePath; - } - } - m_initImages.clear(); } diff --git a/src/vedit.h b/src/vedit.h index fcba907f..aa264063 100644 --- a/src/vedit.h +++ b/src/vedit.h @@ -8,7 +8,6 @@ #include "vtoc.h" #include "vfile.h" -class HGMarkdownHighlighter; class VEditOperations; class VEdit : public QTextEdit @@ -16,61 +15,21 @@ class VEdit : public QTextEdit Q_OBJECT public: VEdit(VFile *p_file, QWidget *p_parent = 0); - ~VEdit(); - void beginEdit(); - void endEdit(); - + virtual ~VEdit(); + virtual void beginEdit(); + virtual void endEdit(); // Save buffer content to VFile. - void saveFile(); - - inline void setModified(bool modified); - inline bool isModified() const; - - void reloadFile(); - void scrollToLine(int lineNumber); - void insertImage(const QString &name); - -signals: - void headersChanged(const QVector &headers); - void curHeaderChanged(int lineNumber); + virtual void saveFile(); + virtual void setModified(bool p_modified); + bool isModified() const; + virtual void reloadFile(); + virtual void scrollToLine(int p_lineNumber); protected: - void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; - bool canInsertFromMimeData(const QMimeData *source) const Q_DECL_OVERRIDE; - void insertFromMimeData(const QMimeData *source) Q_DECL_OVERRIDE; - -private slots: - void generateEditOutline(); - void updateCurHeader(); - -private: - void updateTabSettings(); - void updateFontAndPalette(); - void initInitImages(); - void clearUnusedImages(); - QPointer m_file; - bool isExpandTab; - QString tabSpaces; - HGMarkdownHighlighter *mdHighlighter; - VEditOperations *editOps; - QVector headers; - QVector m_insertedImages; - QVector m_initImages; + VEditOperations *m_editOps; }; -inline bool VEdit::isModified() const -{ - return document()->isModified(); -} - -inline void VEdit::setModified(bool modified) -{ - document()->setModified(modified); - if (m_file) { - m_file->setModified(modified); - } -} #endif // VEDIT_H diff --git a/src/vedittab.cpp b/src/vedittab.cpp index 694c988d..725bc930 100644 --- a/src/vedittab.cpp +++ b/src/vedittab.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -15,12 +14,13 @@ #include "vmarkdownconverter.h" #include "vnotebook.h" #include "vtoc.h" +#include "vmdedit.h" extern VConfigManager vconfig; VEditTab::VEditTab(VFile *p_file, OpenFileMode p_mode, QWidget *p_parent) : QStackedWidget(p_parent), m_file(p_file), isEditMode(false), - mdConverterType(vconfig.getMdConverterType()) + mdConverterType(vconfig.getMdConverterType()), m_fileModified(false) { tableOfContent.filePath = p_file->retrivePath(); curHeader.filePath = p_file->retrivePath(); @@ -45,43 +45,55 @@ VEditTab::~VEditTab() void VEditTab::setupUI() { - textEditor = new VEdit(m_file); - connect(textEditor, &VEdit::headersChanged, - this, &VEditTab::updateTocFromHeaders); - connect(textEditor, SIGNAL(curHeaderChanged(int)), - this, SLOT(updateCurHeader(int))); - connect(textEditor, &VEdit::textChanged, - this, &VEditTab::statusChanged); - addWidget(textEditor); - switch (m_file->getDocType()) { case DocType::Markdown: + m_textEditor = new VMdEdit(m_file, this); + connect(dynamic_cast(m_textEditor), &VMdEdit::headersChanged, + this, &VEditTab::updateTocFromHeaders); + connect(m_textEditor, SIGNAL(curHeaderChanged(int)), + this, SLOT(updateCurHeader(int))); + connect(m_textEditor, &VEdit::textChanged, + this, &VEditTab::handleTextChanged); + addWidget(m_textEditor); + setupMarkdownPreview(); - textBrowser = NULL; break; case DocType::Html: - textBrowser = new QTextBrowser(); - addWidget(textBrowser); - textBrowser->setFont(vconfig.getBaseEditFont()); - textBrowser->setPalette(vconfig.getBaseEditPalette()); + m_textEditor = new VEdit(m_file, this); + connect(m_textEditor, &VEdit::textChanged, + this, &VEditTab::handleTextChanged); + m_textEditor->reloadFile(); + addWidget(m_textEditor); webPreviewer = NULL; break; default: qWarning() << "error: unknown doc type" << int(m_file->getDocType()); + Q_ASSERT(false); } } +void VEditTab::handleTextChanged() +{ + if (m_fileModified) { + return; + } + noticeStatusChanged(); +} + +void VEditTab::noticeStatusChanged() +{ + m_fileModified = m_file->isModified(); + emit statusChanged(); +} + void VEditTab::showFileReadMode() { qDebug() << "read" << m_file->getName(); isEditMode = false; switch (m_file->getDocType()) { case DocType::Html: - textBrowser->setHtml(m_file->getContent()); - textBrowser->setFont(vconfig.getBaseEditFont()); - textBrowser->setPalette(vconfig.getBaseEditPalette()); - setCurrentWidget(textBrowser); + m_textEditor->setReadOnly(true); break; case DocType::Markdown: if (mdConverterType == MarkdownConverterType::Marked) { @@ -93,7 +105,9 @@ void VEditTab::showFileReadMode() break; default: qWarning() << "error: unknown doc type" << int(m_file->getDocType()); + Q_ASSERT(false); } + noticeStatusChanged(); } void VEditTab::previewByConverter() @@ -112,17 +126,18 @@ void VEditTab::previewByConverter() void VEditTab::showFileEditMode() { isEditMode = true; - textEditor->beginEdit(); - setCurrentWidget(textEditor); - textEditor->setFocus(); + m_textEditor->beginEdit(); + setCurrentWidget(m_textEditor); + m_textEditor->setFocus(); + noticeStatusChanged(); } bool VEditTab::closeFile(bool p_forced) { if (p_forced && isEditMode) { // Discard buffer content - textEditor->reloadFile(); - textEditor->endEdit(); + m_textEditor->reloadFile(); + m_textEditor->endEdit(); showFileReadMode(); } else { readFile(); @@ -145,7 +160,7 @@ void VEditTab::readFile() return; } - if (textEditor->isModified()) { + if (m_textEditor->isModified()) { // Prompt to save the changes int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"), QString("Note %1 has been modified.").arg(m_file->getName()), @@ -157,7 +172,7 @@ void VEditTab::readFile() saveFile(); // Fall through case QMessageBox::Discard: - textEditor->reloadFile(); + m_textEditor->reloadFile(); break; case QMessageBox::Cancel: // Nothing to do if user cancel this action @@ -167,14 +182,14 @@ void VEditTab::readFile() return; } } - textEditor->endEdit(); + m_textEditor->endEdit(); showFileReadMode(); } bool VEditTab::saveFile() { bool ret; - if (!isEditMode || !textEditor->isModified()) { + if (!isEditMode || !m_textEditor->isModified()) { return true; } // Make sure the file already exists. Temporary deal with cases when user delete or move @@ -187,15 +202,15 @@ bool VEditTab::saveFile() QMessageBox::Ok, QMessageBox::Ok, this); return false; } - textEditor->saveFile(); + m_textEditor->saveFile(); ret = m_file->save(); if (!ret) { VUtils::showMessage(QMessageBox::Warning, tr("Warning"), tr("Fail to save note"), QString("Fail to write to disk when saving a note. Please try it again."), QMessageBox::Ok, QMessageBox::Ok, this); - textEditor->setModified(true); + m_textEditor->setModified(true); } - emit statusChanged(); + noticeStatusChanged(); return ret; } @@ -353,7 +368,7 @@ void VEditTab::scrollToAnchor(const VAnchor &anchor) curHeader = anchor; if (isEditMode) { if (anchor.lineNumber > -1) { - textEditor->scrollToLine(anchor.lineNumber); + m_textEditor->scrollToLine(anchor.lineNumber); } } else { if (!anchor.anchor.isEmpty()) { diff --git a/src/vedittab.h b/src/vedittab.h index 06eb7807..ddb78009 100644 --- a/src/vedittab.h +++ b/src/vedittab.h @@ -12,7 +12,6 @@ #include "vtoc.h" #include "vfile.h" -class QTextBrowser; class QWebEngineView; class VNote; class QXmlStreamReader; @@ -38,6 +37,7 @@ public: void requestUpdateCurHeader(); void scrollToAnchor(const VAnchor& anchor); inline VFile *getFile(); + signals: void getFocused(); void outlineChanged(const VToc &toc); @@ -50,6 +50,7 @@ private slots: void updateCurHeader(const QString &anchor); void updateCurHeader(int lineNumber); void updateTocFromHeaders(const QVector &headers); + void handleTextChanged(); private: void setupUI(); @@ -60,16 +61,17 @@ private: inline bool isChild(QObject *obj); void parseTocUl(QXmlStreamReader &xml, QVector &headers, int level); void parseTocLi(QXmlStreamReader &xml, QVector &headers, int level); + void noticeStatusChanged(); QPointer m_file; bool isEditMode; - QTextBrowser *textBrowser; - VEdit *textEditor; + VEdit *m_textEditor; QWebEngineView *webPreviewer; VDocument document; MarkdownConverterType mdConverterType; VToc tableOfContent; VAnchor curHeader; + bool m_fileModified; }; inline bool VEditTab::getIsEditMode() const @@ -79,7 +81,7 @@ inline bool VEditTab::getIsEditMode() const inline bool VEditTab::isModified() const { - return textEditor->isModified(); + return m_textEditor->isModified(); } inline bool VEditTab::isChild(QObject *obj) diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 83d4a466..cf62a64b 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -530,6 +530,7 @@ void VMainWindow::setRenderBackgroundColor(QAction *action) void VMainWindow::updateToolbarFromTabChage(const VFile *p_file, bool p_editMode) { + qDebug() << "update toolbar"; if (!p_file) { editNoteAct->setVisible(false); saveExitAct->setVisible(false); diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp new file mode 100644 index 00000000..01eecc56 --- /dev/null +++ b/src/vmdedit.cpp @@ -0,0 +1,211 @@ +#include +#include "vmdedit.h" +#include "hgmarkdownhighlighter.h" +#include "vmdeditoperations.h" +#include "vnote.h" +#include "vconfigmanager.h" +#include "vtoc.h" +#include "utils/vutils.h" + +extern VConfigManager vconfig; + +VMdEdit::VMdEdit(VFile *p_file, QWidget *p_parent) + : VEdit(p_file, p_parent), m_mdHighlighter(NULL) +{ + Q_ASSERT(p_file->getDocType() == DocType::Markdown); + + setAcceptRichText(false); + m_mdHighlighter = new HGMarkdownHighlighter(vconfig.getMdHighlightingStyles(), + 500, document()); + connect(m_mdHighlighter, &HGMarkdownHighlighter::highlightCompleted, + this, &VMdEdit::generateEditOutline); + m_editOps = new VMdEditOperations(this, m_file); + + connect(this, &VMdEdit::cursorPositionChanged, + this, &VMdEdit::updateCurHeader); + + updateTabSettings(); + updateFontAndPalette(); +} + +void VMdEdit::updateFontAndPalette() +{ + setFont(vconfig.getMdEditFont()); + setPalette(vconfig.getMdEditPalette()); +} + +void VMdEdit::updateTabSettings() +{ + if (vconfig.getTabStopWidth() > 0) { + QFontMetrics metrics(vconfig.getMdEditFont()); + setTabStopWidth(vconfig.getTabStopWidth() * metrics.width(' ')); + } + m_expandTab = vconfig.getIsExpandTab(); + if (m_expandTab && (vconfig.getTabStopWidth() > 0)) { + m_tabSpaces = QString(vconfig.getTabStopWidth(), ' '); + } +} + +void VMdEdit::beginEdit() +{ + updateTabSettings(); + updateFontAndPalette(); + + setFont(vconfig.getMdEditFont()); + + setPlainText(m_file->getContent()); + + initInitImages(); + + setReadOnly(false); + setModified(false); +} + +void VMdEdit::endEdit() +{ + setReadOnly(true); + clearUnusedImages(); +} + +void VMdEdit::saveFile() +{ + if (!document()->isModified()) { + return; + } + m_file->setContent(toPlainText()); + document()->setModified(false); +} + +void VMdEdit::reloadFile() +{ + setPlainText(m_file->getContent()); + setModified(false); +} + +void VMdEdit::keyPressEvent(QKeyEvent *event) +{ + if ((event->key() == Qt::Key_Tab) && m_expandTab) { + QTextCursor cursor(document()); + cursor.setPosition(textCursor().position()); + cursor.insertText(m_tabSpaces); + return; + } + VEdit::keyPressEvent(event); +} + +bool VMdEdit::canInsertFromMimeData(const QMimeData *source) const +{ + return source->hasImage() || source->hasUrls() + || VEdit::canInsertFromMimeData(source); +} + +void VMdEdit::insertFromMimeData(const QMimeData *source) +{ + if (source->hasImage()) { + // Image data in the clipboard + bool ret = m_editOps->insertImageFromMimeData(source); + if (ret) { + return; + } + } else if (source->hasUrls()) { + // Paste an image file + bool ret = m_editOps->insertURLFromMimeData(source); + if (ret) { + return; + } + } + VEdit::insertFromMimeData(source); +} + +void VMdEdit::insertImage(const QString &p_name) +{ + m_insertedImages.append(p_name); +} + +void VMdEdit::initInitImages() +{ + m_initImages = VUtils::imagesFromMarkdownFile(m_file->retrivePath()); +} + +void VMdEdit::clearUnusedImages() +{ + QVector images = VUtils::imagesFromMarkdownFile(m_file->retrivePath()); + + if (!m_insertedImages.isEmpty()) { + QVector imageNames(images.size()); + for (int i = 0; i < imageNames.size(); ++i) { + imageNames[i] = VUtils::fileNameFromPath(images[i]); + } + + QDir dir = QDir(m_file->retriveImagePath()); + for (int i = 0; i < m_insertedImages.size(); ++i) { + QString name = m_insertedImages[i]; + int j; + for (j = 0; j < imageNames.size(); ++j) { + if (name == imageNames[j]) { + break; + } + } + + // Delete it + if (j == imageNames.size()) { + QString imagePath = dir.filePath(name); + QFile(imagePath).remove(); + qDebug() << "delete inserted image" << imagePath; + } + } + m_insertedImages.clear(); + } + + for (int i = 0; i < m_initImages.size(); ++i) { + QString imagePath = m_initImages[i]; + int j; + for (j = 0; j < images.size(); ++j) { + if (imagePath == images[j]) { + break; + } + } + + // Delete it + if (j == images.size()) { + QFile(imagePath).remove(); + qDebug() << "delete existing image" << imagePath; + } + } + m_initImages.clear(); +} + +void VMdEdit::updateCurHeader() +{ + int curHeader = 0; + QTextCursor cursor(this->textCursor()); + int curLine = cursor.block().firstLineNumber(); + for (int i = m_headers.size() - 1; i >= 0; --i) { + if (m_headers[i].lineNumber <= curLine) { + curHeader = m_headers[i].lineNumber; + break; + } + } + emit curHeaderChanged(curHeader); +} + +void VMdEdit::generateEditOutline() +{ + QTextDocument *doc = document(); + m_headers.clear(); + // Assume that each block contains only one line + // Only support # syntax for now + QRegExp headerReg("(#{1,6})\\s*(\\S.*)"); // Need to trim the spaces + for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next()) { + Q_ASSERT(block.lineCount() == 1); + if ((block.userState() == HighlightBlockState::BlockNormal) && + headerReg.exactMatch(block.text())) { + VHeader header(headerReg.cap(1).length(), + headerReg.cap(2).trimmed(), "", block.firstLineNumber()); + m_headers.append(header); + } + } + + emit headersChanged(m_headers); + updateCurHeader(); +} diff --git a/src/vmdedit.h b/src/vmdedit.h new file mode 100644 index 00000000..d4b07744 --- /dev/null +++ b/src/vmdedit.h @@ -0,0 +1,51 @@ +#ifndef VMDEDIT_H +#define VMDEDIT_H + +#include "vedit.h" +#include +#include +#include "vtoc.h" + +class HGMarkdownHighlighter; + +class VMdEdit : public VEdit +{ + Q_OBJECT +public: + VMdEdit(VFile *p_file, QWidget *p_parent = 0); + void beginEdit() Q_DECL_OVERRIDE; + void endEdit() Q_DECL_OVERRIDE; + void saveFile() Q_DECL_OVERRIDE; + void reloadFile() Q_DECL_OVERRIDE; + + void insertImage(const QString &p_name); + +signals: + void headersChanged(const QVector &headers); + void curHeaderChanged(int lineNumber); + +private slots: + void generateEditOutline(); + void updateCurHeader(); + +protected: + void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; + bool canInsertFromMimeData(const QMimeData *source) const Q_DECL_OVERRIDE; + void insertFromMimeData(const QMimeData *source) Q_DECL_OVERRIDE; + +private: + void updateFontAndPalette(); + void updateTabSettings(); + void initInitImages(); + void clearUnusedImages(); + + HGMarkdownHighlighter *m_mdHighlighter; + QVector m_insertedImages; + QVector m_initImages; + bool m_expandTab; + QString m_tabSpaces; + QVector m_headers; + +}; + +#endif // VMDEDIT_H diff --git a/src/vmdeditoperations.cpp b/src/vmdeditoperations.cpp index b39c503c..da877df5 100644 --- a/src/vmdeditoperations.cpp +++ b/src/vmdeditoperations.cpp @@ -13,6 +13,7 @@ #include "vedit.h" #include "vdownloader.h" #include "vfile.h" +#include "vmdedit.h" VMdEditOperations::VMdEditOperations(VEdit *p_editor, VFile *p_file) : VEditOperations(p_editor, p_file) @@ -54,7 +55,9 @@ void VMdEditOperations::insertImageFromQImage(const QString &title, const QStrin QString md = QString("![%1](images/%2)").arg(title).arg(fileName); insertTextAtCurPos(md); - m_editor->insertImage(fileName); + VMdEdit *mdEditor = dynamic_cast(m_editor); + Q_ASSERT(mdEditor); + mdEditor->insertImage(fileName); } void VMdEditOperations::insertImageFromPath(const QString &title, @@ -77,7 +80,9 @@ void VMdEditOperations::insertImageFromPath(const QString &title, QString md = QString("![%1](images/%2)").arg(title).arg(fileName); insertTextAtCurPos(md); - m_editor->insertImage(fileName); + VMdEdit *mdEditor = dynamic_cast(m_editor); + Q_ASSERT(mdEditor); + mdEditor->insertImage(fileName); } bool VMdEditOperations::insertImageFromURL(const QUrl &imageUrl)