diff --git a/src/core/coreconfig.cpp b/src/core/coreconfig.cpp index 18436aa3..8e03df84 100644 --- a/src/core/coreconfig.cpp +++ b/src/core/coreconfig.cpp @@ -8,6 +8,7 @@ using namespace vnotex; #define READSTR(key) readString(appObj, userObj, (key)) #define READINT(key) readInt(appObj, userObj, (key)) #define READBOOL(key) readBool(appObj, userObj, (key)) +#define READSTRLIST(key) readStringList(appObj, userObj, (key)) QStringList CoreConfig::s_availableLocales; @@ -46,6 +47,8 @@ void CoreConfig::init(const QJsonObject &p_app, if (m_toolBarIconSize <= 0) { m_toolBarIconSize = 16; } + + loadNoteManagement(appObj, userObj); } QJsonObject CoreConfig::toJson() const @@ -97,6 +100,20 @@ void CoreConfig::loadShortcuts(const QJsonObject &p_app, const QJsonObject &p_us } } +void CoreConfig::loadNoteManagement(const QJsonObject &p_app, const QJsonObject &p_user) +{ + const auto topAppObj = p_app.value(QStringLiteral("note_management")).toObject(); + const auto topUserObj = p_user.value(QStringLiteral("note_management")).toObject(); + + // External node. + { + const auto appObj = topAppObj.value(QStringLiteral("external_node")).toObject(); + const auto userObj = topUserObj.value(QStringLiteral("external_node")).toObject(); + + m_externalNodeExcludePatterns = READSTRLIST(QStringLiteral("exclude_patterns")); + } +} + QJsonObject CoreConfig::saveShortcuts() const { QJsonObject obj; @@ -126,3 +143,8 @@ void CoreConfig::setToolBarIconSize(int p_size) Q_ASSERT(p_size > 0); updateConfig(m_toolBarIconSize, p_size, this); } + +const QStringList &CoreConfig::getExternalNodeExcludePatterns() const +{ + return m_externalNodeExcludePatterns; +} diff --git a/src/core/coreconfig.h b/src/core/coreconfig.h index dcae4ab3..78613c1f 100644 --- a/src/core/coreconfig.h +++ b/src/core/coreconfig.h @@ -56,11 +56,15 @@ namespace vnotex int getToolBarIconSize() const; void setToolBarIconSize(int p_size); + const QStringList &getExternalNodeExcludePatterns() const; + static const QStringList &getAvailableLocales(); private: void loadShortcuts(const QJsonObject &p_app, const QJsonObject &p_user); + void loadNoteManagement(const QJsonObject &p_app, const QJsonObject &p_user); + QJsonObject saveShortcuts() const; // Theme name. @@ -75,6 +79,8 @@ namespace vnotex // Icon size of MainWindow tool bar. int m_toolBarIconSize = 16; + QStringList m_externalNodeExcludePatterns; + static QStringList s_availableLocales; }; } // ns vnotex diff --git a/src/core/iconfig.h b/src/core/iconfig.h index 27412734..8557e410 100644 --- a/src/core/iconfig.h +++ b/src/core/iconfig.h @@ -3,6 +3,7 @@ #include #include +#include namespace vnotex { @@ -80,6 +81,19 @@ namespace vnotex return read(p_default, p_user, p_key).toString(); } + static QStringList readStringList(const QJsonObject &p_default, + const QJsonObject &p_user, + const QString &p_key) + { + auto arr = read(p_default, p_user, p_key).toArray(); + QStringList res; + res.reserve(arr.size()); + for (const auto &ele : arr) { + res.push_back(ele.toString()); + } + return res; + } + static QString readString(const QJsonObject &p_obj, const QString &p_key) { diff --git a/src/core/notebook/notebook.cpp b/src/core/notebook/notebook.cpp index 5cc45d03..0511de6a 100644 --- a/src/core/notebook/notebook.cpp +++ b/src/core/notebook/notebook.cpp @@ -347,7 +347,8 @@ QSharedPointer Notebook::copyAsNode(Node *p_parent, return m_configMgr->copyAsNode(p_parent, p_flags, p_path); } -void Notebook::reloadNode(Node *p_node) +void Notebook::reloadNodes() { - m_configMgr->reloadNode(p_node); + m_root.clear(); + getRootNode(); } diff --git a/src/core/notebook/notebook.h b/src/core/notebook/notebook.h index a6d6d970..4307b225 100644 --- a/src/core/notebook/notebook.h +++ b/src/core/notebook/notebook.h @@ -127,7 +127,7 @@ namespace vnotex bool isBuiltInFolder(const Node *p_node, const QString &p_name) const; - void reloadNode(Node *p_node); + void reloadNodes(); static const QString c_defaultAttachmentFolder; diff --git a/src/core/notebookconfigmgr/inotebookconfigmgr.h b/src/core/notebookconfigmgr/inotebookconfigmgr.h index 5a69980d..858a0b60 100644 --- a/src/core/notebookconfigmgr/inotebookconfigmgr.h +++ b/src/core/notebookconfigmgr/inotebookconfigmgr.h @@ -77,8 +77,6 @@ namespace vnotex virtual QVector> fetchExternalChildren(Node *p_node) const = 0; - virtual void reloadNode(Node *p_node) = 0; - protected: // Version of the config processing code. virtual QString getCodeVersion() const; diff --git a/src/core/notebookconfigmgr/vxnotebookconfigmgr.cpp b/src/core/notebookconfigmgr/vxnotebookconfigmgr.cpp index 85f3c68c..c94d4eaf 100644 --- a/src/core/notebookconfigmgr/vxnotebookconfigmgr.cpp +++ b/src/core/notebookconfigmgr/vxnotebookconfigmgr.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -166,6 +167,10 @@ const QString VXNotebookConfigMgr::c_nodeConfigName = "vx.json"; const QString VXNotebookConfigMgr::c_recycleBinFolderName = "vx_recycle_bin"; +bool VXNotebookConfigMgr::s_initialized = false; + +QVector VXNotebookConfigMgr::s_externalNodeExcludePatterns; + VXNotebookConfigMgr::VXNotebookConfigMgr(const QString &p_name, const QString &p_displayName, const QString &p_description, @@ -174,6 +179,17 @@ VXNotebookConfigMgr::VXNotebookConfigMgr(const QString &p_name, : BundleNotebookConfigMgr(p_backend, p_parent), m_info(p_name, p_displayName, p_description) { + if (!s_initialized) { + s_initialized = true; + + const auto &patterns = ConfigMgr::getInst().getCoreConfig().getExternalNodeExcludePatterns(); + s_externalNodeExcludePatterns.reserve(patterns.size()); + for (const auto &pat : patterns) { + if (!pat.isEmpty()) { + s_externalNodeExcludePatterns.push_back(QRegExp(pat, Qt::CaseInsensitive, QRegExp::Wildcard)); + } + } + } } QString VXNotebookConfigMgr::getName() const @@ -927,6 +943,10 @@ QVector> VXNotebookConfigMgr::fetchExternalChildren continue; } + if (isExcludedFromExternalNode(folder)) { + continue; + } + if (p_node->containsContainerChild(folder)) { continue; } @@ -943,6 +963,10 @@ QVector> VXNotebookConfigMgr::fetchExternalChildren continue; } + if (isExcludedFromExternalNode(file)) { + continue; + } + if (p_node->containsContentChild(file)) { continue; } @@ -954,7 +978,12 @@ QVector> VXNotebookConfigMgr::fetchExternalChildren return externalNodes; } -void VXNotebookConfigMgr::reloadNode(Node *p_node) +bool VXNotebookConfigMgr::isExcludedFromExternalNode(const QString &p_name) const { - // TODO. + for (const auto ®Exp : s_externalNodeExcludePatterns) { + if (regExp.exactMatch(p_name)) { + return true; + } + } + return false; } diff --git a/src/core/notebookconfigmgr/vxnotebookconfigmgr.h b/src/core/notebookconfigmgr/vxnotebookconfigmgr.h index 5184dc07..a30a0fdd 100644 --- a/src/core/notebookconfigmgr/vxnotebookconfigmgr.h +++ b/src/core/notebookconfigmgr/vxnotebookconfigmgr.h @@ -5,6 +5,7 @@ #include #include +#include #include "../global.h" @@ -70,8 +71,6 @@ namespace vnotex QVector> fetchExternalChildren(Node *p_node) const Q_DECL_OVERRIDE; - void reloadNode(Node *p_node) Q_DECL_OVERRIDE; - private: // Config of a file child. struct NodeFileConfig @@ -190,8 +189,14 @@ namespace vnotex void inheritNodeFlags(const Node *p_node, Node *p_child) const; + bool isExcludedFromExternalNode(const QString &p_name) const; + Info m_info; + static bool s_initialized; + + static QVector s_externalNodeExcludePatterns; + // Name of the node's config file. static const QString c_nodeConfigName; diff --git a/src/data/core/vnotex.json b/src/data/core/vnotex.json index cbca4456..db9e78ac 100644 --- a/src/data/core/vnotex.json +++ b/src/data/core/vnotex.json @@ -27,7 +27,16 @@ "NewWorkspace" : "Ctrl+G, N", "Export" : "Ctrl+G, T" }, - "toolbar_icon_size" : 16 + "toolbar_icon_size" : 16, + "note_management" : { + "external_node" : { + "//comment" : "Wildcard patterns of files and folders to exclude as external files", + "exclude_patterns" : [ + ".gitignore", + ".git" + ] + } + } }, "editor" : { "core": { diff --git a/src/widgets/mainwindow.cpp b/src/widgets/mainwindow.cpp index 2834f102..15db3d19 100644 --- a/src/widgets/mainwindow.cpp +++ b/src/widgets/mainwindow.cpp @@ -102,6 +102,16 @@ void MainWindow::setupStatusBar() void MainWindow::setupTipsArea() { + connect(&VNoteX::getInst(), &VNoteX::tipsRequested, + this, &MainWindow::showTips); +} + +void MainWindow::createTipsArea() +{ + if (m_tipsLabel) { + return; + } + m_tipsLabel = new QLabel(this); m_tipsLabel->setObjectName("MainWindowTipsLabel"); m_tipsLabel->hide(); @@ -113,9 +123,6 @@ void MainWindow::setupTipsArea() this, [this]() { setTipsAreaVisible(false); }); - - connect(&VNoteX::getInst(), &VNoteX::tipsRequested, - this, &MainWindow::showTips); } void MainWindow::setupCentralWidget() @@ -623,6 +630,8 @@ void MainWindow::exportNotes() void MainWindow::showTips(const QString &p_message, int p_timeoutMilliseconds) { + createTipsArea(); + m_tipsTimer->stop(); setTipsAreaVisible(false); @@ -639,6 +648,7 @@ void MainWindow::showTips(const QString &p_message, int p_timeoutMilliseconds) void MainWindow::setTipsAreaVisible(bool p_visible) { + Q_ASSERT(m_tipsLabel); if (p_visible) { m_tipsLabel->adjustSize(); int labelW = m_tipsLabel->width(); diff --git a/src/widgets/mainwindow.h b/src/widgets/mainwindow.h index 7b6f472d..53887138 100644 --- a/src/widgets/mainwindow.h +++ b/src/widgets/mainwindow.h @@ -106,6 +106,8 @@ namespace vnotex void setupTipsArea(); + void createTipsArea(); + void saveStateAndGeometry(); void loadStateAndGeometry(); diff --git a/src/widgets/notebookexplorer.cpp b/src/widgets/notebookexplorer.cpp index 363b72aa..35622c0d 100644 --- a/src/widgets/notebookexplorer.cpp +++ b/src/widgets/notebookexplorer.cpp @@ -76,6 +76,8 @@ void NotebookExplorer::setupUI() &VNoteX::getInst(), &VNoteX::nodeAboutToMove); connect(m_nodeExplorer, &NotebookNodeExplorer::nodeAboutToRemove, &VNoteX::getInst(), &VNoteX::nodeAboutToRemove); + connect(m_nodeExplorer, &NotebookNodeExplorer::nodeAboutToReload, + &VNoteX::getInst(), &VNoteX::nodeAboutToReload); mainLayout->addWidget(m_nodeExplorer); setFocusProxy(m_nodeExplorer); diff --git a/src/widgets/notebooknodeexplorer.cpp b/src/widgets/notebooknodeexplorer.cpp index 8652e873..5aa59297 100644 --- a/src/widgets/notebooknodeexplorer.cpp +++ b/src/widgets/notebooknodeexplorer.cpp @@ -761,6 +761,9 @@ void NotebookNodeExplorer::createContextMenuOnRoot(QMenu *p_menu) act = createAction(Action::Reload, p_menu); p_menu->addAction(act); + act = createAction(Action::ReloadIndex, p_menu); + p_menu->addAction(act); + act = createAction(Action::OpenLocation, p_menu); p_menu->addAction(act); } @@ -775,6 +778,9 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_ act = createAction(Action::Reload, p_menu); p_menu->addAction(act); + act = createAction(Action::ReloadIndex, p_menu); + p_menu->addAction(act); + if (selectedSize == 1) { act = createAction(Action::EmptyRecycleBin, p_menu); p_menu->addAction(act); @@ -800,6 +806,9 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_ act = createAction(Action::Reload, p_menu); p_menu->addAction(act); + act = createAction(Action::ReloadIndex, p_menu); + p_menu->addAction(act); + if (selectedSize == 1) { p_menu->addSeparator(); @@ -845,6 +854,9 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_ act = createAction(Action::Reload, p_menu); p_menu->addAction(act); + act = createAction(Action::ReloadIndex, p_menu); + p_menu->addAction(act); + act = createAction(Action::Sort, p_menu); p_menu->addAction(act); @@ -1091,14 +1103,28 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent) connect(act, &QAction::triggered, this, [this]() { auto node = currentExploredFolderNode(); - if (m_notebook && node) { - // TODO: emit signals to notify other components. - m_notebook->reloadNode(node); - } updateNode(node); }); break; + case Action::ReloadIndex: + act = new QAction(tr("Re&load Index From Disk"), p_parent); + connect(act, &QAction::triggered, + this, [this]() { + if (!m_notebook) { + return; + } + + auto event = QSharedPointer::create(); + emit nodeAboutToReload(m_notebook->getRootNode().data(), event); + if (!event->m_response.toBool()) { + return; + } + + reload(); + }); + break; + case Action::ImportToConfig: act = new QAction(tr("&Import To Index"), p_parent); connect(act, &QAction::triggered, diff --git a/src/widgets/notebooknodeexplorer.h b/src/widgets/notebooknodeexplorer.h index 8167f9a4..b50762f5 100644 --- a/src/widgets/notebooknodeexplorer.h +++ b/src/widgets/notebooknodeexplorer.h @@ -123,6 +123,8 @@ namespace vnotex // @m_response of @p_event: true to continue the removal, false to cancel the removal. void nodeAboutToRemove(Node *p_node, const QSharedPointer &p_event); + void nodeAboutToReload(Node *p_node, const QSharedPointer &p_event); + private: enum Column { Name = 0 }; @@ -142,6 +144,7 @@ namespace vnotex RemoveFromConfig, Sort, Reload, + ReloadIndex, ImportToConfig, Open }; diff --git a/src/widgets/viewarea.cpp b/src/widgets/viewarea.cpp index 0f935c54..caf3758e 100644 --- a/src/widgets/viewarea.cpp +++ b/src/widgets/viewarea.cpp @@ -61,37 +61,16 @@ ViewArea::ViewArea(QWidget *p_parent) }); connect(&VNoteX::getInst(), &VNoteX::nodeAboutToMove, - this, [this](Node *p_node, const QSharedPointer &p_event) { - if (p_event->m_handled) { - return; - } - - bool ret = close(p_node, false); - p_event->m_response = ret; - p_event->m_handled = !ret; - }); + this, &ViewArea::handleNodeChange); connect(&VNoteX::getInst(), &VNoteX::nodeAboutToRemove, - this, [this](Node *p_node, const QSharedPointer &p_event) { - if (p_event->m_handled) { - return; - } - - bool ret = close(p_node, false); - p_event->m_response = ret; - p_event->m_handled = !ret; - }); + this, &ViewArea::handleNodeChange); connect(&VNoteX::getInst(), &VNoteX::nodeAboutToRename, - this, [this](Node *p_node, const QSharedPointer &p_event) { - if (p_event->m_handled) { - return; - } + this, &ViewArea::handleNodeChange); - bool ret = close(p_node, false); - p_event->m_response = ret; - p_event->m_handled = !ret; - }); + connect(&VNoteX::getInst(), &VNoteX::nodeAboutToReload, + this, &ViewArea::handleNodeChange); auto &configMgr = ConfigMgr::getInst(); connect(&configMgr, &ConfigMgr::editorConfigChanged, @@ -130,6 +109,17 @@ ViewArea::~ViewArea() Q_ASSERT(m_workspaces.isEmpty()); } +void ViewArea::handleNodeChange(Node *p_node, const QSharedPointer &p_event) +{ + if (p_event->m_handled) { + return; + } + + bool ret = close(p_node, false); + p_event->m_response = ret; + p_event->m_handled = !ret; +} + void ViewArea::setupUI() { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); diff --git a/src/widgets/viewarea.h b/src/widgets/viewarea.h index a546fa61..f6b6afc4 100644 --- a/src/widgets/viewarea.h +++ b/src/widgets/viewarea.h @@ -127,6 +127,8 @@ namespace vnotex bool close(bool p_force); + void handleNodeChange(Node *p_node, const QSharedPointer &p_event); + private: enum class SplitType {