QuickAccess: add quick note (#2373)

* feature_quick_create_note

* adj name and complete quick create

* del unused

* del unused

* adj name

* adj to const

* adj name 2

* adj

* fix

---------

Co-authored-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
chendapao 2023-08-24 22:51:17 +08:00 committed by GitHub
parent f773bc0348
commit e8fe0726ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 719 additions and 129 deletions

View File

@ -461,6 +461,10 @@ void VXNotebookConfigMgr::addChildNode(Node *p_parent, const QSharedPointer<Node
QSharedPointer<Node> VXNotebookConfigMgr::loadNodeByPath(const QSharedPointer<Node> &p_root, const QString &p_relativePath)
{
auto p = PathUtils::cleanPath(p_relativePath);
if (p == ".") {
return p_root;
}
auto paths = p.split('/', QString::SkipEmptyParts);
auto node = p_root;
for (auto &pa : paths) {

View File

@ -38,6 +38,34 @@ QJsonObject SessionConfig::NotebookItem::toJson() const
return jobj;
}
bool SessionConfig::QuickNoteScheme::operator==(const QuickNoteScheme &p_other) const
{
return m_name == p_other.m_name &&
m_folderPath == p_other.m_folderPath &&
m_noteName == p_other.m_noteName &&
m_template == p_other.m_template;
}
void SessionConfig::QuickNoteScheme::fromJson(const QJsonObject &p_jobj)
{
m_name = p_jobj[QStringLiteral("name")].toString();
m_folderPath = p_jobj[QStringLiteral("folder_path")].toString();
m_noteName = p_jobj[QStringLiteral("note_name")].toString();
m_template = p_jobj[QStringLiteral("template")].toString();
}
QJsonObject SessionConfig::QuickNoteScheme::toJson() const
{
QJsonObject jobj;
jobj[QStringLiteral("name")] = m_name;
jobj[QStringLiteral("folder_path")] = m_folderPath;
jobj[QStringLiteral("note_name")] = m_noteName;
jobj[QStringLiteral("template")] = m_template;
return jobj;
}
void SessionConfig::ExternalProgram::fromJson(const QJsonObject &p_jobj)
{
m_name = p_jobj[QStringLiteral("name")].toString();
@ -97,6 +125,8 @@ void SessionConfig::init()
loadHistory(sessionJobj);
loadQuickNoteSchemes(sessionJobj);
if (MainConfig::isVersionChanged()) {
doVersionSpecificOverride();
}
@ -235,6 +265,7 @@ QJsonObject SessionConfig::toJson() const
writeByteArray(obj, QStringLiteral("notebook_explorer_session"), m_notebookExplorerSession);
obj[QStringLiteral("external_programs")] = saveExternalPrograms();
obj[QStringLiteral("history")] = saveHistory();
obj[QStringLiteral("quick_note_schemes")] = saveQuickNoteSchemes();
return obj;
}
@ -458,6 +489,24 @@ QJsonArray SessionConfig::saveExternalPrograms() const
return arr;
}
void SessionConfig::loadQuickNoteSchemes(const QJsonObject &p_session)
{
const auto arr = p_session.value(QStringLiteral("quick_note_schemes")).toArray();
m_quickNoteSchemes.resize(arr.size());
for (int i = 0; i < arr.size(); ++i) {
m_quickNoteSchemes[i].fromJson(arr[i].toObject());
}
}
QJsonArray SessionConfig::saveQuickNoteSchemes() const
{
QJsonArray arr;
for (const auto &scheme : m_quickNoteSchemes) {
arr.append(scheme.toJson());
}
return arr;
}
const QVector<SessionConfig::ExternalProgram> &SessionConfig::getExternalPrograms() const
{
return m_externalPrograms;
@ -541,3 +590,13 @@ QJsonObject SessionConfig::saveExportOption() const
return obj;
}
const QVector<SessionConfig::QuickNoteScheme> &SessionConfig::getQuickNoteSchemes() const
{
return m_quickNoteSchemes;
}
void SessionConfig::setQuickNoteSchemes(const QVector<QuickNoteScheme>& p_schemes)
{
updateConfig(m_quickNoteSchemes, p_schemes, this);
}

View File

@ -55,6 +55,25 @@ namespace vnotex
QByteArray m_locationListState;
};
struct QuickNoteScheme
{
bool operator==(const QuickNoteScheme &p_other) const;
void fromJson(const QJsonObject &p_jobj);
QJsonObject toJson() const;
QString m_name;
// Where to create the quick note.
QString m_folderPath;
// Name of the quick note. Snippet is supported.
QString m_noteName;
QString m_template;
};
enum OpenGL
{
None,
@ -149,6 +168,9 @@ namespace vnotex
void removeHistory(const QString &p_itemPath);
void clearHistory();
const QVector<QuickNoteScheme> &getQuickNoteSchemes() const;
void setQuickNoteSchemes(const QVector<QuickNoteScheme>& p_schemes);
private:
void loadCore(const QJsonObject &p_session);
@ -166,6 +188,10 @@ namespace vnotex
QJsonArray saveExternalPrograms() const;
void loadQuickNoteSchemes(const QJsonObject &p_session);
QJsonArray saveQuickNoteSchemes() const;
void doVersionSpecificOverride();
void loadHistory(const QJsonObject &p_session);
@ -215,7 +241,9 @@ namespace vnotex
QVector<HistoryItem> m_history;
// Default folder path to open for external media like images and files.
QString m_externalMediaDefaultPath;;
QString m_externalMediaDefaultPath;
QVector<QuickNoteScheme> m_quickNoteSchemes;
};
} // ns vnotex

