From b0d3e42647176827e004137d533ab34a77dc62f4 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Sat, 1 Apr 2017 19:58:12 +0800 Subject: [PATCH] refine edit mode 1. Support "Ctrl+Alt+" to insert title in Markdown; 2. Support Auto Indent; 3. Support Auto List; --- src/resources/vnote.ini | 2 + src/vconfigmanager.cpp | 2 + src/vconfigmanager.h | 42 ++++++++++++ src/vmainwindow.cpp | 67 +++++++++++++++----- src/vmainwindow.h | 4 ++ src/vmdeditoperations.cpp | 130 ++++++++++++++++++++++++++++++++++++++ src/vmdeditoperations.h | 4 ++ 7 files changed, 234 insertions(+), 17 deletions(-) diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 3383423f..01389110 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -7,6 +7,8 @@ is_expand_tab=true highlight_cursor_line=true highlight_selected_word=true highlight_searched_word=true +auto_indent=true +auto_list=true current_background_color=System current_render_background_color=System language=System diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index 36b7fb1c..f949735d 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -57,6 +57,8 @@ void VConfigManager::initialize() m_highlightCursorLine = getConfigFromSettings("global", "highlight_cursor_line").toBool(); m_highlightSelectedWord = getConfigFromSettings("global", "highlight_selected_word").toBool(); m_highlightSearchedWord = getConfigFromSettings("global", "highlight_searched_word").toBool(); + m_autoIndent = getConfigFromSettings("global", "auto_indent").toBool(); + m_autoList = getConfigFromSettings("global", "auto_list").toBool(); readPredefinedColorsFromSettings(); curBackgroundColor = getConfigFromSettings("global", "current_background_color").toString(); diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index 89a3b0a6..2be1ccc0 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -81,6 +81,12 @@ public: inline bool getHighlightSearchedWord() const; inline void setHighlightSearchedWord(bool p_searchedWord); + inline bool getAutoIndent() const; + inline void setAutoIndent(bool p_autoIndent); + + inline bool getAutoList() const; + inline void setAutoList(bool p_autoList); + inline const QVector &getPredefinedColors() const; inline const QString &getCurBackgroundColor() const; @@ -167,6 +173,12 @@ private: // Highlight searched word. bool m_highlightSearchedWord; + // Auto Indent. + bool m_autoIndent; + + // Auto List. + bool m_autoList; + // App defined color QVector predefinedColors; QString curBackgroundColor; @@ -362,6 +374,36 @@ inline void VConfigManager::setHighlightSearchedWord(bool p_searchedWord) m_highlightSearchedWord); } +inline bool VConfigManager::getAutoIndent() const +{ + return m_autoIndent; +} + +inline void VConfigManager::setAutoIndent(bool p_autoIndent) +{ + if (m_autoIndent == p_autoIndent) { + return; + } + m_autoIndent = p_autoIndent; + setConfigToSettings("global", "auto_indent", + m_autoIndent); +} + +inline bool VConfigManager::getAutoList() const +{ + return m_autoList; +} + +inline void VConfigManager::setAutoList(bool p_autoList) +{ + if (m_autoList == p_autoList) { + return; + } + m_autoList = p_autoList; + setConfigToSettings("global", "auto_list", + m_autoList); +} + inline const QVector& VConfigManager::getPredefinedColors() const { return predefinedColors; diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 558b148f..ab10c0f8 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -467,6 +467,20 @@ void VMainWindow::initEditMenu() connect(tabStopWidthAct, &QActionGroup::triggered, this, &VMainWindow::setTabStopWidth); + // Auto Indent. + m_autoIndentAct = new QAction(tr("Auto Indent"), this); + m_autoIndentAct->setStatusTip(tr("Indent automatically when inserting a new line")); + m_autoIndentAct->setCheckable(true); + connect(m_autoIndentAct, &QAction::triggered, + this, &VMainWindow::changeAutoIndent); + + // Auto List. + QAction *autoListAct = new QAction(tr("Auto List"), this); + autoListAct->setStatusTip(tr("Continue the list automatically when inserting a new line")); + autoListAct->setCheckable(true); + connect(autoListAct, &QAction::triggered, + this, &VMainWindow::changeAutoList); + // Highlight current cursor line. QAction *cursorLineAct = new QAction(tr("Highlight Cursor Line"), this); cursorLineAct->setStatusTip(tr("Highlight current cursor line")); @@ -494,11 +508,7 @@ void VMainWindow::initEditMenu() findReplaceMenu->addAction(m_replaceAllAct); findReplaceMenu->addSeparator(); findReplaceMenu->addAction(searchedWordAct); - if (vconfig.getHighlightSearchedWord()) { - searchedWordAct->setChecked(true); - } else { - searchedWordAct->setChecked(false); - } + searchedWordAct->setChecked(vconfig.getHighlightSearchedWord()); editMenu->addSeparator(); m_findReplaceAct->setEnabled(false); @@ -532,21 +542,26 @@ void VMainWindow::initEditMenu() default: qWarning() << "unsupported tab stop width" << tabStopWidth << "in config"; } - initEditorBackgroundMenu(editMenu); - editMenu->addSeparator(); - editMenu->addAction(cursorLineAct); - if (vconfig.getHighlightCursorLine()) { - cursorLineAct->setChecked(true); - } else { - cursorLineAct->setChecked(false); + + editMenu->addAction(m_autoIndentAct); + m_autoIndentAct->setChecked(vconfig.getAutoIndent()); + + editMenu->addAction(autoListAct); + if (vconfig.getAutoList()) { + // Let the trigger handler to trigger m_autoIndentAct, too. + autoListAct->trigger(); } + Q_ASSERT(!(autoListAct->isChecked() && !m_autoIndentAct->isChecked())); + + editMenu->addSeparator(); + + initEditorBackgroundMenu(editMenu); + + editMenu->addAction(cursorLineAct); + cursorLineAct->setChecked(vconfig.getHighlightCursorLine()); editMenu->addAction(selectedWordAct); - if (vconfig.getHighlightSelectedWord()) { - selectedWordAct->setChecked(true); - } else { - selectedWordAct->setChecked(false); - } + selectedWordAct->setChecked(vconfig.getHighlightSelectedWord()); } void VMainWindow::initDockWindows() @@ -1075,3 +1090,21 @@ void VMainWindow::closeCurrentFile() } } +void VMainWindow::changeAutoIndent(bool p_checked) +{ + vconfig.setAutoIndent(p_checked); +} + +void VMainWindow::changeAutoList(bool p_checked) +{ + vconfig.setAutoList(p_checked); + if (p_checked) { + if (!m_autoIndentAct->isChecked()) { + m_autoIndentAct->trigger(); + } + m_autoIndentAct->setEnabled(false); + } else { + m_autoIndentAct->setEnabled(true); + } +} + diff --git a/src/vmainwindow.h b/src/vmainwindow.h index b8bc3428..13448f3f 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -68,6 +68,8 @@ private slots: void enableMermaid(bool p_checked); void enableMathjax(bool p_checked); void handleCaptainModeChanged(bool p_enabled); + void changeAutoIndent(bool p_checked); + void changeAutoList(bool p_checked); protected: void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; @@ -148,6 +150,8 @@ private: QAction *m_replaceFindAct; QAction *m_replaceAllAct; + QAction *m_autoIndentAct; + // Menus QMenu *viewMenu; diff --git a/src/vmdeditoperations.cpp b/src/vmdeditoperations.cpp index d57cdc94..18384b5a 100644 --- a/src/vmdeditoperations.cpp +++ b/src/vmdeditoperations.cpp @@ -20,6 +20,9 @@ #include "vdownloader.h" #include "vfile.h" #include "vmdedit.h" +#include "vconfigmanager.h" + +extern VConfigManager vconfig; const QString VMdEditOperations::c_defaultImageTitle = "image"; @@ -178,7 +181,25 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event) return true; } } else { + int modifiers = p_event->modifiers(); switch (p_event->key()) { + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + { + if (modifiers == (Qt::ControlModifier | Qt::AltModifier)) { + // Ctrl + Alt + : insert title at level . + if (insertTitle(p_event->key() - Qt::Key_0)) { + p_event->accept(); + return true; + } + } + break; + } + case Qt::Key_Tab: { if (handleKeyTab(p_event)) { @@ -267,6 +288,14 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event) break; } + case Qt::Key_Return: + { + if (handleKeyReturn(p_event)) { + return true; + } + break; + } + default: break; } @@ -612,6 +641,73 @@ bool VMdEditOperations::handleKeyEsc(QKeyEvent *p_event) return accept; } +bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event) +{ + if (p_event->modifiers() & Qt::ControlModifier) { + return false; + } + + bool ret = false; + if (vconfig.getAutoIndent()) { + ret = true; + // Indent the new line as previous line. + insertNewBlockWithIndent(); + + // Continue the list from previous line. + if (vconfig.getAutoList()) { + insertListMarkAsPreviousLine(); + } + } + return ret; +} + +void VMdEditOperations::insertNewBlockWithIndent() +{ + QTextCursor cursor = m_editor->textCursor(); + + cursor.beginEditBlock(); + cursor.removeSelectedText(); + QTextBlock block = cursor.block(); + QString text = block.text(); + QRegExp regExp("(^\\s*)"); + regExp.indexIn(text); + Q_ASSERT(regExp.captureCount() == 1); + QString leadingSpaces = regExp.capturedTexts()[1]; + cursor.insertBlock(); + cursor.insertText(leadingSpaces); + cursor.endEditBlock(); + m_editor->setTextCursor(cursor); +} + +void VMdEditOperations::insertListMarkAsPreviousLine() +{ + QTextCursor cursor = m_editor->textCursor(); + QTextBlock block = cursor.block(); + QTextBlock preBlock = block.previous(); + QString text = preBlock.text(); + QRegExp regExp("^\\s*(-|\\d+\\.)\\s"); + int regIdx = regExp.indexIn(text); + if (regIdx != -1) { + Q_ASSERT(regExp.captureCount() == 1); + cursor.beginEditBlock(); + QString markText = regExp.capturedTexts()[1]; + if (markText == "-") { + // Insert - in front. + cursor.insertText("- "); + } else { + // markText is like "123.". + Q_ASSERT(markText.endsWith('.')); + bool ok = false; + int num = markText.left(markText.size() - 1).toInt(&ok, 10); + Q_ASSERT(ok); + num++; + cursor.insertText(QString::number(num, 10) + ". "); + } + cursor.endEditBlock(); + m_editor->setTextCursor(cursor); + } +} + bool VMdEditOperations::handleKeyPressVim(QKeyEvent *p_event) { int modifiers = p_event->modifiers(); @@ -1004,3 +1100,37 @@ void VMdEditOperations::setKeyState(KeyState p_state) m_keyState = p_state; emit keyStateChanged(m_keyState); } + +bool VMdEditOperations::insertTitle(int p_level) +{ + Q_ASSERT(p_level > 0 && p_level < 7); + QTextDocument *doc = m_editor->document(); + QString titleMark(p_level, '#'); + QTextCursor cursor = m_editor->textCursor(); + if (cursor.hasSelection()) { + // Insert title # in front of the selected lines. + int start = cursor.selectionStart(); + int end = cursor.selectionEnd(); + int startBlock = doc->findBlock(start).blockNumber(); + int endBlock = doc->findBlock(end).blockNumber(); + cursor.beginEditBlock(); + cursor.clearSelection(); + for (int i = startBlock; i <= endBlock; ++i) { + QTextBlock block = doc->findBlockByNumber(i); + cursor.setPosition(block.position(), QTextCursor::MoveAnchor); + cursor.insertText(titleMark + " "); + } + cursor.movePosition(QTextCursor::EndOfBlock); + cursor.endEditBlock(); + } else { + // Insert title # in front of current block. + cursor.beginEditBlock(); + cursor.movePosition(QTextCursor::StartOfBlock); + cursor.insertText(titleMark + " "); + cursor.movePosition(QTextCursor::EndOfBlock); + cursor.endEditBlock(); + } + m_editor->setTextCursor(cursor); + return true; +} + diff --git a/src/vmdeditoperations.h b/src/vmdeditoperations.h index bc7f26b9..15ad6077 100644 --- a/src/vmdeditoperations.h +++ b/src/vmdeditoperations.h @@ -39,11 +39,15 @@ private: bool handleKeyU(QKeyEvent *p_event); bool handleKeyW(QKeyEvent *p_event); bool handleKeyEsc(QKeyEvent *p_event); + bool handleKeyReturn(QKeyEvent *p_event); bool handleKeyPressVim(QKeyEvent *p_event); bool handleKeyBracketLeft(QKeyEvent *p_event); bool shouldTriggerVimMode(QKeyEvent *p_event); int keySeqToNumber(const QList &p_seq); bool suffixNumAllowed(const QList &p_seq); + bool insertTitle(int p_level); + void insertNewBlockWithIndent(); + void insertListMarkAsPreviousLine(); QTimer *m_pendingTimer;