support note template

This commit is contained in:
Le Tan 2021-06-21 21:01:40 +08:00
parent 88a3ee183f
commit af85dc5aed
16 changed files with 210 additions and 16 deletions

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

View File

@ -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);

View File

@ -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;

View File

@ -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 \

View File

@ -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();
}

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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()));

View File

@ -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
src/core/templatemgr.cpp Normal file
View File

@ -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
src/core/templatemgr.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();