View File

@ -2,6 +2,8 @@
#include <QDir>
#include <utils/fileutils.h>
#include "configmgr.h"
using namespace vnotex;
@ -20,5 +22,17 @@ QStringList TemplateMgr::getTemplates() const
QString TemplateMgr::getTemplateFilePath(const QString &p_name) const
{
if (p_name.isEmpty()) {
return QString();
}
return QDir(getTemplateFolder()).filePath(p_name);
}
QString TemplateMgr::getTemplateContent(const QString &p_name) const
{
const auto filePath = getTemplateFilePath(p_name);
if (filePath.isEmpty()) {
return QString();
}
return FileUtils::readTextFile(filePath);
}

View File

@ -24,6 +24,8 @@ namespace vnotex
QString getTemplateFilePath(const QString &p_name) const;
QString getTemplateContent(const QString &p_name) const;
private:
TemplateMgr() = default;
};

View File

@ -79,6 +79,9 @@ namespace vnotex
// The handler should determine in which folder this note belongs to.
void newNoteRequested();
// Requested to new a quick note (maybe in current folder).
void newQuickNoteRequested();
// Requested to new a folder in current notebook.
void newFolderRequested();

View File

@ -14,6 +14,7 @@
#include <utils/fileutils.h>
#include "exception.h"
#include "nodeinfowidget.h"
#include "notetemplateselector.h"
#include <utils/widgetutils.h>
#include <core/templatemgr.h>
#include <core/configmgr.h>
@ -43,27 +44,8 @@ void NewNoteDialog::setupUI(const Node *p_node)
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();
}
m_templateSelector = new NoteTemplateSelector(m_infoWidget);
infoLayout->addRow(tr("Template:"), m_templateSelector);
setDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
@ -106,41 +88,56 @@ bool NewNoteDialog::validateNameInput(QString &p_msg)
void NewNoteDialog::acceptedButtonClicked()
{
s_lastTemplate = m_templateComboBox->currentData().toString();
s_lastTemplate = m_templateSelector->getCurrentTemplate();
{
auto fileType = FileTypeHelper::getInst().getFileTypeByName(m_infoWidget->getFileType()).m_type;
ConfigMgr::getInst().getWidgetConfig().setNewNoteDefaultFileType(static_cast<int>(fileType));
}
if (validateInputs() && newNote()) {
if (validateInputs()) {
Notebook *notebook = const_cast<Notebook *>(m_infoWidget->getNotebook());
Node *parentNode = const_cast<Node *>(m_infoWidget->getParentNode());
QString errMsg;
m_newNode = newNote(notebook,
parentNode,
m_infoWidget->getName(),
m_templateSelector->getTemplateContent(),
errMsg);
if (!m_newNode) {
setInformationText(errMsg, ScrollDialog::InformationLevel::Error);
return;
}
accept();
}
}
bool NewNoteDialog::newNote()
QSharedPointer<Node> NewNoteDialog::newNote(Notebook *p_notebook,
Node *p_parentNode,
const QString &p_name,
const QString &p_templateContent,
QString &p_errMsg)
{
m_newNode.clear();
Q_ASSERT(p_notebook && p_parentNode);
QSharedPointer<Node> newNode;
p_errMsg.clear();
Notebook *notebook = const_cast<Notebook *>(m_infoWidget->getNotebook());
Node *parentNode = const_cast<Node *>(m_infoWidget->getParentNode());
try {
m_newNode = notebook->newNode(parentNode,
newNode = p_notebook->newNode(p_parentNode,
Node::Flag::Content,
m_infoWidget->getName(),
getTemplateContent());
p_name,
evaluateTemplateContent(p_templateContent, p_name));
} catch (Exception &p_e) {
QString msg = tr("Failed to create note under (%1) in (%2) (%3).").arg(parentNode->getName(),
notebook->getName(),
p_e.what());
qCritical() << msg;
setInformationText(msg, ScrollDialog::InformationLevel::Error);
return false;
p_errMsg = tr("Failed to create note under (%1) in (%2) (%3).").arg(p_parentNode->getName(),
p_notebook->getName(),
p_e.what());
qCritical() << p_errMsg;
return nullptr;
}
emit notebook->nodeUpdated(m_newNode.data());
return true;
emit p_notebook->nodeUpdated(newNode.data());
return newNode;
}
const QSharedPointer<Node> &NewNoteDialog::getNewNode() const
@ -166,66 +163,17 @@ void NewNoteDialog::initDefaultValues(const Node *p_node)
if (!s_lastTemplate.isEmpty()) {
// Restore.
int idx = m_templateComboBox->findData(s_lastTemplate);
if (idx != -1) {
m_templateComboBox->setCurrentIndex(idx);
} else {
if (!m_templateSelector->setCurrentTemplate(s_lastTemplate)) {
s_lastTemplate.clear();
}
}
}
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);
}
m_templateComboBox->setCurrentIndex(0);
connect(m_templateComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &NewNoteDialog::updateCurrentTemplate);
}
QString NewNoteDialog::getTemplateContent() const
QString NewNoteDialog::evaluateTemplateContent(const QString &p_content, const QString &p_name)
{
int cursorOffset = 0;
return SnippetMgr::getInst().applySnippetBySymbol(m_templateContent,
return SnippetMgr::getInst().applySnippetBySymbol(p_content,
QString(),
cursorOffset,
SnippetMgr::generateOverrides(m_infoWidget->getName()));
}
void NewNoteDialog::updateCurrentTemplate()
{
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);
}
SnippetMgr::generateOverrides(p_name));
}

