Browse Source

refine edit mode

1. Support "Ctrl+Alt+<N>" to insert title in Markdown;
2. Support Auto Indent;
3. Support Auto List;
Le Tan 8 years ago
parent
commit
b0d3e42647
7 changed files with 233 additions and 16 deletions
  1. 2 0
      src/resources/vnote.ini
  2. 2 0
      src/vconfigmanager.cpp
  3. 42 0
      src/vconfigmanager.h
  4. 49 16
      src/vmainwindow.cpp
  5. 4 0
      src/vmainwindow.h
  6. 130 0
      src/vmdeditoperations.cpp
  7. 4 0
      src/vmdeditoperations.h

+ 2 - 0
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

+ 2 - 0
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();

+ 42 - 0
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<VColor> &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<VColor> 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<VColor>& VConfigManager::getPredefinedColors() const
 {
     return predefinedColors;

+ 49 - 16
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->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);
-    if (vconfig.getHighlightCursorLine()) {
-        cursorLineAct->setChecked(true);
-    } else {
-        cursorLineAct->setChecked(false);
-    }
+    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);
+    }
+}
+

+ 4 - 0
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;
 

+ 130 - 0
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 + <N>: insert title at level <N>.
+                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;
+}
+

+ 4 - 0
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<QString> &p_seq);
     bool suffixNumAllowed(const QList<QString> &p_seq);
+    bool insertTitle(int p_level);
+    void insertNewBlockWithIndent();
+    void insertListMarkAsPreviousLine();
 
     QTimer *m_pendingTimer;