diff --git a/src/dialog/vsettingsdialog.cpp b/src/dialog/vsettingsdialog.cpp index 3d12ed50..5191f219 100644 --- a/src/dialog/vsettingsdialog.cpp +++ b/src/dialog/vsettingsdialog.cpp @@ -603,28 +603,34 @@ VMarkdownTab::VMarkdownTab(QWidget *p_parent) 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(tr("Heading sequence")); - m_headingSequence->setToolTip(tr("Enable auto sequence for all headings (in the form like 1.2.3.4.)")); - m_headingSequenceCombo = new QComboBox(); - m_headingSequenceCombo->setToolTip(tr("Base level to start heading sequence")); - m_headingSequenceCombo->addItem(tr("1"), 1); - m_headingSequenceCombo->addItem(tr("2"), 2); - m_headingSequenceCombo->addItem(tr("3"), 3); - m_headingSequenceCombo->addItem(tr("4"), 4); - m_headingSequenceCombo->addItem(tr("5"), 5); - m_headingSequenceCombo->addItem(tr("6"), 6); - m_headingSequenceCombo->setEnabled(false); - connect(m_headingSequence, &QCheckBox::stateChanged, - this, [this](int p_state){ - this->m_headingSequenceCombo->setEnabled(p_state == Qt::Checked); + m_headingSequenceTypeCombo = new QComboBox(); + m_headingSequenceTypeCombo->setToolTip(tr("Enable auto sequence for all headings (in the form like 1.2.3.4.)")); + m_headingSequenceTypeCombo->addItem(tr("Disabled"), (int)HeadingSequenceType::Disabled); + m_headingSequenceTypeCombo->addItem(tr("Enabled"), (int)HeadingSequenceType::Enabled); + m_headingSequenceTypeCombo->addItem(tr("Enabled for notes only"), (int)HeadingSequenceType::EnabledNoteOnly); + + m_headingSequenceLevelCombo = new QComboBox(); + m_headingSequenceLevelCombo->setToolTip(tr("Base level to start heading sequence")); + m_headingSequenceLevelCombo->addItem(tr("1"), 1); + m_headingSequenceLevelCombo->addItem(tr("2"), 2); + m_headingSequenceLevelCombo->addItem(tr("3"), 3); + m_headingSequenceLevelCombo->addItem(tr("4"), 4); + m_headingSequenceLevelCombo->addItem(tr("5"), 5); + m_headingSequenceLevelCombo->addItem(tr("6"), 6); + m_headingSequenceLevelCombo->setEnabled(false); + + connect(m_headingSequenceTypeCombo, static_cast(&QComboBox::activated), + this, [this](int p_index){ + if (p_index > -1) { + HeadingSequenceType type = (HeadingSequenceType)m_headingSequenceTypeCombo->itemData(p_index).toInt(); + m_headingSequenceLevelCombo->setEnabled(type != HeadingSequenceType::Disabled); + } }); + QHBoxLayout *headingSequenceLayout = new QHBoxLayout(); - headingSequenceLayout->addWidget(m_headingSequence); - headingSequenceLayout->addWidget(m_headingSequenceCombo); + headingSequenceLayout->addWidget(m_headingSequenceTypeCombo); + headingSequenceLayout->addWidget(m_headingSequenceLevelCombo); // Web Zoom Factor. m_customWebZoom = new QCheckBox(tr("Custom Web zoom factor"), this); @@ -652,8 +658,8 @@ VMarkdownTab::VMarkdownTab(QWidget *p_parent) colorColumnLabel->setToolTip(m_colorColumnEdit->toolTip()); QFormLayout *mainLayout = new QFormLayout(); - mainLayout->addRow(openModeLabel, m_openModeCombo); - mainLayout->addRow(headingSequenceLayout); + mainLayout->addRow(tr("Note open mode:"), m_openModeCombo); + mainLayout->addRow(tr("Heading sequence:"), headingSequenceLayout); mainLayout->addRow(zoomFactorLayout); mainLayout->addRow(colorColumnLabel, m_colorColumnEdit); @@ -727,21 +733,28 @@ bool VMarkdownTab::saveOpenMode() bool VMarkdownTab::loadHeadingSequence() { - bool enabled = g_config->getEnableHeadingSequence(); + HeadingSequenceType type = g_config->getHeadingSequenceType(); int level = g_config->getHeadingSequenceBaseLevel(); if (level < 1 || level > 6) { level = 1; } - m_headingSequence->setChecked(enabled); - m_headingSequenceCombo->setCurrentIndex(level - 1); + int idx = m_headingSequenceTypeCombo->findData((int)type); + Q_ASSERT(idx > -1); + m_headingSequenceTypeCombo->setCurrentIndex(idx); + m_headingSequenceLevelCombo->setCurrentIndex(level - 1); + m_headingSequenceLevelCombo->setEnabled(type != HeadingSequenceType::Disabled); + return true; } bool VMarkdownTab::saveHeadingSequence() { - g_config->setEnableHeadingSequence(m_headingSequence->isChecked()); - g_config->setHeadingSequenceBaseLevel(m_headingSequenceCombo->currentData().toInt()); + QVariant typeData = m_headingSequenceTypeCombo->currentData(); + Q_ASSERT(typeData.isValid()); + g_config->setHeadingSequenceType((HeadingSequenceType)typeData.toInt()); + g_config->setHeadingSequenceBaseLevel(m_headingSequenceLevelCombo->currentData().toInt()); + return true; } diff --git a/src/dialog/vsettingsdialog.h b/src/dialog/vsettingsdialog.h index 3ed31cda..2406134f 100644 --- a/src/dialog/vsettingsdialog.h +++ b/src/dialog/vsettingsdialog.h @@ -117,8 +117,8 @@ public: QComboBox *m_openModeCombo; // Whether enable heading sequence. - QCheckBox *m_headingSequence; - QComboBox *m_headingSequenceCombo; + QComboBox *m_headingSequenceTypeCombo; + QComboBox *m_headingSequenceLevelCombo; // Web zoom factor. QCheckBox *m_customWebZoom; diff --git a/src/resources/icons/heading_sequence.svg b/src/resources/icons/heading_sequence.svg new file mode 100644 index 00000000..b8014ac6 --- /dev/null +++ b/src/resources/icons/heading_sequence.svg @@ -0,0 +1,7 @@ + + + + Layer 2 + 1.2. + + diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 60f5b20d..673e97eb 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -97,7 +97,8 @@ insert_title_from_note_name=true note_open_mode=0 ; Whether auto generate heading sequence -enable_heading_sequence=false +; 0 - Disabled, 1 - Enabled, 2 - Enabled only for notes +heading_sequence_type=0 ; Heading sequence base level heading_sequence_base_level=1 diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index 0000c689..256e6f2c 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -191,8 +191,14 @@ void VConfigManager::initialize() m_noteOpenMode = OpenFileMode::Read; } - m_enableHeadingSequence = getConfigFromSettings("global", - "enable_heading_sequence").toBool(); + int tmpHeadingSequenceType = getConfigFromSettings("global", + "heading_sequence_type").toInt(); + if (tmpHeadingSequenceType < (int)HeadingSequenceType::Invalid + && tmpHeadingSequenceType >= (int)HeadingSequenceType::Disabled) { + m_headingSequenceType = (HeadingSequenceType)tmpHeadingSequenceType; + } else { + m_headingSequenceType = HeadingSequenceType::Disabled; + } m_headingSequenceBaseLevel = getConfigFromSettings("global", "heading_sequence_base_level").toInt(); diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index 6cd6a91b..1d14d43f 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -43,6 +43,18 @@ struct MarkdownitOption bool m_linkify; }; +// Type of heading sequence. +enum class HeadingSequenceType +{ + Disabled = 0, + Enabled, + + // Enabled only for internal notes. + EnabledNoteOnly, + + Invalid +}; + class VConfigManager : public QObject { public: @@ -262,8 +274,8 @@ public: OpenFileMode getNoteOpenMode() const; void setNoteOpenMode(OpenFileMode p_mode); - bool getEnableHeadingSequence() const; - void setEnableHeadingSequence(bool p_enabled); + HeadingSequenceType getHeadingSequenceType() const; + void setHeadingSequenceType(HeadingSequenceType p_type); int getHeadingSequenceBaseLevel() const; void setHeadingSequenceBaseLevel(int p_level); @@ -599,7 +611,7 @@ private: OpenFileMode m_noteOpenMode; // Whether auto genearte heading sequence. - bool m_enableHeadingSequence; + HeadingSequenceType m_headingSequenceType; // Heading sequence base level. int m_headingSequenceBaseLevel; @@ -1471,20 +1483,21 @@ inline void VConfigManager::setNoteOpenMode(OpenFileMode p_mode) m_noteOpenMode == OpenFileMode::Read ? 0 : 1); } -inline bool VConfigManager::getEnableHeadingSequence() const +inline HeadingSequenceType VConfigManager::getHeadingSequenceType() const { - return m_enableHeadingSequence; + return m_headingSequenceType; } -inline void VConfigManager::setEnableHeadingSequence(bool p_enabled) +inline void VConfigManager::setHeadingSequenceType(HeadingSequenceType p_type) { - if (m_enableHeadingSequence == p_enabled) { + if (m_headingSequenceType == p_type) { return; } - m_enableHeadingSequence = p_enabled; - setConfigToSettings("global", "enable_heading_sequence", - m_enableHeadingSequence); + m_headingSequenceType = p_type; + setConfigToSettings("global", + "heading_sequence_type", + (int)m_headingSequenceType); } inline int VConfigManager::getHeadingSequenceBaseLevel() const diff --git a/src/vedit.cpp b/src/vedit.cpp index 9010581c..9e425b55 100644 --- a/src/vedit.cpp +++ b/src/vedit.cpp @@ -13,10 +13,12 @@ extern VConfigManager *g_config; extern VNote *g_vnote; -void VEditConfig::init(const QFontMetrics &p_metric) +void VEditConfig::init(const QFontMetrics &p_metric, + bool p_enableHeadingSequence) { update(p_metric); + // Init configs that do not support update later. m_enableVimMode = g_config->getEnableVimMode(); if (g_config->getLineDistanceHeight() <= 0) { @@ -26,6 +28,8 @@ void VEditConfig::init(const QFontMetrics &p_metric) } m_highlightWholeBlock = m_enableVimMode; + + m_enableHeadingSequence = p_enableHeadingSequence; } void VEditConfig::update(const QFontMetrics &p_metric) @@ -84,7 +88,7 @@ VEdit::VEdit(VFile *p_file, QWidget *p_parent) updateFontAndPalette(); - m_config.init(QFontMetrics(font())); + m_config.init(QFontMetrics(font()), false); updateConfig(); connect(this, &VEdit::cursorPositionChanged, diff --git a/src/vedit.h b/src/vedit.h index 6eba974b..12b4e6c9 100644 --- a/src/vedit.h +++ b/src/vedit.h @@ -37,10 +37,12 @@ public: m_tabSpaces("\t"), m_enableVimMode(false), m_highlightWholeBlock(false), - m_lineDistanceHeight(0) + m_lineDistanceHeight(0), + m_enableHeadingSequence(false) {} - void init(const QFontMetrics &p_metric); + void init(const QFontMetrics &p_metric, + bool p_enableHeadingSequence); // Only update those configs which could be updated online. void update(const QFontMetrics &p_metric); @@ -63,6 +65,9 @@ public: // Line distance height in pixels. int m_lineDistanceHeight; + + // Whether enable auto heading sequence. + bool m_enableHeadingSequence; }; class LineNumberArea; diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index e03b9beb..0e131258 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -331,6 +331,7 @@ void VMainWindow::initViewToolBar(QSize p_iconSize) viewToolBar->addAction(expandViewAct); } +// Enable/disable all actions of @p_widget. static void setActionsEnabled(QWidget *p_widget, bool p_enabled) { Q_ASSERT(p_widget); @@ -351,6 +352,22 @@ void VMainWindow::initEditToolBar(QSize p_iconSize) m_editToolBar->addSeparator(); + m_headingSequenceAct = new QAction(QIcon(":/resources/icons/heading_sequence.svg"), + tr("Heading Sequence"), + this); + m_headingSequenceAct->setStatusTip(tr("Enable heading sequence in current note in edit mode")); + m_headingSequenceAct->setCheckable(true); + connect(m_headingSequenceAct, &QAction::triggered, + this, [this](bool p_checked){ + if (isHeadingSequenceApplicable()) { + VMdTab *tab = dynamic_cast(m_curTab.data()); + Q_ASSERT(tab); + tab->enableHeadingSequence(p_checked); + } + }); + + m_editToolBar->addAction(m_headingSequenceAct); + QAction *boldAct = new QAction(QIcon(":/resources/icons/bold.svg"), tr("Bold (Ctrl+B)"), this); boldAct->setStatusTip(tr("Insert bold text or change selected text to bold")); @@ -1694,61 +1711,66 @@ void VMainWindow::setCodeBlockStyle(QAction *p_action) } } -void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file, - bool p_editMode) +void VMainWindow::updateActionsStateFromTab(const VEditTab *p_tab) { - bool systemFile = p_file - && p_file->getType() == FileType::Orphan - && dynamic_cast(p_file)->isSystemFile(); + const VFile *file = p_tab ? p_tab->getFile() : NULL; + bool editMode = p_tab ? p_tab->isEditMode() : false; + bool systemFile = file + && file->getType() == FileType::Orphan + && dynamic_cast(file)->isSystemFile(); - m_printAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown); - m_exportAsPDFAct->setEnabled(p_file && p_file->getDocType() == DocType::Markdown); + m_printAct->setEnabled(file && file->getDocType() == DocType::Markdown); + m_exportAsPDFAct->setEnabled(file && file->getDocType() == DocType::Markdown); - discardExitAct->setVisible(p_file && p_editMode); - saveExitAct->setVisible(p_file && p_editMode); - editNoteAct->setEnabled(p_file && p_file->isModifiable() && !p_editMode); + discardExitAct->setVisible(file && editMode); + saveExitAct->setVisible(file && editMode); + editNoteAct->setEnabled(file && file->isModifiable() && !editMode); editNoteAct->setVisible(!saveExitAct->isVisible()); - saveNoteAct->setEnabled(p_file && p_editMode); - deleteNoteAct->setEnabled(p_file && p_file->getType() == FileType::Note); - noteInfoAct->setEnabled(p_file && !systemFile); + saveNoteAct->setEnabled(file && editMode); + deleteNoteAct->setEnabled(file && file->getType() == FileType::Note); + noteInfoAct->setEnabled(file && !systemFile); - m_attachmentBtn->setEnabled(p_file && p_file->getType() == FileType::Note); + m_attachmentBtn->setEnabled(file && file->getType() == FileType::Note); - m_insertImageAct->setEnabled(p_file && p_editMode); + m_insertImageAct->setEnabled(file && editMode); - setActionsEnabled(m_editToolBar, p_file && p_editMode); + setActionsEnabled(m_editToolBar, file && editMode); + + // Handle heading sequence act independently. + m_headingSequenceAct->setEnabled(isHeadingSequenceApplicable()); + const VMdTab *mdTab = dynamic_cast(p_tab); + m_headingSequenceAct->setChecked(mdTab && mdTab->isHeadingSequenceEnabled()); // Find/Replace - m_findReplaceAct->setEnabled(p_file); - m_findNextAct->setEnabled(p_file); - m_findPreviousAct->setEnabled(p_file); - m_replaceAct->setEnabled(p_file && p_editMode); - m_replaceFindAct->setEnabled(p_file && p_editMode); - m_replaceAllAct->setEnabled(p_file && p_editMode); + m_findReplaceAct->setEnabled(file); + m_findNextAct->setEnabled(file); + m_findPreviousAct->setEnabled(file); + m_replaceAct->setEnabled(file && editMode); + m_replaceFindAct->setEnabled(file && editMode); + m_replaceAllAct->setEnabled(file && editMode); - if (!p_file) { + if (!file) { m_findReplaceDialog->closeDialog(); } } void VMainWindow::handleAreaTabStatusUpdated(const VEditTabInfo &p_info) { - bool editMode = false; m_curTab = p_info.m_editTab; if (m_curTab) { m_curFile = m_curTab->getFile(); - editMode = m_curTab->isEditMode(); } else { m_curFile = NULL; } - updateActionStateFromTabStatusChange(m_curFile, editMode); + updateActionsStateFromTab(m_curTab); m_attachmentList->setFile(dynamic_cast(m_curFile.data())); QString title; if (m_curFile) { - m_findReplaceDialog->updateState(m_curFile->getDocType(), editMode); + m_findReplaceDialog->updateState(m_curFile->getDocType(), + m_curTab->isEditMode()); if (m_curFile->getType() == FileType::Note) { const VNoteFile *tmpFile = dynamic_cast((VFile *)m_curFile); @@ -2465,3 +2487,19 @@ void VMainWindow::openStartupPages() break; } } + +bool VMainWindow::isHeadingSequenceApplicable() const +{ + if (!m_curTab) { + return false; + } + + Q_ASSERT(m_curFile); + + if (!m_curFile->isModifiable() + || m_curFile->getDocType() != DocType::Markdown) { + return false; + } + + return true; +} diff --git a/src/vmainwindow.h b/src/vmainwindow.h index 9b9b36ea..2a273c49 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -202,8 +202,10 @@ private: void initEditorStyleMenu(QMenu *p_emnu); void updateWindowTitle(const QString &str); - void updateActionStateFromTabStatusChange(const VFile *p_file, - bool p_editMode); + + // Update state of actions according to @p_tab. + void updateActionsStateFromTab(const VEditTab *p_tab); + void saveStateAndGeometry(); void restoreStateAndGeometry(); void repositionAvatar(); @@ -231,6 +233,10 @@ private: // Will not change m_panelViewState. void changePanelView(PanelViewState p_state); + // Whether heading sequence is applicable to current tab. + // Only available for writable Markdown file. + bool isHeadingSequenceApplicable() const; + VNote *vnote; QPointer m_curFile; QPointer m_curTab; @@ -285,6 +291,9 @@ private: QAction *m_autoIndentAct; + // Enable heading sequence for current note. + QAction *m_headingSequenceAct; + // Act group for render styles. QActionGroup *m_renderStyleActs; diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp index 59d16ca8..2ca757a0 100644 --- a/src/vmdedit.cpp +++ b/src/vmdedit.cpp @@ -464,7 +464,7 @@ void VMdEdit::updateHeaders(const QVector &p_headerRegions) m_headers.clear(); - bool autoSequence = g_config->getEnableHeadingSequence() && !isReadOnly(); + bool autoSequence = m_config.m_enableHeadingSequence && !isReadOnly(); int headingSequenceBaseLevel = g_config->getHeadingSequenceBaseLevel(); if (headingSequenceBaseLevel < 1 || headingSequenceBaseLevel > 6) { headingSequenceBaseLevel = 1; diff --git a/src/vmdtab.cpp b/src/vmdtab.cpp index 80514e75..cfa605bd 100644 --- a/src/vmdtab.cpp +++ b/src/vmdtab.cpp @@ -22,13 +22,25 @@ extern VConfigManager *g_config; VMdTab::VMdTab(VFile *p_file, VEditArea *p_editArea, OpenFileMode p_mode, QWidget *p_parent) - : VEditTab(p_file, p_editArea, p_parent), m_editor(NULL), m_webViewer(NULL), - m_document(NULL), m_mdConType(g_config->getMdConverterType()) + : VEditTab(p_file, p_editArea, p_parent), + m_editor(NULL), + m_webViewer(NULL), + m_document(NULL), + m_mdConType(g_config->getMdConverterType()), + m_enableHeadingSequence(false) { V_ASSERT(m_file->getDocType() == DocType::Markdown); m_file->open(); + HeadingSequenceType headingSequenceType = g_config->getHeadingSequenceType(); + if (headingSequenceType == HeadingSequenceType::Enabled) { + m_enableHeadingSequence = true; + } else if (headingSequenceType == HeadingSequenceType::EnabledNoteOnly + && m_file->getType() == FileType::Note) { + m_enableHeadingSequence = true; + } + setupUI(); if (p_mode == OpenFileMode::Edit) { @@ -344,6 +356,7 @@ void VMdTab::setupMarkdownEditor() { Q_ASSERT(m_file->isModifiable() && !m_editor); qDebug() << "create Markdown editor"; + m_editor = new VMdEdit(m_file, m_document, m_mdConType, this); connect(dynamic_cast(m_editor), &VMdEdit::headersChanged, this, &VMdTab::updateOutlineFromHeaders); @@ -372,6 +385,7 @@ void VMdTab::setupMarkdownEditor() connect(m_editor, SIGNAL(ready(void)), this, SLOT(restoreFromTabInfo(void))); + enableHeadingSequence(m_enableHeadingSequence); m_editor->reloadFile(); m_stacks->addWidget(m_editor); } @@ -654,3 +668,18 @@ void VMdTab::restoreFromTabInfo() // Clear it anyway. m_infoToRestore.clear(); } + +void VMdTab::enableHeadingSequence(bool p_enabled) +{ + m_enableHeadingSequence = p_enabled; + + if (m_editor) { + VEditConfig &config = m_editor->getConfig(); + config.m_enableHeadingSequence = m_enableHeadingSequence; + } +} + +bool VMdTab::isHeadingSequenceEnabled() const +{ + return m_enableHeadingSequence; +} diff --git a/src/vmdtab.h b/src/vmdtab.h index eebf9c6d..15417129 100644 --- a/src/vmdtab.h +++ b/src/vmdtab.h @@ -65,6 +65,11 @@ public: // Create a filled VEditTabInfo. VEditTabInfo fetchTabInfo() const Q_DECL_OVERRIDE; + // Enable or disable heading sequence. + void enableHeadingSequence(bool p_enabled); + + bool isHeadingSequenceEnabled() const; + public slots: // Enter edit mode. void editFile() Q_DECL_OVERRIDE; @@ -149,6 +154,9 @@ private: VDocument *m_document; MarkdownConverterType m_mdConType; + // Whether heading sequence is enabled. + bool m_enableHeadingSequence; + QStackedLayout *m_stacks; }; diff --git a/src/vnote.qrc b/src/vnote.qrc index 267d34c7..883a2be2 100644 --- a/src/vnote.qrc +++ b/src/vnote.qrc @@ -131,5 +131,6 @@ resources/icons/sort.svg resources/icons/create_subdir.svg resources/icons/compact_mode.svg + resources/icons/heading_sequence.svg