View File

@ -3,14 +3,12 @@
#include "scrolldialog.h"
class QComboBox;
class QPlainTextEdit;
namespace vnotex
{
class Notebook;
class Node;
class NodeInfoWidget;
class NoteTemplateSelector;
class NewNoteDialog : public ScrollDialog
{
@ -21,6 +19,12 @@ namespace vnotex
const QSharedPointer<Node> &getNewNode() const;
static QSharedPointer<Node> newNote(Notebook *p_notebook,
Node *p_parentNode,
const QString &p_name,
const QString &p_templateContent,
QString &p_errMsg);
protected:
void acceptedButtonClicked() Q_DECL_OVERRIDE;
@ -29,27 +33,17 @@ namespace vnotex
void setupNodeInfoWidget(const Node *p_node, QWidget *p_parent);
void setupTemplateComboBox(QWidget *p_parent);
bool validateInputs();
bool validateNameInput(QString &p_msg);
bool newNote();
void initDefaultValues(const Node *p_node);
QString getTemplateContent() const;
void updateCurrentTemplate();
static QString evaluateTemplateContent(const QString &p_content, const QString &p_name);
NodeInfoWidget *m_infoWidget = nullptr;
QComboBox *m_templateComboBox = nullptr;
QPlainTextEdit *m_templateTextEdit = nullptr;
QString m_templateContent;
NoteTemplateSelector *m_templateSelector = nullptr;
QSharedPointer<Node> m_newNode;

View File

@ -0,0 +1,112 @@
#include "notetemplateselector.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QComboBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <core/templatemgr.h>
#include <core/exception.h>
#include <utils/fileutils.h>
#include <utils/widgetutils.h>
#include <widgets/widgetsfactory.h>
using namespace vnotex;
NoteTemplateSelector::NoteTemplateSelector(QWidget *p_parent)
: QWidget(p_parent)
{
setupUI();
}
void NoteTemplateSelector::setupUI()
{
auto mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
auto selectorLayout = new QHBoxLayout();
mainLayout->addLayout(selectorLayout);
setupTemplateComboBox(this);
selectorLayout->addWidget(m_templateComboBox, 1);
auto manageBtn = new QPushButton(tr("Manage"), this);
selectorLayout->addWidget(manageBtn);
connect(manageBtn, &QPushButton::clicked,
this, []() {
WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(TemplateMgr::getInst().getTemplateFolder()));
});
m_templateTextEdit = WidgetsFactory::createPlainTextConsole(this);
mainLayout->addWidget(m_templateTextEdit);
m_templateTextEdit->hide();
}
void NoteTemplateSelector::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);
}
m_templateComboBox->setCurrentIndex(0);
connect(m_templateComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &NoteTemplateSelector::updateCurrentTemplate);
}
void NoteTemplateSelector::updateCurrentTemplate()
{
m_templateContent.clear();
m_templateTextEdit->clear();
auto templateName = m_templateComboBox->currentData().toString();
if (templateName.isEmpty()) {
m_templateTextEdit->hide();
emit templateChanged();
return;
}
const auto filePath = TemplateMgr::getInst().getTemplateFilePath(templateName);
try {
m_templateContent = FileUtils::readTextFile(filePath);
m_templateTextEdit->setPlainText(m_templateContent);
} catch (Exception &p_e) {
QString msg = tr("Failed to load template (%1) (%2).")
.arg(filePath, p_e.what());
qCritical() << msg;
m_templateTextEdit->setPlainText(msg);
}
m_templateTextEdit->show();
emit templateChanged();
}
QString NoteTemplateSelector::getCurrentTemplate() const
{
return m_templateComboBox->currentData().toString();
}
bool NoteTemplateSelector::setCurrentTemplate(const QString &p_template)
{
int idx = m_templateComboBox->findData(p_template);
if (idx != -1) {
m_templateComboBox->setCurrentIndex(idx);
return true;
} else {
return false;
}
}
const QString& NoteTemplateSelector::getTemplateContent() const
{
return m_templateContent;
}

View File

@ -0,0 +1,40 @@
#ifndef NOTETEMPLATESELECTOR_H
#define NOTETEMPLATESELECTOR_H
#include <QWidget>
class QComboBox;
class QPlainTextEdit;
namespace vnotex
{
class NoteTemplateSelector : public QWidget
{
Q_OBJECT
public:
explicit NoteTemplateSelector(QWidget *p_parent = nullptr);
QString getCurrentTemplate() const;
bool setCurrentTemplate(const QString &p_template);
const QString& getTemplateContent() const;
signals:
void templateChanged();
private:
void setupUI();
void setupTemplateComboBox(QWidget *p_parent);
void updateCurrentTemplate();
QComboBox *m_templateComboBox = nullptr;
QPlainTextEdit *m_templateTextEdit = nullptr;
QString m_templateContent;
};
}
#endif // NOTETEMPLATESELECTOR_H

