Browse Source

support note template

Le Tan 4 years ago
parent
commit
af85dc5aed

+ 1 - 1
libs/vtextedit

@@ -1 +1 @@
-Subproject commit 893a88cdd7fdc3957005d109b46c9972a83d6772
+Subproject commit b9c3758d1d34a2281748352902cf1d3452f24bd4

+ 7 - 0
src/core/configmgr.cpp

@@ -381,6 +381,13 @@ QString ConfigMgr::getUserDictsFolder() const
     return folderPath;
 }
 
+QString ConfigMgr::getUserTemplateFolder() const
+{
+    auto folderPath = PathUtils::concatenateFilePath(m_userConfigFolderPath, QStringLiteral("templates"));
+    QDir().mkpath(folderPath);
+    return folderPath;
+}
+
 QString ConfigMgr::getUserOrAppFile(const QString &p_filePath) const
 {
     QFileInfo fi(p_filePath);

+ 2 - 0
src/core/configmgr.h

@@ -91,6 +91,8 @@ namespace vnotex
         QString getAppDictsFolder() const;
         QString getUserDictsFolder() const;
 
+        QString getUserTemplateFolder() const;
+
         // If @p_filePath is absolute, just return it.
         // Otherwise, first try to find it in user folder, then in app folder.
         QString getUserOrAppFile(const QString &p_filePath) const;

+ 2 - 0
src/core/core.pri

@@ -23,6 +23,7 @@ SOURCES += \
     $$PWD/markdowneditorconfig.cpp \
     $$PWD/quickaccesshelper.cpp \
     $$PWD/singleinstanceguard.cpp \
+    $$PWD/templatemgr.cpp \
     $$PWD/texteditorconfig.cpp \
     $$PWD/vnotex.cpp \
     $$PWD/thememgr.cpp \
@@ -51,6 +52,7 @@ HEADERS += \
     $$PWD/quickaccesshelper.h \
     $$PWD/singleinstanceguard.h \
     $$PWD/iconfig.h \
+    $$PWD/templatemgr.h \
     $$PWD/texteditorconfig.h \
     $$PWD/vnotex.h \
     $$PWD/thememgr.h \

+ 0 - 2
src/core/mainconfig.cpp

@@ -117,6 +117,4 @@ QString MainConfig::getVersion(const QJsonObject &p_jobj)
 void MainConfig::doVersionSpecificOverride()
 {
     // In a new version, we may want to change one value by force.
-    m_editorConfig->m_toolBarIconSize = 16;
-    m_editorConfig->writeToSettings();
 }

+ 5 - 2
src/core/notebook/notebook.cpp

@@ -175,9 +175,12 @@ QSharedPointer<Node> Notebook::getRecycleBinNode() const
     return nullptr;
 }
 
-QSharedPointer<Node> Notebook::newNode(Node *p_parent, Node::Flags p_flags, const QString &p_name)
+QSharedPointer<Node> Notebook::newNode(Node *p_parent,
+                                       Node::Flags p_flags,
+                                       const QString &p_name,
+                                       const QString &p_content)
 {
-    return m_configMgr->newNode(p_parent, p_flags, p_name);
+    return m_configMgr->newNode(p_parent, p_flags, p_name, p_content);
 }
 
 const QDateTime &Notebook::getCreatedTimeUtc() const

+ 2 - 1
src/core/notebook/notebook.h

