diff --git a/README.md b/README.md index 93d6083a..84de95a3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ Users from China can download the latest release of VNote from [Baidu Netdisk](h - [Github releases](https://github.com/tamlok/vnote/releases) - Latest builds on master: [ ![Download](https://api.bintray.com/packages/tamlok/vnote/vnote/images/download.svg) ](https://bintray.com/tamlok/vnote/vnote/_latestVersion) +**NOT** supported in XP since QtWebEngineProcess used by VNote could not work in XP. + ## Linux [![Build Status](https://travis-ci.org/tamlok/vnote.svg?branch=master)](https://travis-ci.org/tamlok/vnote) diff --git a/README_zh.md b/README_zh.md index 374e0a69..e7a149ef 100644 --- a/README_zh.md +++ b/README_zh.md @@ -14,6 +14,8 @@ - [Github releases](https://github.com/tamlok/vnote/releases) - master分支的最新构建:[ ![Download](https://api.bintray.com/packages/tamlok/vnote/vnote/images/download.svg) ](https://bintray.com/tamlok/vnote/vnote/_latestVersion) +VNote不支持**XP**,因为QtWebEngineProcess无法在XP上运行。 + ## Linux [![Build Status](https://travis-ci.org/tamlok/vnote.svg?branch=master)](https://travis-ci.org/tamlok/vnote) diff --git a/src/dialog/vsettingsdialog.cpp b/src/dialog/vsettingsdialog.cpp index 84e01104..188e614d 100644 --- a/src/dialog/vsettingsdialog.cpp +++ b/src/dialog/vsettingsdialog.cpp @@ -10,25 +10,57 @@ extern VConfigManager *g_config; VSettingsDialog::VSettingsDialog(QWidget *p_parent) : QDialog(p_parent) { - m_tabs = new QTabWidget; - m_tabs->addTab(new VGeneralTab(), tr("General")); - m_tabs->addTab(new VReadEditTab(), tr("Read/Edit")); - m_tabs->addTab(new VNoteManagementTab(), tr("Note Management")); + m_tabList = new QListWidget(this); + m_tabList->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + + m_tabs = new QStackedLayout(); m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(m_btnBox, &QDialogButtonBox::accepted, this, &VSettingsDialog::saveConfiguration); connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(m_tabs); + QHBoxLayout *tabLayout = new QHBoxLayout(); + tabLayout->addWidget(m_tabList); + tabLayout->addLayout(m_tabs); + tabLayout->setContentsMargins(0, 0, 0, 0); + tabLayout->setSpacing(0); + tabLayout->setStretch(0, 0); + tabLayout->setStretch(1, 5); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addLayout(tabLayout); mainLayout->addWidget(m_btnBox); setLayout(mainLayout); setWindowTitle(tr("Settings")); + // Add tabs. + addTab(new VGeneralTab(), tr("General")); + addTab(new VReadEditTab(), tr("Read/Edit")); + addTab(new VNoteManagementTab(), tr("Note Management")); + addTab(new VMarkdownTab(), tr("Markdown")); + + m_tabList->setMaximumWidth(m_tabList->sizeHintForColumn(0) + 5); + + connect(m_tabList, &QListWidget::currentItemChanged, + this, [this](QListWidgetItem *p_cur, QListWidgetItem *p_pre) { + Q_UNUSED(p_pre); + Q_ASSERT(p_cur); + int idx = p_cur->data(Qt::UserRole).toInt(); + Q_ASSERT(idx >= 0); + m_tabs->setCurrentWidget(m_tabs->widget(idx)); + }); + loadConfiguration(); } +void VSettingsDialog::addTab(QWidget *p_widget, const QString &p_label) +{ + int idx = m_tabs->addWidget(p_widget); + QListWidgetItem *item = new QListWidgetItem(p_label, m_tabList); + item->setData(Qt::UserRole, idx); +} + void VSettingsDialog::loadConfiguration() { // General Tab. @@ -58,6 +90,15 @@ void VSettingsDialog::loadConfiguration() } } + // Markdown Tab. + { + VMarkdownTab *markdownTab = dynamic_cast(m_tabs->widget(3)); + Q_ASSERT(markdownTab); + if (!markdownTab->loadConfiguration()) { + goto err; + } + } + return; err: VUtils::showMessage(QMessageBox::Warning, tr("Warning"), @@ -95,6 +136,15 @@ void VSettingsDialog::saveConfiguration() } } + // Markdown Tab. + { + VMarkdownTab *markdownTab = dynamic_cast(m_tabs->widget(3)); + Q_ASSERT(markdownTab); + if (!markdownTab->saveConfiguration()) { + goto err; + } + } + accept(); return; err: @@ -234,25 +284,14 @@ VReadEditTab::VReadEditTab(QWidget *p_parent) zoomFactorLayout->addWidget(m_customWebZoom); zoomFactorLayout->addWidget(m_webZoomFactorSpin); - // Default note open mode. - m_openModeCombo = new QComboBox(); - m_openModeCombo->setToolTip(tr("Default mode to open a note")); - m_openModeCombo->addItem(tr("Read Mode"), (int)OpenFileMode::Read); - m_openModeCombo->addItem(tr("Edit Mode"), (int)OpenFileMode::Edit); - - QLabel *openModeLabel = new QLabel(tr("Note open mode:")); - openModeLabel->setToolTip(m_openModeCombo->toolTip()); - QFormLayout *readLayout = new QFormLayout(); readLayout->addRow(zoomFactorLayout); - readLayout->addRow(openModeLabel, m_openModeCombo); m_readBox->setLayout(readLayout); QVBoxLayout *mainLayout = new QVBoxLayout(); mainLayout->addWidget(m_readBox); mainLayout->addWidget(m_editBox); - m_editBox->hide(); setLayout(mainLayout); } @@ -262,10 +301,6 @@ bool VReadEditTab::loadConfiguration() return false; } - if (!loadOpenMode()) { - return false; - } - return true; } @@ -275,10 +310,6 @@ bool VReadEditTab::saveConfiguration() return false; } - if (!saveOpenMode()) { - return false; - } - return true; } @@ -315,29 +346,6 @@ void VReadEditTab::customWebZoomChanged(int p_state) m_webZoomFactorSpin->setEnabled(p_state == Qt::Checked); } -bool VReadEditTab::loadOpenMode() -{ - int mode = (int)g_config->getNoteOpenMode(); - bool found = false; - for (int i = 0; i < m_openModeCombo->count(); ++i) { - if (m_openModeCombo->itemData(i).toInt() == mode) { - m_openModeCombo->setCurrentIndex(i); - found = true; - break; - } - } - - Q_ASSERT(found); - return true; -} - -bool VReadEditTab::saveOpenMode() -{ - int mode = m_openModeCombo->currentData().toInt(); - g_config->setNoteOpenMode((OpenFileMode)mode); - return true; -} - VNoteManagementTab::VNoteManagementTab(QWidget *p_parent) : QWidget(p_parent) { @@ -487,3 +495,91 @@ void VNoteManagementTab::customImageFolderExtChanged(int p_state) m_imageFolderEditExt->setEnabled(false); } } + +VMarkdownTab::VMarkdownTab(QWidget *p_parent) + : QWidget(p_parent) +{ + // Default note open mode. + m_openModeCombo = new QComboBox(); + m_openModeCombo->setToolTip(tr("Default mode to open a note")); + m_openModeCombo->addItem(tr("Read Mode"), (int)OpenFileMode::Read); + m_openModeCombo->addItem(tr("Edit Mode"), (int)OpenFileMode::Edit); + + QLabel *openModeLabel = new QLabel(tr("Note open mode:")); + openModeLabel->setToolTip(m_openModeCombo->toolTip()); + + // Heading sequence. + m_headingSequence = new QCheckBox(); + m_headingSequence->setToolTip(tr("Enable auto sequence for all headings (in the form like 1.2.3.4.)")); + + QLabel *headingSequenceLabel = new QLabel(tr("Heading sequence:")); + headingSequenceLabel->setToolTip(m_headingSequence->toolTip()); + + QFormLayout *mainLayout = new QFormLayout(); + mainLayout->addRow(openModeLabel, m_openModeCombo); + mainLayout->addRow(headingSequenceLabel, m_headingSequence); + + setLayout(mainLayout); +} + +bool VMarkdownTab::loadConfiguration() +{ + if (!loadOpenMode()) { + return false; + } + + if (!loadHeadingSequence()) { + return false; + } + + return true; +} + +bool VMarkdownTab::saveConfiguration() +{ + if (!saveOpenMode()) { + return false; + } + + if (!saveHeadingSequence()) { + return false; + } + + return true; +} + +bool VMarkdownTab::loadOpenMode() +{ + int mode = (int)g_config->getNoteOpenMode(); + bool found = false; + for (int i = 0; i < m_openModeCombo->count(); ++i) { + if (m_openModeCombo->itemData(i).toInt() == mode) { + m_openModeCombo->setCurrentIndex(i); + found = true; + break; + } + } + + Q_ASSERT(found); + return true; +} + +bool VMarkdownTab::saveOpenMode() +{ + int mode = m_openModeCombo->currentData().toInt(); + g_config->setNoteOpenMode((OpenFileMode)mode); + return true; +} + +bool VMarkdownTab::loadHeadingSequence() +{ + bool enabled = g_config->getEnableHeadingSequence(); + m_headingSequence->setChecked(enabled); + return true; +} + +bool VMarkdownTab::saveHeadingSequence() +{ + g_config->setEnableHeadingSequence(m_headingSequence->isChecked()); + return true; +} diff --git a/src/dialog/vsettingsdialog.h b/src/dialog/vsettingsdialog.h index ed245285..c0ac1bd5 100644 --- a/src/dialog/vsettingsdialog.h +++ b/src/dialog/vsettingsdialog.h @@ -6,12 +6,13 @@ #include class QDialogButtonBox; -class QTabWidget; class QComboBox; class QGroupBox; class QDoubleSpinBox; class QCheckBox; class QLineEdit; +class QStackedLayout; +class QListWidget; class VGeneralTab : public QWidget { @@ -52,18 +53,12 @@ public: QCheckBox *m_customWebZoom; QDoubleSpinBox *m_webZoomFactorSpin; - // Default note open mode for markdown. - QComboBox *m_openModeCombo; - private slots: void customWebZoomChanged(int p_state); private: bool loadWebZoomFactor(); bool saveWebZoomFactor(); - - bool loadOpenMode(); - bool saveOpenMode(); }; class VNoteManagementTab : public QWidget @@ -97,6 +92,28 @@ private: bool saveImageFolderExt(); }; +class VMarkdownTab : public QWidget +{ + Q_OBJECT +public: + explicit VMarkdownTab(QWidget *p_parent = 0); + bool loadConfiguration(); + bool saveConfiguration(); + + // Default note open mode for markdown. + QComboBox *m_openModeCombo; + + // Whether enable heading sequence. + QCheckBox *m_headingSequence; + +private: + bool loadOpenMode(); + bool saveOpenMode(); + + bool loadHeadingSequence(); + bool saveHeadingSequence(); +}; + class VSettingsDialog : public QDialog { Q_OBJECT @@ -109,7 +126,10 @@ private slots: private: void loadConfiguration(); - QTabWidget *m_tabs; + void addTab(QWidget *p_widget, const QString &p_label); + + QStackedLayout *m_tabs; + QListWidget *m_tabList; QDialogButtonBox *m_btnBox; }; diff --git a/src/hgmarkdownhighlighter.cpp b/src/hgmarkdownhighlighter.cpp index 979410bb..298223db 100644 --- a/src/hgmarkdownhighlighter.cpp +++ b/src/hgmarkdownhighlighter.cpp @@ -278,9 +278,56 @@ void HGMarkdownHighlighter::initImageRegionsFromResult() m_imageRegions.resize(idx); } - emit imageLinksUpdated(m_imageRegions); - qDebug() << "highlighter: parse" << m_imageRegions.size() << "image regions"; + + emit imageLinksUpdated(m_imageRegions); +} + +void HGMarkdownHighlighter::initHeaderRegionsFromResult() +{ + if (!result) { + // From Qt5.7, the capacity is preserved. + m_headerRegions.clear(); + emit headersUpdated(m_headerRegions); + return; + } + + int idx = 0; + int oriSize = m_headerRegions.size(); + pmh_element_type hx[6] = {pmh_H1, pmh_H2, pmh_H3, pmh_H4, pmh_H5, pmh_H6}; + for (int i = 0; i < 6; ++i) { + pmh_element *elem = result[hx[i]]; + while (elem != NULL) { + if (elem->end <= elem->pos) { + elem = elem->next; + continue; + } + + if (idx < oriSize) { + // Try to reuse the original element. + VElementRegion ® = m_headerRegions[idx]; + if ((int)elem->pos != reg.m_startPos || (int)elem->end != reg.m_endPos) { + reg.m_startPos = (int)elem->pos; + reg.m_endPos = (int)elem->end; + } + } else { + m_headerRegions.push_back(VElementRegion(elem->pos, elem->end)); + } + + ++idx; + elem = elem->next; + } + } + + if (idx < oriSize) { + m_headerRegions.resize(idx); + } + + std::sort(m_headerRegions.begin(), m_headerRegions.end()); + + qDebug() << "highlighter: parse" << m_headerRegions.size() << "header regions"; + + emit headersUpdated(m_headerRegions); } void HGMarkdownHighlighter::initBlockHighlihgtOne(unsigned long pos, unsigned long end, int styleIndex) @@ -399,6 +446,8 @@ void HGMarkdownHighlighter::parse() initImageRegionsFromResult(); + initHeaderRegionsFromResult(); + if (result) { pmh_free_elements(result); result = NULL; diff --git a/src/hgmarkdownhighlighter.h b/src/hgmarkdownhighlighter.h index 48402b6d..99f6b5dd 100644 --- a/src/hgmarkdownhighlighter.h +++ b/src/hgmarkdownhighlighter.h @@ -106,6 +106,17 @@ struct VElementRegion return (m_startPos == p_other.m_startPos && m_endPos == p_other.m_endPos); } + + bool operator<(const VElementRegion &p_other) const + { + if (m_startPos < p_other.m_startPos) { + return true; + } else if (m_startPos == p_other.m_startPos) { + return m_endPos <= p_other.m_endPos; + } else { + return false; + } + } }; class HGMarkdownHighlighter : public QSyntaxHighlighter @@ -133,6 +144,9 @@ signals: // Emitted when image regions have been fetched from a new parsing result. void imageLinksUpdated(const QVector &p_imageRegions); + // Emitted when header regions have been fetched from a new parsing result. + void headersUpdated(const QVector &p_headerRegions); + protected: void highlightBlock(const QString &text) Q_DECL_OVERRIDE; @@ -174,6 +188,11 @@ private: // All image link regions. QVector m_imageRegions; + // All header regions. + // May contains illegal elements. + // Sorted by start position. + QVector m_headerRegions; + // Timer to signal highlightCompleted(). QTimer *m_completeTimer; @@ -211,6 +230,9 @@ private: // Fetch all the image link regions from parsing result. void initImageRegionsFromResult(); + // Fetch all the header regions from parsing result. + void initHeaderRegionsFromResult(); + // Whether @p_block is totally inside a HTML comment. bool isBlockInsideCommentRegion(const QTextBlock &p_block) const; diff --git a/src/resources/docs/shortcuts_en.md b/src/resources/docs/shortcuts_en.md index c0d0557c..46a0a035 100644 --- a/src/resources/docs/shortcuts_en.md +++ b/src/resources/docs/shortcuts_en.md @@ -189,4 +189,4 @@ VNote supports following features of Vim: For now, VNote does **NOT** support the macro and repeat(`.`) features of Vim. -Enjoy Vim on VNote! +Enjoy Vim in VNote! diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index b032ab4d..03e0a214 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -83,6 +83,9 @@ insert_title_from_note_name=true ; 0 - Read, 1 - Edit note_open_mode=0 +; Whether auto generate heading sequence +enable_heading_sequence=false + [session] tools_dock_checked=true diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index be92d588..b299e840 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -39,9 +39,9 @@ const QString VUtils::c_fencedCodeBlockEndRegExp = QString("^(\\s*)```$"); const QString VUtils::c_previewImageBlockRegExp = QString("[\\n|^][ |\\t]*\\xfffc[ |\\t]*(?=\\n)"); -VUtils::VUtils() -{ -} +const QString VUtils::c_headerRegExp = QString("^(#{1,6})\\s+(((\\d+\\.)+(?=\\s))?\\s?\\S.*)\\s*$"); + +const QString VUtils::c_headerPrefixRegExp = QString("^(#{1,6}\\s+((\\d+\\.)+(?=\\s))?\\s?)\\S.*\\s*$"); void VUtils::initAvailableLanguage() { diff --git a/src/utils/vutils.h b/src/utils/vutils.h index 0e417790..84cbdc0a 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -144,8 +144,21 @@ public: // Regular expression for preview image block. static const QString c_previewImageBlockRegExp; + // Regular expression for header block. + // Captured texts: + // 1. Header marker (##); + // 2. Header Title (need to be trimmed); + // 3. Header Sequence (1.1., 1.2., optional); + // 4. Unused; + static const QString c_headerRegExp; + + // Regular expression for header block. + // Captured texts: + // 1. prefix till the real header title content; + static const QString c_headerPrefixRegExp; + private: - VUtils(); + VUtils() {} static void initAvailableLanguage(); diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index 20d21af5..f88be7ad 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -174,6 +174,9 @@ void VConfigManager::initialize() } else { m_noteOpenMode = OpenFileMode::Read; } + + m_enableHeadingSequence = getConfigFromSettings("global", + "enable_heading_sequence").toBool(); } void VConfigManager::readPredefinedColorsFromSettings() diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index 6040551c..87ebdf01 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -232,6 +232,9 @@ public: OpenFileMode getNoteOpenMode() const; void setNoteOpenMode(OpenFileMode p_mode); + bool getEnableHeadingSequence() const; + void setEnableHeadingSequence(bool p_enabled); + // Return the configured key sequence of @p_operation. // Return empty if there is no corresponding config. QString getShortcutKeySequence(const QString &p_operation) const; @@ -469,6 +472,9 @@ private: // Default mode when opening a note. OpenFileMode m_noteOpenMode; + // Whether auto genearte heading sequence. + bool m_enableHeadingSequence; + // The name of the config file in each directory, obsolete. // Use c_dirConfigFile instead. static const QString c_obsoleteDirConfigFile; @@ -1204,4 +1210,20 @@ inline void VConfigManager::setNoteOpenMode(OpenFileMode p_mode) m_noteOpenMode == OpenFileMode::Read ? 0 : 1); } +inline bool VConfigManager::getEnableHeadingSequence() const +{ + return m_enableHeadingSequence; +} + +inline void VConfigManager::setEnableHeadingSequence(bool p_enabled) +{ + if (m_enableHeadingSequence == p_enabled) { + return; + } + + m_enableHeadingSequence = p_enabled; + setConfigToSettings("global", "enable_heading_sequence", + m_enableHeadingSequence); +} + #endif // VCONFIGMANAGER_H diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp index 20c694ae..9970a89a 100644 --- a/src/vmdedit.cpp +++ b/src/vmdedit.cpp @@ -31,8 +31,9 @@ VMdEdit::VMdEdit(VFile *p_file, VDocument *p_vdoc, MarkdownConverterType p_type, g_config->getCodeBlockStyles(), g_config->getMarkdownHighlightInterval(), document()); - connect(m_mdHighlighter, &HGMarkdownHighlighter::highlightCompleted, - this, &VMdEdit::generateEditOutline); + + connect(m_mdHighlighter, &HGMarkdownHighlighter::headersUpdated, + this, &VMdEdit::updateOutline); // After highlight, the cursor may trun into non-visible. We should make it visible // in this case. @@ -99,9 +100,6 @@ void VMdEdit::beginEdit() setModified(false); - // Request update outline. - generateEditOutline(); - if (m_freshEdit) { // Will set to false when all async jobs completed. setReadOnly(true); @@ -110,6 +108,8 @@ void VMdEdit::beginEdit() } else { setReadOnly(false); } + + m_mdHighlighter->updateHighlight(); } void VMdEdit::endEdit() @@ -330,24 +330,98 @@ void VMdEdit::updateCurHeader() emit curHeaderChanged(VAnchor(m_file, "", m_headers[idx].lineNumber, m_headers[idx].index)); } -void VMdEdit::generateEditOutline() +static void addHeaderSequence(QVector &p_sequence, int p_level) +{ + Q_ASSERT(p_level >= 1 && p_level < p_sequence.size()); + ++p_sequence[p_level]; + for (int i = p_level + 1; i < p_sequence.size(); ++i) { + p_sequence[i] = 0; + } +} + +static QString headerSequenceStr(const QVector &p_sequence) +{ + QString res; + for (int i = 1; i < p_sequence.size(); ++i) { + if (p_sequence[i] != 0) { + res = res + QString::number(p_sequence[i]) + '.'; + } else if (res.isEmpty()) { + continue; + } else { + break; + } + } + + return res; +} + +static void insertSequenceToHeader(QTextBlock &p_block, + QRegExp &p_reg, + QRegExp &p_preReg, + const QString &p_seq) +{ + if (!p_block.isValid()) { + return; + } + + QString text = p_block.text(); + bool matched = p_reg.exactMatch(text); + Q_ASSERT(matched); + + matched = p_preReg.exactMatch(text); + Q_ASSERT(matched); + + int start = p_reg.cap(1).length() + 1; + int end = p_preReg.cap(1).length(); + + Q_ASSERT(start <= end); + + QTextCursor cursor(p_block); + cursor.setPosition(p_block.position() + start); + if (start != end) { + cursor.setPosition(p_block.position() + end, QTextCursor::KeepAnchor); + } + + cursor.insertText(p_seq + ' '); +} + +void VMdEdit::updateOutline(const QVector &p_headerRegions) { QTextDocument *doc = document(); QVector headers; + QVector headerBlockNumbers; + QVector headerSequences; + if (!p_headerRegions.isEmpty()) { + headers.reserve(p_headerRegions.size()); + headerBlockNumbers.reserve(p_headerRegions.size()); + headerSequences.reserve(p_headerRegions.size()); + } // Assume that each block contains only one line // Only support # syntax for now - QRegExp headerReg("(#{1,6})\\s+(\\S.*)"); // Need to trim the spaces + QRegExp headerReg(VUtils::c_headerRegExp); int baseLevel = -1; - for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next()) { - V_ASSERT(block.lineCount() == 1); + for (auto const & reg : p_headerRegions) { + QTextBlock block = doc->findBlock(reg.m_startPos); + if (!block.isValid()) { + continue; + } + + Q_ASSERT(block.lineCount() == 1); + + if (!block.contains(reg.m_endPos - 1)) { + continue; + } + if ((block.userState() == HighlightBlockState::Normal) && headerReg.exactMatch(block.text())) { int level = headerReg.cap(1).length(); VHeader header(level, headerReg.cap(2).trimmed(), "", block.firstLineNumber(), headers.size()); headers.append(header); + headerBlockNumbers.append(block.blockNumber()); + headerSequences.append(headerReg.cap(3)); if (baseLevel == -1) { baseLevel = level; @@ -359,18 +433,37 @@ void VMdEdit::generateEditOutline() m_headers.clear(); + bool autoSequence = g_config->getEnableHeadingSequence() && !isReadOnly(); + QVector seqs(7, 0); + QRegExp preReg(VUtils::c_headerPrefixRegExp); int curLevel = baseLevel - 1; - for (auto & item : headers) { + for (int i = 0; i < headers.size(); ++i) { + VHeader &item = headers[i]; while (item.level > curLevel + 1) { curLevel += 1; // Insert empty level which is an invalid header. m_headers.append(VHeader(curLevel, c_emptyHeaderName, "", -1, m_headers.size())); + if (autoSequence) { + addHeaderSequence(seqs, curLevel); + } } item.index = m_headers.size(); m_headers.append(item); curLevel = item.level; + if (autoSequence) { + addHeaderSequence(seqs, item.level); + + QString seqStr = headerSequenceStr(seqs); + if (headerSequences[i] != seqStr) { + // Insert correct sequence. + insertSequenceToHeader(doc->findBlockByNumber(headerBlockNumbers[i]), + headerReg, + preReg, + seqStr); + } + } } emit headersChanged(m_headers); @@ -670,10 +763,10 @@ void VMdEdit::finishOneAsyncJob(int p_idx) m_finishedAsyncJobs[p_idx] = true; if (-1 == m_finishedAsyncJobs.indexOf(false)) { // All jobs finished. - m_freshEdit = false; setUndoRedoEnabled(true); setReadOnly(false); setModified(false); + m_freshEdit = false; emit statusChanged(); } } diff --git a/src/vmdedit.h b/src/vmdedit.h index 0ce63816..db6cb07a 100644 --- a/src/vmdedit.h +++ b/src/vmdedit.h @@ -53,7 +53,7 @@ signals: void statusChanged(); private slots: - void generateEditOutline(); + void updateOutline(const QVector &p_headerRegions); // When there is no header in current cursor, will signal an invalid header. void updateCurHeader();