View File

@ -39,6 +39,8 @@ void FileAssociationPage::setupUI()
m_externalProgramsBox = new QGroupBox(tr("External Programs"), this);
WidgetsFactory::createFormLayout(m_externalProgramsBox);
mainLayout->addWidget(m_externalProgramsBox);
mainLayout->addStretch();
}
void FileAssociationPage::loadInternal()

View File

@ -46,6 +46,8 @@ void ImageHostPage::setupUI()
auto box = setupGeneralBox(this);
m_mainLayout->addWidget(box);
m_mainLayout->addStretch();
}
QGroupBox *ImageHostPage::setupGeneralBox(QWidget *p_parent)
@ -54,9 +56,8 @@ QGroupBox *ImageHostPage::setupGeneralBox(QWidget *p_parent)
auto layout = WidgetsFactory::createFormLayout(box);
{
m_defaultImageHostComboBox = WidgetsFactory::createComboBox(box);
// Add items in loadInternal().
m_defaultImageHostComboBox = WidgetsFactory::createComboBox(box);
const QString label(tr("Default image host:"));
layout->addRow(label, m_defaultImageHostComboBox);
@ -121,11 +122,15 @@ void ImageHostPage::loadInternal()
}
}
removeLastStretch();
// Setup boxes.
for (const auto &host : hosts) {
auto box = setupGroupBoxForImageHost(host, this);
addWidgetToLayout(box);
}
m_mainLayout->addStretch();
}
bool ImageHostPage::saveInternal()
@ -185,8 +190,12 @@ void ImageHostPage::newImageHost()
{
NewImageHostDialog dialog(this);
if (dialog.exec()) {
removeLastStretch();
auto box = setupGroupBoxForImageHost(dialog.getNewImageHost(), this);
addWidgetToLayout(box);
m_mainLayout->addStretch();
}
}
@ -293,3 +302,12 @@ void ImageHostPage::testImageHost(const QString &p_hostName)
QString(),
msg);
}
void ImageHostPage::removeLastStretch()
{
auto item = m_mainLayout->itemAt(m_mainLayout->count() - 1);
if (item) {
m_mainLayout->removeItem(item);
delete item;
}
}

View File

@ -46,6 +46,8 @@ namespace vnotex
QGroupBox *setupGeneralBox(QWidget *p_parent);
void removeLastStretch();
QVBoxLayout *m_mainLayout = nullptr;
// [host] -> list of related fields.

View File

@ -46,6 +46,8 @@ void MarkdownEditorPage::setupUI()
auto editBox = setupEditGroup();
mainLayout->addWidget(editBox);
mainLayout->addStretch();
}
void MarkdownEditorPage::loadInternal()

View File

