diff --git a/src/dialog/vfileinfodialog.cpp b/src/dialog/vfileinfodialog.cpp index 01a17042..1c26469e 100644 --- a/src/dialog/vfileinfodialog.cpp +++ b/src/dialog/vfileinfodialog.cpp @@ -1,16 +1,22 @@ #include #include "vfileinfodialog.h" +#include "vdirectory.h" +#include "vfile.h" +#include "vconfigmanager.h" + +extern VConfigManager *g_config; VFileInfoDialog::VFileInfoDialog(const QString &title, const QString &info, - const QString &defaultName, + VDirectory *directory, const VFile *file, QWidget *parent) - : QDialog(parent), infoLabel(NULL), title(title), info(info), defaultName(defaultName) + : QDialog(parent), infoLabel(NULL), title(title), info(info), + m_directory(directory), m_file(file) { setupUI(); - connect(nameEdit, &QLineEdit::textChanged, this, &VFileInfoDialog::enableOkButton); + connect(nameEdit, &QLineEdit::textChanged, this, &VFileInfoDialog::handleInputChanged); - enableOkButton(); + handleInputChanged(); } void VFileInfoDialog::setupUI() @@ -19,10 +25,14 @@ void VFileInfoDialog::setupUI() infoLabel = new QLabel(info); } nameLabel = new QLabel(tr("Note &name:")); - nameEdit = new QLineEdit(defaultName); + nameEdit = new QLineEdit(m_file->getName()); nameEdit->selectAll(); nameLabel->setBuddy(nameEdit); + m_warnLabel = new QLabel(); + m_warnLabel->setWordWrap(true); + m_warnLabel->hide(); + // Ok is the default button. m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept); @@ -41,6 +51,7 @@ void VFileInfoDialog::setupUI() } mainLayout->addLayout(topLayout); + mainLayout->addWidget(m_warnLabel); mainLayout->addWidget(m_btnBox); mainLayout->setSizeConstraint(QLayout::SetFixedSize); setLayout(mainLayout); @@ -48,10 +59,28 @@ void VFileInfoDialog::setupUI() setWindowTitle(title); } -void VFileInfoDialog::enableOkButton() +void VFileInfoDialog::handleInputChanged() { + bool showWarnLabel = false; + QString name = nameEdit->text(); + bool nameOk = !name.isEmpty(); + if (nameOk && name != m_file->getName()) { + // Check if the name conflicts with existing notebook name. + // Case-insensitive when creating note. + if (m_directory->findFile(name, false)) { + nameOk = false; + showWarnLabel = true; + QString nameConflictText = tr("WARNING: Name (case-insensitive) already exists. " + "Please choose another name.") + .arg(g_config->c_warningTextStyle); + m_warnLabel->setText(nameConflictText); + } + } + + m_warnLabel->setVisible(showWarnLabel); + QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok); - okBtn->setEnabled(!nameEdit->text().isEmpty()); + okBtn->setEnabled(nameOk); } QString VFileInfoDialog::getNameInput() const diff --git a/src/dialog/vfileinfodialog.h b/src/dialog/vfileinfodialog.h index 555ae7c8..7cd4b1d7 100644 --- a/src/dialog/vfileinfodialog.h +++ b/src/dialog/vfileinfodialog.h @@ -7,17 +7,20 @@ class QLabel; class QLineEdit; class QDialogButtonBox; class QString; +class VDirectory; +class VFile; class VFileInfoDialog : public QDialog { Q_OBJECT public: - VFileInfoDialog(const QString &title, const QString &info, const QString &defaultName, + VFileInfoDialog(const QString &title, const QString &info, + VDirectory *directory, const VFile *file, QWidget *parent = 0); QString getNameInput() const; private slots: - void enableOkButton(); + void handleInputChanged(); private: void setupUI(); @@ -25,11 +28,14 @@ private: QLabel *infoLabel; QLabel *nameLabel; QLineEdit *nameEdit; + QLabel *m_warnLabel; QDialogButtonBox *m_btnBox; QString title; QString info; - QString defaultName; + + VDirectory *m_directory; + const VFile *m_file; }; #endif // VFILEINFODIALOG_H diff --git a/src/dialog/vnewfiledialog.cpp b/src/dialog/vnewfiledialog.cpp index 81f47b1e..0342ff70 100644 --- a/src/dialog/vnewfiledialog.cpp +++ b/src/dialog/vnewfiledialog.cpp @@ -1,13 +1,21 @@ #include #include "vnewfiledialog.h" +#include "vconfigmanager.h" +#include "vdirectory.h" -VNewFileDialog::VNewFileDialog(const QString &title, const QString &info, const QString &name, - const QString &defaultName, QWidget *parent) - : QDialog(parent), title(title), info(info), name(name), defaultName(defaultName) +extern VConfigManager *g_config; + +VNewFileDialog::VNewFileDialog(const QString &title, const QString &info, + const QString &defaultName, VDirectory *directory, + QWidget *parent) + : QDialog(parent), title(title), info(info), + defaultName(defaultName), m_directory(directory) { setupUI(); - connect(nameEdit, &QLineEdit::textChanged, this, &VNewFileDialog::enableOkButton); + connect(nameEdit, &QLineEdit::textChanged, this, &VNewFileDialog::handleInputChanged); + + handleInputChanged(); } void VNewFileDialog::setupUI() @@ -17,21 +25,35 @@ void VNewFileDialog::setupUI() infoLabel = new QLabel(info); } - nameLabel = new QLabel(name); + // Name. + QLabel *nameLabel = new QLabel(tr("Note &name:")); nameEdit = new QLineEdit(defaultName); int dotIndex = defaultName.lastIndexOf('.'); nameEdit->setSelection(0, (dotIndex == -1) ? defaultName.size() : dotIndex); nameLabel->setBuddy(nameEdit); + // InsertTitle. + m_insertTitleCB = new QCheckBox(tr("Insert note name as title (for Markdown only)")); + m_insertTitleCB->setToolTip(tr("Insert note name into the new note as a title")); + m_insertTitleCB->setChecked(g_config->getInsertTitleFromNoteName()); + connect(m_insertTitleCB, &QCheckBox::stateChanged, + this, [this](int p_state) { + g_config->setInsertTitleFromNoteName(p_state == Qt::Checked); + }); + + QFormLayout *topLayout = new QFormLayout(); + topLayout->addRow(nameLabel, nameEdit); + topLayout->addRow("", m_insertTitleCB); + + m_warnLabel = new QLabel(); + m_warnLabel->setWordWrap(true); + m_warnLabel->hide(); + // Ok is the default button. m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - QHBoxLayout *topLayout = new QHBoxLayout(); - topLayout->addWidget(nameLabel); - topLayout->addWidget(nameEdit); - QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok); nameEdit->setMinimumWidth(okBtn->sizeHint().width() * 3); @@ -39,7 +61,9 @@ void VNewFileDialog::setupUI() if (infoLabel) { mainLayout->addWidget(infoLabel); } + mainLayout->addLayout(topLayout); + mainLayout->addWidget(m_warnLabel); mainLayout->addWidget(m_btnBox); mainLayout->setSizeConstraint(QLayout::SetFixedSize); setLayout(mainLayout); @@ -47,13 +71,36 @@ void VNewFileDialog::setupUI() setWindowTitle(title); } -void VNewFileDialog::enableOkButton(const QString &editText) +void VNewFileDialog::handleInputChanged() { + bool showWarnLabel = false; + QString name = nameEdit->text(); + bool nameOk = !name.isEmpty(); + if (nameOk) { + // Check if the name conflicts with existing notebook name. + // Case-insensitive when creating note. + if (m_directory->findFile(name, false)) { + nameOk = false; + showWarnLabel = true; + QString nameConflictText = tr("WARNING: Name (case-insensitive) already exists. " + "Please choose another name.") + .arg(g_config->c_warningTextStyle); + m_warnLabel->setText(nameConflictText); + } + } + + m_warnLabel->setVisible(showWarnLabel); + QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok); - okBtn->setEnabled(!editText.isEmpty()); + okBtn->setEnabled(nameOk); } QString VNewFileDialog::getNameInput() const { return nameEdit->text(); } + +bool VNewFileDialog::getInsertTitleInput() const +{ + return m_insertTitleCB->isChecked(); +} diff --git a/src/dialog/vnewfiledialog.h b/src/dialog/vnewfiledialog.h index 1ee1cc1f..2eeb8370 100644 --- a/src/dialog/vnewfiledialog.h +++ b/src/dialog/vnewfiledialog.h @@ -6,31 +6,40 @@ class QLabel; class QLineEdit; class QDialogButtonBox; -class QString; +class QCheckBox; +class VDirectory; class VNewFileDialog : public QDialog { Q_OBJECT public: - VNewFileDialog(const QString &title, const QString &info, const QString &name, - const QString &defaultName, QWidget *parent = 0); + VNewFileDialog(const QString &title, const QString &info, + const QString &defaultName, VDirectory *directory, + QWidget *parent = 0); + QString getNameInput() const; + bool getInsertTitleInput() const; + private slots: - void enableOkButton(const QString &editText); + void handleInputChanged(); private: void setupUI(); - QLabel *nameLabel; QLineEdit *nameEdit; + QCheckBox *m_insertTitleCB; + QPushButton *okBtn; QDialogButtonBox *m_btnBox; + QLabel *m_warnLabel; + QString title; QString info; - QString name; QString defaultName; + + VDirectory *m_directory; }; #endif // VNEWFILEDIALOG_H diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 69ad0237..6ad2411b 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -76,6 +76,9 @@ markdown_highlight_interval=400 ; Adds specified height between lines (in pixels) line_distance_height=3 +; Whether insert the note name as a title when creating a new note +insert_title_from_note_name=true + [session] tools_dock_checked=true diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index 7e85d740..61227698 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -163,6 +163,9 @@ void VConfigManager::initialize() m_lineDistanceHeight = getConfigFromSettings("global", "line_distance_height").toInt(); + + m_insertTitleFromNoteName = getConfigFromSettings("global", + "insert_title_from_note_name").toBool(); } void VConfigManager::readPredefinedColorsFromSettings() diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index de0571f8..1722cbee 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -225,6 +225,9 @@ public: int getLineDistanceHeight() const; + bool getInsertTitleFromNoteName() const; + void setInsertTitleFromNoteName(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; @@ -456,6 +459,9 @@ private: // Line distance height in pixel. int m_lineDistanceHeight; + // Whether insert the note name as a title when creating a new note. + bool m_insertTitleFromNoteName; + // The name of the config file in each directory, obsolete. // Use c_dirConfigFile instead. static const QString c_obsoleteDirConfigFile; @@ -1159,4 +1165,20 @@ inline int VConfigManager::getLineDistanceHeight() const return m_lineDistanceHeight; } +inline bool VConfigManager::getInsertTitleFromNoteName() const +{ + return m_insertTitleFromNoteName; +} + +inline void VConfigManager::setInsertTitleFromNoteName(bool p_enabled) +{ + if (p_enabled == m_insertTitleFromNoteName) { + return; + } + + m_insertTitleFromNoteName = p_enabled; + setConfigToSettings("global", "insert_title_from_note_name", + m_insertTitleFromNoteName); +} + #endif // VCONFIGMANAGER_H diff --git a/src/vfilelist.cpp b/src/vfilelist.cpp index 57ed32f3..3accb4e9 100644 --- a/src/vfilelist.cpp +++ b/src/vfilelist.cpp @@ -178,46 +178,35 @@ void VFileList::fileInfo(VFile *p_file) if (!p_file) { return; } + VDirectory *dir = p_file->getDirectory(); - QString info; - QString defaultName = p_file->getName(); - QString curName = defaultName; - do { - VFileInfoDialog dialog(tr("Note Information"), info, defaultName, this); - if (dialog.exec() == QDialog::Accepted) { - QString name = dialog.getNameInput(); - if (name == curName) { - return; - } - - // Case-insensitive when creating note. - if (dir->findFile(name, false)) { - info = "Name (case-insensitive) already exists. Please choose another name."; - defaultName = name; - continue; - } - - if (!promptForDocTypeChange(p_file, QDir(p_file->retriveBasePath()).filePath(name))) { - return; - } - - if (!p_file->rename(name)) { - VUtils::showMessage(QMessageBox::Warning, tr("Warning"), - tr("Fail to rename note %2.") - .arg(g_config->c_dataTextStyle).arg(curName), "", - QMessageBox::Ok, QMessageBox::Ok, this); - return; - } - - QListWidgetItem *item = findItem(p_file); - if (item) { - fillItem(item, p_file); - } - - emit fileUpdated(p_file); + QString curName = p_file->getName(); + VFileInfoDialog dialog(tr("Note Information"), "", dir, p_file, this); + if (dialog.exec() == QDialog::Accepted) { + QString name = dialog.getNameInput(); + if (name == curName) { + return; } - break; - } while (true); + + if (!promptForDocTypeChange(p_file, QDir(p_file->retriveBasePath()).filePath(name))) { + return; + } + + if (!p_file->rename(name)) { + VUtils::showMessage(QMessageBox::Warning, tr("Warning"), + tr("Fail to rename note %2.") + .arg(g_config->c_dataTextStyle).arg(curName), "", + QMessageBox::Ok, QMessageBox::Ok, this); + return; + } + + QListWidgetItem *item = findItem(p_file); + if (item) { + fillItem(item, p_file); + } + + emit fileUpdated(p_file); + } } void VFileList::fillItem(QListWidgetItem *p_item, const VFile *p_file) @@ -277,38 +266,44 @@ void VFileList::newFile() .arg(g_config->c_dataTextStyle).arg(m_directory->getName()); info = info + "
" + tr("Note with name ending with \"%1\" will be treated as Markdown type.") .arg(suffixStr); - QString text(tr("Note &name:")); - QString defaultText = QString("new_note.%1").arg(defaultSuf); - do { - VNewFileDialog dialog(tr("Create Note"), info, text, defaultText, this); - if (dialog.exec() == QDialog::Accepted) { - QString name = dialog.getNameInput(); - // Case-insensitive when creating note. - if (m_directory->findFile(name, false)) { - info = tr("Name (case-insensitive) already exists. Please choose another name."); - defaultText = name; - continue; - } - - VFile *file = m_directory->createFile(name); - if (!file) { - VUtils::showMessage(QMessageBox::Warning, tr("Warning"), - tr("Fail to create note %2.") - .arg(g_config->c_dataTextStyle).arg(name), "", - QMessageBox::Ok, QMessageBox::Ok, this); - return; - } - QVector items = updateFileListAdded(); - Q_ASSERT(items.size() == 1); - fileList->setCurrentItem(items[0], QItemSelectionModel::ClearAndSelect); - // Qt seems not to update the QListWidget correctly. Manually force it to repaint. - fileList->update(); - - // Open it in edit mode - emit fileCreated(file, OpenFileMode::Edit); + QString defaultName = QString("new_note.%1").arg(defaultSuf); + defaultName = VUtils::getFileNameWithSequence(m_directory->retrivePath(), defaultName); + VNewFileDialog dialog(tr("Create Note"), info, defaultName, m_directory, this); + if (dialog.exec() == QDialog::Accepted) { + VFile *file = m_directory->createFile(dialog.getNameInput()); + if (!file) { + VUtils::showMessage(QMessageBox::Warning, tr("Warning"), + tr("Fail to create note %2.") + .arg(g_config->c_dataTextStyle).arg(dialog.getNameInput()), "", + QMessageBox::Ok, QMessageBox::Ok, this); + return; } - break; - } while (true); + + // Write title if needed. + if (dialog.getInsertTitleInput()) { + if (!file->open()) { + qWarning() << "fail to open newly-created note" << file->getName(); + } else { + Q_ASSERT(file->getContent().isEmpty()); + QString content = QString("# %1\n").arg(QFileInfo(file->getName()).baseName()); + file->setContent(content); + if (!file->save()) { + qWarning() << "fail to write to newly-created note" << file->getName(); + } + + file->close(); + } + } + + QVector items = updateFileListAdded(); + Q_ASSERT(items.size() == 1); + fileList->setCurrentItem(items[0], QItemSelectionModel::ClearAndSelect); + // Qt seems not to update the QListWidget correctly. Manually force it to repaint. + fileList->update(); + + // Open it in edit mode + emit fileCreated(file, OpenFileMode::Edit); + } } QVector VFileList::updateFileListAdded()