@@ -67,7 +67,8 @@ namespace vnotex
 
         QSharedPointer<Node> newNode(Node *p_parent,
                                      Node::Flags p_flags,
-                                     const QString &p_name);
+                                     const QString &p_name,
+                                     const QString &p_content = QString());
 
         // Add @p_name under @p_parent to add as a new node @p_type.
         QSharedPointer<Node> addAsNode(Node *p_parent,

+ 2 - 1
src/core/notebookconfigmgr/inotebookconfigmgr.h

@@ -45,7 +45,8 @@ namespace vnotex
 
         virtual QSharedPointer<Node> newNode(Node *p_parent,
                                              Node::Flags p_flags,
-                                             const QString &p_name) = 0;
+                                             const QString &p_name,
+                                             const QString &p_content) = 0;
 
         virtual QSharedPointer<Node> addAsNode(Node *p_parent,
                                                Node::Flags p_flags,

+ 7 - 5
src/core/notebookconfigmgr/vxnotebookconfigmgr.cpp

@@ -273,7 +273,7 @@ void VXNotebookConfigMgr::createRecycleBinNode(const QSharedPointer<Node> &p_roo
 {
     Q_ASSERT(p_root->isRoot());
 
-    auto node = newNode(p_root.data(), Node::Flag::Container, c_recycleBinFolderName);
+    auto node = newNode(p_root.data(), Node::Flag::Container, c_recycleBinFolderName, "");
     node->setUse(Node::Use::RecycleBin);
     markNodeReadOnly(node.data());
 }
@@ -376,7 +376,8 @@ void VXNotebookConfigMgr::loadFolderNode(Node *p_node, const NodeConfig &p_confi
 
 QSharedPointer<Node> VXNotebookConfigMgr::newNode(Node *p_parent,
                                                   Node::Flags p_flags,
-                                                  const QString &p_name)
+                                                  const QString &p_name,
+                                                  const QString &p_content)
 {
     Q_ASSERT(p_parent && p_parent->isContainer() && !p_name.isEmpty());
 
@@ -384,7 +385,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::newNode(Node *p_parent,
 
     if (p_flags & Node::Flag::Content) {
         Q_ASSERT(!(p_flags & Node::Flag::Container));
-        node = newFileNode(p_parent, p_name, true, NodeParameters());
+        node = newFileNode(p_parent, p_name, p_content, true, NodeParameters());
     } else {
         node = newFolderNode(p_parent, p_name, true, NodeParameters());
     }
@@ -403,7 +404,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::addAsNode(Node *p_parent,
     QSharedPointer<Node> node;
     if (p_flags & Node::Flag::Content) {
         Q_ASSERT(!(p_flags & Node::Flag::Container));
-        node = newFileNode(p_parent, p_name, false, p_paras);
+        node = newFileNode(p_parent, p_name, "", false, p_paras);
     } else {
         node = newFolderNode(p_parent, p_name, false, p_paras);
     }
@@ -430,6 +431,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyAsNode(Node *p_parent,
 
 QSharedPointer<Node> VXNotebookConfigMgr::newFileNode(Node *p_parent,
                                                       const QString &p_name,
+                                                      const QString &p_content,
                                                       bool p_create,
                                                       const NodeParameters &p_paras)
 {
@@ -447,7 +449,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::newFileNode(Node *p_parent,
 
     // Write empty file.
     if (p_create) {
-        getBackend()->writeFile(node->fetchPath(), QString());
+        getBackend()->writeFile(node->fetchPath(), p_content);
         node->setExists(true);
     } else {
         node->setExists(getBackend()->existsFile(node->fetchPath()));

+ 3 - 1
src/core/notebookconfigmgr/vxnotebookconfigmgr.h

@@ -41,7 +41,8 @@ namespace vnotex
 
         QSharedPointer<Node> newNode(Node *p_parent,
                                      Node::Flags p_flags,
-                                     const QString &p_name) Q_DECL_OVERRIDE;
+                                     const QString &p_name,
+                                     const QString &p_content) Q_DECL_OVERRIDE;
 
         QSharedPointer<Node> addAsNode(Node *p_parent,
                                        Node::Flags p_flags,
@@ -154,6 +155,7 @@ namespace vnotex
 
         QSharedPointer<Node> newFileNode(Node *p_parent,
                                          const QString &p_name,
+                                         const QString &p_content,
                                          bool p_create,
                                          const NodeParameters &p_paras);
 

+ 24 - 0
src/core/templatemgr.cpp

@@ -0,0 +1,24 @@
+#include "templatemgr.h"
+
+#include <QDir>
+
+#include "configmgr.h"
+
+using namespace vnotex;
+
+QString TemplateMgr::getTemplateFolder() const
+{
+    return ConfigMgr::getInst().getUserTemplateFolder();
+}
+
+QStringList TemplateMgr::getTemplates() const
+{
+    QDir dir(getTemplateFolder());
+    dir.setFilter(QDir::Files | QDir::NoSymLinks);
+    return dir.entryList();
+}
+
+QString TemplateMgr::getTemplateFilePath(const QString &p_name) const
+{
+    return QDir(getTemplateFolder()).filePath(p_name);
+}

+ 32 - 0
src/core/templatemgr.h

@@ -0,0 +1,32 @@
+#ifndef TEMPLATEMGR_H
+#define TEMPLATEMGR_H
+
+#include <QObject>
+#include <QStringList>
+
+#include "noncopyable.h"
+
+namespace vnotex
+{
+    class TemplateMgr : public QObject, private Noncopyable
+    {
+        Q_OBJECT
+    public:
+        static TemplateMgr &getInst()
+        {
+            static TemplateMgr inst;
+            return inst;
+        }
+
+        QString getTemplateFolder() const;
+
+        QStringList getTemplates() const;
+
+        QString getTemplateFilePath(const QString &p_name) const;
+
+    private:
+        TemplateMgr() = default;
+    };
+}
+
+#endif // TEMPLATEMGR_H

+ 96 - 2
src/widgets/dialogs/newnotedialog.cpp

@@ -1,6 +1,11 @@
 #include "newnotedialog.h"
 
-#include <QtWidgets>
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QFormLayout>
+#include <QPushButton>
+#include <QPlainTextEdit>
 
 #include "notebook/notebook.h"
 #include "notebook/node.h"
@@ -10,9 +15,12 @@
 #include "exception.h"
 #include "nodeinfowidget.h"
 #include <utils/widgetutils.h>
+#include <core/templatemgr.h>
 
 using namespace vnotex;
 
+QString NewNoteDialog::s_lastTemplate;
+
 NewNoteDialog::NewNoteDialog(Node *p_node, QWidget *p_parent)
     : ScrollDialog(p_parent)
 {
@@ -29,6 +37,30 @@ void NewNoteDialog::setupUI(const Node *p_node)
     setupNodeInfoWidget(p_node, this);
     setCentralWidget(m_infoWidget);
 
+    auto infoLayout = m_infoWidget->getMainLayout();
+
+    {
+        auto templateLayout = new QHBoxLayout();
+        templateLayout->setContentsMargins(0, 0, 0, 0);
+        infoLayout->addRow(tr("Template:"), templateLayout);
+
+        setupTemplateComboBox(m_infoWidget);
+        templateLayout->addWidget(m_templateComboBox);
+
+        templateLayout->addStretch();
+
+        auto manageBtn = new QPushButton(tr("Manage"), m_infoWidget);
+        templateLayout->addWidget(manageBtn);
+        connect(manageBtn, &QPushButton::clicked,
+                this, []() {
+                    WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(TemplateMgr::getInst().getTemplateFolder()));
+                });
+
+        m_templateTextEdit = WidgetsFactory::createPlainTextConsole(m_infoWidget);
+        infoLayout->addRow("", m_templateTextEdit);
+        m_templateTextEdit->hide();
+    }
+
     setDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
     setButtonEnabled(QDialogButtonBox::Ok, false);
 
@@ -73,6 +105,8 @@ bool NewNoteDialog::validateNameInput(QString &p_msg)
 
 void NewNoteDialog::acceptedButtonClicked()
 {
+    s_lastTemplate = m_templateComboBox->currentData().toString();
+
     if (newNote()) {
         accept();
     }
@@ -85,7 +119,10 @@ bool NewNoteDialog::newNote()
     Notebook *notebook = const_cast<Notebook *>(m_infoWidget->getNotebook());
     Node *parentNode = const_cast<Node *>(m_infoWidget->getParentNode());
     try {
-        m_newNode = notebook->newNode(parentNode, Node::Flag::Content, m_infoWidget->getName());
+        m_newNode = notebook->newNode(parentNode,
+                                      Node::Flag::Content,
+                                      m_infoWidget->getName(),
+                                      getTemplateContent());
     } catch (Exception &p_e) {
         QString msg = tr("Failed to create note under (%1) in (%2) (%3).").arg(parentNode->getName(),
                                                                                notebook->getName(),
@@ -118,3 +155,60 @@ void NewNoteDialog::initDefaultValues(const Node *p_node)
         validateInputs();
     }
 }
+
+void NewNoteDialog::setupTemplateComboBox(QWidget *p_parent)
+{
+    m_templateComboBox = WidgetsFactory::createComboBox(p_parent);
+
+    // None.
+    m_templateComboBox->addItem(tr("None"), "");
+
+    int idx = 1;
+    auto templates = TemplateMgr::getInst().getTemplates();
+    for (const auto &temp : templates) {
+        m_templateComboBox->addItem(temp, temp);
+        m_templateComboBox->setItemData(idx++, temp, Qt::ToolTipRole);
+    }
+
+    if (!s_lastTemplate.isEmpty()) {
+        // Restore.
+        int idx = m_templateComboBox->findData(s_lastTemplate);
+        if (idx != -1) {
+            m_templateComboBox->setCurrentIndex(idx);
+        } else {
+            s_lastTemplate.clear();
+        }
+    }
+
+    connect(m_templateComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
+            this, [this]() {
+                m_templateContent.clear();
+                m_templateTextEdit->clear();
+
+                auto temp = m_templateComboBox->currentData().toString();
+                if (temp.isEmpty()) {
+                    m_templateTextEdit->hide();
+                    return;
+                }
+
+                const auto filePath = TemplateMgr::getInst().getTemplateFilePath(temp);
+                try {
+                    m_templateContent = FileUtils::readTextFile(filePath);
+                    m_templateTextEdit->setPlainText(m_templateContent);
+                    m_templateTextEdit->show();
+                } catch (Exception &p_e) {
+                    m_templateTextEdit->hide();
+
+                    QString msg = tr("Failed to load template (%1) (%2).")
+                                    .arg(filePath, p_e.what());
+                    qCritical() << msg;
+                    setInformationText(msg, ScrollDialog::InformationLevel::Error);
+                }
+        });
+}
+
+QString NewNoteDialog::getTemplateContent() const
+{
+    // TODO: parse snippets of the template.
+    return m_templateContent;
+}

+ 15 - 0
src/widgets/dialogs/newnotedialog.h

@@ -3,6 +3,9 @@
 
 #include "scrolldialog.h"
 
+class QComboBox;
+class QPlainTextEdit;
+
 namespace vnotex
 {
     class Notebook;
@@ -29,15 +32,27 @@ namespace vnotex
 
         void setupNodeInfoWidget(const Node *p_node, QWidget *p_parent);
 
+        void setupTemplateComboBox(QWidget *p_parent);
+
         bool validateNameInput(QString &p_msg);
 
         bool newNote();
 
         void initDefaultValues(const Node *p_node);
 
+        QString getTemplateContent() const;
+
         NodeInfoWidget *m_infoWidget = nullptr;
 
+        QComboBox *m_templateComboBox = nullptr;
+
+        QPlainTextEdit *m_templateTextEdit = nullptr;
+
+        QString m_templateContent;
+
         QSharedPointer<Node> m_newNode;
+
+        static QString s_lastTemplate;
     };
 } // ns vnotex
 

+ 9 - 1
src/widgets/dialogs/nodeinfowidget.cpp

@@ -1,6 +1,9 @@
 #include "nodeinfowidget.h"
 
-#include <QtWidgets>
+#include <QComboBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QFormLayout>
 
 #include "notebook/notebook.h"
 #include "../widgetsfactory.h"
@@ -174,3 +177,8 @@ void NodeInfoWidget::setupFileTypeComboBox(QWidget *p_parent)
                 m_nameLineEdit->setFocus();
             });
 }
+
+QFormLayout *NodeInfoWidget::getMainLayout() const
+{
+    return m_mainLayout;
+}

+ 3 - 0
src/widgets/dialogs/nodeinfowidget.h

@@ -35,6 +35,9 @@ namespace vnotex
 
         const Node *getParentNode() const;
 
+        // Allow upper level to add more widgets to the layout.
+        QFormLayout *getMainLayout() const;
+
     signals:
         void inputEdited();