@ -6,13 +6,24 @@
#include <QPlainTextEdit>
#include <QDebug>
#include <QFileDialog>
#include <QCheckBox>
#include <QPushButton>
#include <QComboBox>
#include <QLineEdit>
#include <QInputDialog>
#include <widgets/widgetsfactory.h>
#include <core/sessionconfig.h>
#include <core/coreconfig.h>
#include <core/configmgr.h>
#include <core/notebookmgr.h>
#include <core/vnotex.h>
#include <utils/widgetutils.h>
#include <widgets/locationinputwithbrowsebutton.h>
#include <widgets/lineeditwithsnippet.h>
#include <widgets/widgetsfactory.h>
#include <widgets/messageboxhelper.h>
#include "../notetemplateselector.h"
using namespace vnotex;
@ -31,6 +42,11 @@ void QuickAccessPage::setupUI()
auto quickAccessBox = setupQuickAccessGroup();
mainLayout->addWidget(quickAccessBox);
auto quickNoteBox = setupQuickNoteGroup();
mainLayout->addWidget(quickNoteBox);
mainLayout->addStretch();
}
void QuickAccessPage::loadInternal()
@ -45,6 +61,26 @@ void QuickAccessPage::loadInternal()
m_quickAccessTextEdit->setPlainText(quickAccess.join(QChar('\n')));
}
}
loadQuickNoteSchemes();
}
void QuickAccessPage::loadQuickNoteSchemes()
{
const auto &sessionConfig = ConfigMgr::getInst().getSessionConfig();
m_quickNoteSchemes = sessionConfig.getQuickNoteSchemes();
m_quickNoteCurrentIndex = -1;
m_quickNoteSchemeComboBox->clear();
for (const auto &scheme : m_quickNoteSchemes) {
m_quickNoteSchemeComboBox->addItem(scheme.m_name);
}
if (m_quickNoteSchemeComboBox->count() > 0) {
m_quickNoteSchemeComboBox->setCurrentIndex(0);
// Manually call the handler.
setCurrentQuickNote(0);
}
}
bool QuickAccessPage::saveInternal()
@ -60,9 +96,20 @@ bool QuickAccessPage::saveInternal()
}
}
saveQuickNoteSchemes();
return true;
}
void QuickAccessPage::saveQuickNoteSchemes()
{
// Save current quick note scheme from inputs.
saveCurrentQuickNote();
auto &sessionConfig = ConfigMgr::getInst().getSessionConfig();
sessionConfig.setQuickNoteSchemes(m_quickNoteSchemes);
}
QString QuickAccessPage::title() const
{
return tr("Quick Access");
@ -104,6 +151,7 @@ QGroupBox *QuickAccessPage::setupQuickAccessGroup()
{
m_quickAccessTextEdit = WidgetsFactory::createPlainTextEdit(box);
m_quickAccessTextEdit->setToolTip(tr("Edit the files pinned to Quick Access (one file per line)"));
m_quickAccessTextEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
const QString label(tr("Quick Access:"));
layout->addRow(label, m_quickAccessTextEdit);
@ -114,3 +162,180 @@ QGroupBox *QuickAccessPage::setupQuickAccessGroup()
return box;
}
QString QuickAccessPage::getDefaultQuickNoteFolderPath()
{
auto defaultPath = QDir::homePath();
auto currentNotebook = VNoteX::getInst().getNotebookMgr().getCurrentNotebook();
if (currentNotebook) {
defaultPath = currentNotebook->getRootFolderAbsolutePath();
}
return defaultPath;
}
QGroupBox *QuickAccessPage::setupQuickNoteGroup()
{
auto box = new QGroupBox(tr("Quick Note"), this);
auto mainLayout = WidgetsFactory::createFormLayout(box);
{
auto selectorLayout = new QHBoxLayout();
// Add items in loadInternal().
m_quickNoteSchemeComboBox = WidgetsFactory::createComboBox(box);
selectorLayout->addWidget(m_quickNoteSchemeComboBox, 1);
m_quickNoteSchemeComboBox->setPlaceholderText(tr("No scheme to show"));
auto newBtn = new QPushButton(tr("New"), box);
connect(newBtn, &QPushButton::clicked,
this, &QuickAccessPage::newQuickNoteScheme);
selectorLayout->addWidget(newBtn);
auto deleteBtn = new QPushButton(tr("Delete"), box);
deleteBtn->setEnabled(false);
connect(deleteBtn, &QPushButton::clicked,
this, &QuickAccessPage::removeQuickNoteScheme);
selectorLayout->addWidget(deleteBtn);
const QString label(tr("Scheme:"));
mainLayout->addRow(label, selectorLayout);
addSearchItem(label, m_quickNoteSchemeComboBox);
connect(m_quickNoteSchemeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &QuickAccessPage::pageIsChanged);
connect(m_quickNoteSchemeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [deleteBtn](int idx) {
deleteBtn->setEnabled(idx > -1);
});
}
m_quickNoteInfoGroupBox = new QGroupBox(box);
mainLayout->addRow(m_quickNoteInfoGroupBox);
auto infoLayout = WidgetsFactory::createFormLayout(m_quickNoteInfoGroupBox);
{
const QString label(tr("Folder path:"));
m_quickNoteFolderPathInput = new LocationInputWithBrowseButton(m_quickNoteInfoGroupBox);
m_quickNoteFolderPathInput->setPlaceholderText(tr("Empty to use current explored folder dynamically"));
infoLayout->addRow(label, m_quickNoteFolderPathInput);
addSearchItem(label, m_quickNoteFolderPathInput);
connect(m_quickNoteFolderPathInput, &LocationInputWithBrowseButton::textChanged,
this, &QuickAccessPage::pageIsChanged);
connect(m_quickNoteFolderPathInput, &LocationInputWithBrowseButton::clicked,
this, [this]() {
auto folderPath = QFileDialog::getExistingDirectory(this,
tr("Select Quick Note Folder"),
getDefaultQuickNoteFolderPath());
if (!folderPath.isEmpty()) {
m_quickNoteFolderPathInput->setText(folderPath);
}
});
}
{
const QString label(tr("Note name:"));
m_quickNoteNoteNameLineEdit = WidgetsFactory::createLineEditWithSnippet(m_quickNoteInfoGroupBox);
infoLayout->addRow(label, m_quickNoteNoteNameLineEdit);
connect(m_quickNoteNoteNameLineEdit, &QLineEdit::textChanged,
this, &QuickAccessPage::pageIsChanged);
}
{
const QString label(tr("Note template:"));
m_quickNoteTemplateSelector = new NoteTemplateSelector(m_quickNoteInfoGroupBox);
infoLayout->addRow(label, m_quickNoteTemplateSelector);
connect(m_quickNoteTemplateSelector, &NoteTemplateSelector::templateChanged,
this, &QuickAccessPage::pageIsChanged);
}
m_quickNoteInfoGroupBox->setVisible(false);
connect(m_quickNoteSchemeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [this](int idx) {
if (isLoading()) {
return;
}
setCurrentQuickNote(idx);
});
return box;
}
void QuickAccessPage::newQuickNoteScheme()
{
bool isDuplicated = false;
QString schemeName;
do {
schemeName = QInputDialog::getText(this, tr("Quick Note Scheme"),
isDuplicated ? tr("Scheme name already exists! Try again:") : tr("Scheme name:"));
if (schemeName.isEmpty()) {
return;
}
isDuplicated = m_quickNoteSchemeComboBox->findText(schemeName) != -1;
} while (isDuplicated);
SessionConfig::QuickNoteScheme scheme;
scheme.m_name = schemeName;
scheme.m_folderPath = getDefaultQuickNoteFolderPath();
scheme.m_noteName = tr("quick_note_%da%.md");
m_quickNoteSchemes.push_back(scheme);
m_quickNoteSchemeComboBox->addItem(schemeName);
m_quickNoteSchemeComboBox->setCurrentText(schemeName);
emit pageIsChanged();
}
void QuickAccessPage::removeQuickNoteScheme()
{
int idx = m_quickNoteSchemeComboBox->currentIndex();
Q_ASSERT(idx > -1);
auto& scheme = m_quickNoteSchemes[idx];
int ret = MessageBoxHelper::questionOkCancel(MessageBoxHelper::Type::Question,
tr("Delete quick note scheme (%1)?").arg(scheme.m_name));
if (ret != QMessageBox::Ok) {
return;
}
m_quickNoteCurrentIndex = -1;
m_quickNoteSchemes.removeAt(idx);
m_quickNoteSchemeComboBox->removeItem(idx);
emit pageIsChanged();
}
void QuickAccessPage::saveCurrentQuickNote()
{
if (m_quickNoteCurrentIndex < 0) {
return;
}
Q_ASSERT(m_quickNoteCurrentIndex < m_quickNoteSchemes.size());
auto& scheme = m_quickNoteSchemes[m_quickNoteCurrentIndex];
scheme.m_folderPath = m_quickNoteFolderPathInput->text();
// No need to apply the snippet for now.
scheme.m_noteName = m_quickNoteNoteNameLineEdit->text();
scheme.m_template = m_quickNoteTemplateSelector->getCurrentTemplate();
}
void QuickAccessPage::loadCurrentQuickNote()
{
if (m_quickNoteCurrentIndex < 0) {
m_quickNoteFolderPathInput->setText(QString());
m_quickNoteNoteNameLineEdit->setText(QString());
m_quickNoteTemplateSelector->setCurrentTemplate(QString());
return;
}
Q_ASSERT(m_quickNoteCurrentIndex < m_quickNoteSchemes.size());
const auto& scheme = m_quickNoteSchemes[m_quickNoteCurrentIndex];
m_quickNoteFolderPathInput->setText(scheme.m_folderPath);
m_quickNoteNoteNameLineEdit->setText(scheme.m_noteName);
m_quickNoteTemplateSelector->setCurrentTemplate(scheme.m_template);
}
void QuickAccessPage::setCurrentQuickNote(int idx)
{
saveCurrentQuickNote();
m_quickNoteCurrentIndex = idx;
loadCurrentQuickNote();
m_quickNoteInfoGroupBox->setVisible(idx > -1);
}

View File

@ -3,12 +3,17 @@
#include "settingspage.h"
#include <core/sessionconfig.h>
class QGroupBox;
class QPlainTextEdit;
class QComboBox;
namespace vnotex
{
class LocationInputWithBrowseButton;
class LineEditWithSnippet;
class NoteTemplateSelector;
class QuickAccessPage : public SettingsPage
{
@ -30,9 +35,41 @@ namespace vnotex
QGroupBox *setupQuickAccessGroup();
QGroupBox *setupQuickNoteGroup();
void newQuickNoteScheme();
void removeQuickNoteScheme();
void saveCurrentQuickNote();
void loadCurrentQuickNote();
void loadQuickNoteSchemes();
void saveQuickNoteSchemes();
void setCurrentQuickNote(int idx);
static QString getDefaultQuickNoteFolderPath();
LocationInputWithBrowseButton *m_flashPageInput = nullptr;
QPlainTextEdit *m_quickAccessTextEdit = nullptr;
QComboBox *m_quickNoteSchemeComboBox = nullptr;
LocationInputWithBrowseButton *m_quickNoteFolderPathInput = nullptr;
LineEditWithSnippet *m_quickNoteNoteNameLineEdit = nullptr;
NoteTemplateSelector *m_quickNoteTemplateSelector = nullptr;
QGroupBox *m_quickNoteInfoGroupBox = nullptr;
QVector<SessionConfig::QuickNoteScheme> m_quickNoteSchemes;
int m_quickNoteCurrentIndex = -1;
};
}

View File

@ -73,7 +73,9 @@ void SettingsPage::pageIsChangedWithRestartNeeded()
void SettingsPage::load()
{
m_loading = true;
loadInternal();
m_loading = false;
m_changed = false;
m_restartNeeded = false;
}
@ -115,3 +117,8 @@ bool SettingsPage::isRestartNeeded() const
{
return m_restartNeeded;
}
bool SettingsPage::isLoading() const
{
return m_loading;
}

View File

@ -44,6 +44,8 @@ namespace vnotex
void setError(const QString &p_err);
bool isLoading() const;
protected slots:
void pageIsChanged();
@ -70,6 +72,8 @@ namespace vnotex
bool m_restartNeeded = false;
bool m_loading = false;
QString m_error;
};
}

View File

@ -86,11 +86,7 @@ void ThemePage::setupUI()
layout->addWidget(scrollArea, 0, 2, 5, 1);
}
// Override.
{
auto box = new QGroupBox(tr("Style Override"), this);
mainLayout->addWidget(box);
}
mainLayout->addStretch();
}
void ThemePage::loadInternal()

View File

@ -374,7 +374,7 @@ bool MarkdownEditor::insertImageToBufferFromLocalFile(const QString &p_title,
ba = FileUtils::readFile(p_srcImagePath);
} catch (Exception &e) {
MessageBoxHelper::notify(MessageBoxHelper::Warning,
QString("Failed to read local image file (%1) (%2).").arg(p_srcImagePath, e.what()),
tr("Failed to read local image file (%1) (%2).").arg(p_srcImagePath, e.what()),
this);
return false;
}
@ -387,7 +387,7 @@ bool MarkdownEditor::insertImageToBufferFromLocalFile(const QString &p_title,
destFilePath = m_buffer->insertImage(p_srcImagePath, destFileName);
} catch (Exception &e) {
MessageBoxHelper::notify(MessageBoxHelper::Warning,
QString("Failed to insert image from local file (%1) (%2).").arg(p_srcImagePath, e.what()),
tr("Failed to insert image from local file (%1) (%2).").arg(p_srcImagePath, e.what()),
this);
return false;
}
@ -430,7 +430,7 @@ bool MarkdownEditor::insertImageToBufferFromData(const QString &p_title,
destFilePath = m_buffer->insertImage(p_image, destFileName);
} catch (Exception &e) {
MessageBoxHelper::notify(MessageBoxHelper::Warning,
QString("Failed to insert image from data (%1).").arg(e.what()),
tr("Failed to insert image from data (%1).").arg(e.what()),
this);
return false;
}
@ -1470,7 +1470,7 @@ QString MarkdownEditor::saveToImageHost(const QByteArray &p_imageData, const QSt
if (targetUrl.isEmpty()) {
MessageBoxHelper::notify(MessageBoxHelper::Warning,
QString("Failed to upload image to image host (%1) as (%2).").arg(m_imageHost->getName(), destPath),
tr("Failed to upload image to image host (%1) as (%2).").arg(m_imageHost->getName(), destPath),
QString(),
errMsg,
this);
@ -1551,7 +1551,7 @@ void MarkdownEditor::uploadImagesToImageHost()
ba = FileUtils::readFile(link.m_path);
} catch (Exception &e) {
MessageBoxHelper::notify(MessageBoxHelper::Warning,
QString("Failed to read local image file (%1) (%2).").arg(link.m_path, e.what()),
tr("Failed to read local image file (%1) (%2).").arg(link.m_path, e.what()),
this);
continue;
}
@ -1569,7 +1569,7 @@ void MarkdownEditor::uploadImagesToImageHost()
if (targetUrl.isEmpty()) {
MessageBoxHelper::notify(MessageBoxHelper::Warning,
QString("Failed to upload image to image host (%1) as (%2).").arg(host->getName(), destPath),
tr("Failed to upload image to image host (%1) as (%2).").arg(host->getName(), destPath),
QString(),
errMsg,
this);

View File

@ -44,3 +44,8 @@ void LocationInputWithBrowseButton::setToolTip(const QString &p_tip)
{
m_lineEdit->setToolTip(p_tip);
}
void LocationInputWithBrowseButton::setPlaceholderText(const QString &p_text)
{
m_lineEdit->setPlaceholderText(p_text);
}

View File

@ -22,6 +22,8 @@ namespace vnotex
void setToolTip(const QString &p_tip);
void setPlaceholderText(const QString &p_text);
signals:
void clicked();

View File

@ -332,6 +332,8 @@ void MainWindow::setupNotebookExplorer()
m_notebookExplorer, &NotebookExplorer::newFolder);
connect(&VNoteX::getInst(), &VNoteX::newNoteRequested,
m_notebookExplorer, &NotebookExplorer::newNote);
connect(&VNoteX::getInst(), &VNoteX::newQuickNoteRequested,
m_notebookExplorer, &NotebookExplorer::newQuickNote);
connect(&VNoteX::getInst(), &VNoteX::importFileRequested,
m_notebookExplorer, &NotebookExplorer::importFile);
connect(&VNoteX::getInst(), &VNoteX::importFolderRequested,

View File

@ -8,6 +8,7 @@
#include <QProgressDialog>
#include "titlebar.h"
#include "dialogs/selectdialog.h"
#include "dialogs/newnotebookdialog.h"
#include "dialogs/newnotebookfromfolderdialog.h"
#include "dialogs/newfolderdialog.h"
@ -22,6 +23,7 @@
#include <utils/iconutils.h>
#include <utils/widgetutils.h>
#include <utils/pathutils.h>
#include <utils/fileutils.h>
#include "notebookselector.h"
#include "notebooknodeexplorer.h"
#include "messageboxhelper.h"
@ -32,6 +34,10 @@
#include <core/events.h>
#include <core/exception.h>
#include <core/fileopenparameters.h>
#include <core/notebookmgr.h>
#include <core/templatemgr.h>
#include <snippet/snippetmgr.h>
#include "navigationmodemgr.h"
#include "widgetsfactory.h"
@ -269,12 +275,11 @@ void NotebookExplorer::newNote()
auto node = checkNotebookAndGetCurrentExploredFolderNode();
if (!node) {
return;
}
}
NewNoteDialog dialog(node, VNoteX::getInst().getMainWindow());
NewNoteDialog dialog(node, VNoteX::getInst().getMainWindow());
if (dialog.exec() == QDialog::Accepted) {
m_nodeExplorer->setCurrentNode(dialog.getNewNode().data());
// Open it right now.
auto paras = QSharedPointer<FileOpenParameters>::create();
paras->m_mode = ViewWindowMode::Edit;
@ -283,6 +288,69 @@ void NotebookExplorer::newNote()
}
}
void NotebookExplorer::newQuickNote()
{
auto &sessionConfig = ConfigMgr::getInst().getSessionConfig();
const auto& schemes = sessionConfig.getQuickNoteSchemes();
if (schemes.isEmpty()) {
MessageBoxHelper::notify(MessageBoxHelper::Information,
tr("Please set up quick note schemes in the Settings dialog first."),
VNoteX::getInst().getMainWindow());
return;
}
SelectDialog dialog(tr("New Quick Note"), VNoteX::getInst().getMainWindow());
for (int i = 0; i < schemes.size(); ++i) {
dialog.addSelection(schemes[i].m_name, i);
}
if (dialog.exec() != QDialog::Accepted) {
return;
}
int selection = dialog.getSelection();
const auto &scheme = schemes[selection];
Notebook *notebook = m_currentNotebook.data();
Node *parentNode = currentExploredFolderNode();
if (!scheme.m_folderPath.isEmpty()) {
auto node = VNoteX::getInst().getNotebookMgr().loadNodeByPath(scheme.m_folderPath);
if (node) {
notebook = node->getNotebook();
parentNode = node.data();
}
}
if (!parentNode) {
MessageBoxHelper::notify(MessageBoxHelper::Information,
tr("The quick note should be created within a notebook."),
VNoteX::getInst().getMainWindow());
return;
}
QFileInfo finfo(SnippetMgr::getInst().applySnippetBySymbol(scheme.m_noteName));
QString newName = FileUtils::generateFileNameWithSequence(parentNode->fetchAbsolutePath(),
finfo.completeBaseName(), finfo.suffix());
QString errMsg;
auto newNode = NewNoteDialog::newNote(notebook, parentNode, newName,
TemplateMgr::getInst().getTemplateContent(scheme.m_template),
errMsg);
if (!newNode) {
MessageBoxHelper::notify(MessageBoxHelper::Information,
tr("Failed to create quick note from scheme (%1) (%2)").arg(scheme.m_name, errMsg),
VNoteX::getInst().getMainWindow());
return;
}
m_nodeExplorer->setCurrentNode(newNode.data());
// Open it right now.
auto paras = QSharedPointer<FileOpenParameters>::create();
paras->m_mode = ViewWindowMode::Edit;
paras->m_newFile = true;
emit VNoteX::getInst().openNodeRequested(newNode.data(), paras);
}
Node *NotebookExplorer::currentExploredFolderNode() const
{
return m_nodeExplorer->currentExploredFolderNode();

View File

@ -51,6 +51,8 @@ namespace vnotex
void newNote();
void newQuickNote();
void importFile();
void importFolder();

View File

@ -14,9 +14,6 @@
#include <QHash>
#include <QTabBar>
#include "viewwindow.h"
#include "mainwindow.h"
#include "propertydefs.h"
#include <utils/widgetutils.h>
#include <utils/docsutils.h>
#include <utils/urldragdroputils.h>
@ -34,6 +31,12 @@
#include "editors/plantumlhelper.h"
#include "editors/graphvizhelper.h"
#include <core/historymgr.h>
#include <widgets/dialogs/selectdialog.h>
#include "viewwindow.h"
#include "mainwindow.h"
#include "propertydefs.h"
#include "messageboxhelper.h"
using namespace vnotex;

View File

@ -25,6 +25,7 @@
#include <core/coreconfig.h>
#include "propertydefs.h"
#include "fileopenparameters.h"
#include "sessionconfig.h"
using namespace vnotex;
@ -80,7 +81,13 @@ void ViewSplit::setupUI()
closeTab(p_idx);
});
connect(this, &QTabWidget::tabBarDoubleClicked,
this, &ViewSplit::closeTab);
this, [this](int p_idx) {
if (p_idx == -1) {
emit VNoteX::getInst().newQuickNoteRequested();
} else {
closeTab(p_idx);
}
});
connect(this, &QTabWidget::tabBarClicked,
this, [this](int p_idx) {
Q_UNUSED(p_idx);

View File

@ -92,6 +92,8 @@ namespace vnotex
void distributeSplitsRequested();
void newQuickNoteRequested();
void removeSplitRequested(ViewSplit *p_split);
void removeSplitAndWorkspaceRequested(ViewSplit *p_split);

View File

@ -42,6 +42,7 @@ SOURCES += \
$$PWD/dialogs/tableinsertdialog.cpp \
$$PWD/dialogs/updater.cpp \
$$PWD/dialogs/viewtagsdialog.cpp \
$$PWD/dialogs/notetemplateselector.cpp \
$$PWD/dockwidgethelper.cpp \
$$PWD/dragdropareaindicator.cpp \
$$PWD/editors/graphhelper.cpp \
@ -181,6 +182,7 @@ HEADERS += \
$$PWD/dialogs/tableinsertdialog.h \
$$PWD/dialogs/updater.h \
$$PWD/dialogs/viewtagsdialog.h \
$$PWD/dialogs/notetemplateselector.h \
$$PWD/dockwidgethelper.h \
$$PWD/dragdropareaindicator.h \
$$PWD/editors/graphhelper.h \