mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
support external nodes (#1718)
This commit is contained in:
parent
aa00164dff
commit
9895207dd4
34
src/core/notebook/externalnode.cpp
Normal file
34
src/core/notebook/externalnode.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "externalnode.h"
|
||||
|
||||
#include "node.h"
|
||||
#include <utils/pathutils.h>
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
ExternalNode::ExternalNode(Node *p_parent, const QString &p_name, Type p_type)
|
||||
: m_parentNode(p_parent),
|
||||
m_name(p_name),
|
||||
m_type(p_type)
|
||||
{
|
||||
Q_ASSERT(m_parentNode);
|
||||
}
|
||||
|
||||
Node *ExternalNode::getNode() const
|
||||
{
|
||||
return m_parentNode;
|
||||
}
|
||||
|
||||
const QString &ExternalNode::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
bool ExternalNode::isFolder() const
|
||||
{
|
||||
return m_type == Type::Folder;
|
||||
}
|
||||
|
||||
QString ExternalNode::fetchAbsolutePath() const
|
||||
{
|
||||
return PathUtils::concatenateFilePath(m_parentNode->fetchAbsolutePath(), m_name);
|
||||
}
|
41
src/core/notebook/externalnode.h
Normal file
41
src/core/notebook/externalnode.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef EXTERNALNODE_H
|
||||
#define EXTERNALNODE_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace vnotex
|
||||
{
|
||||
class Node;
|
||||
|
||||
// External node not managed by VNote.
|
||||
class ExternalNode
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
File,
|
||||
Folder
|
||||
};
|
||||
|
||||
ExternalNode(Node *p_parent, const QString &p_name, Type p_type);
|
||||
|
||||
Node *getNode() const;
|
||||
|
||||
const QString &getName() const;
|
||||
|
||||
bool isFolder() const;
|
||||
|
||||
QString fetchAbsolutePath() const;
|
||||
|
||||
private:
|
||||
// Parent node.
|
||||
// We support only one level further the external folder.
|
||||
Node *m_parentNode = nullptr;
|
||||
|
||||
QString m_name;
|
||||
|
||||
Type m_type = Type::File;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // EXTERNALNODE_H
|
@ -103,13 +103,13 @@ bool Node::containsChild(const QString &p_name, bool p_caseSensitive) const
|
||||
|
||||
bool Node::containsChild(const QSharedPointer<Node> &p_node) const
|
||||
{
|
||||
return getChildren().indexOf(p_node) != -1;
|
||||
return m_children.indexOf(p_node) != -1;
|
||||
}
|
||||
|
||||
QSharedPointer<Node> Node::findChild(const QString &p_name, bool p_caseSensitive) const
|
||||
{
|
||||
auto targetName = p_caseSensitive ? p_name : p_name.toLower();
|
||||
for (auto &child : getChildren()) {
|
||||
for (const auto &child : m_children) {
|
||||
if (p_caseSensitive ? child->getName() == targetName
|
||||
: child->getName().toLower() == targetName) {
|
||||
return child;
|
||||
@ -164,7 +164,12 @@ void Node::setModifiedTimeUtc()
|
||||
m_modifiedTimeUtc = QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
|
||||
const QVector<QSharedPointer<Node>> &Node::getChildren() const
|
||||
const QVector<QSharedPointer<Node>> &Node::getChildrenRef() const
|
||||
{
|
||||
return m_children;
|
||||
}
|
||||
|
||||
QVector<QSharedPointer<Node>> Node::getChildren() const
|
||||
{
|
||||
return m_children;
|
||||
}
|
||||
@ -347,3 +352,54 @@ void Node::sortChildren(const QVector<int> &p_beforeIdx, const QVector<int> &p_a
|
||||
|
||||
save();
|
||||
}
|
||||
|
||||
QVector<QSharedPointer<ExternalNode>> Node::fetchExternalChildren() const
|
||||
{
|
||||
return getConfigMgr()->fetchExternalChildren(const_cast<Node *>(this));
|
||||
}
|
||||
|
||||
bool Node::containsContainerChild(const QString &p_name) const
|
||||
{
|
||||
// TODO: we assume that m_children is sorted first the container children.
|
||||
for (auto &child : m_children) {
|
||||
if (!child->isContainer()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (child->getName() == p_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Node::containsContentChild(const QString &p_name) const
|
||||
{
|
||||
// TODO: we assume that m_children is sorted: first the container children then content children.
|
||||
for (int i = m_children.size() - 1; i >= 0; --i) {
|
||||
if (m_children[i]->isContainer()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_children[i]->getName() == p_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Node::exists() const
|
||||
{
|
||||
return m_flags & Flag::Exists;
|
||||
}
|
||||
|
||||
void Node::setExists(bool p_exists)
|
||||
{
|
||||
if (p_exists) {
|
||||
m_flags |= Flag::Exists;
|
||||
} else {
|
||||
m_flags &= ~Flag::Exists;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ namespace vnotex
|
||||
class INotebookConfigMgr;
|
||||
class INotebookBackend;
|
||||
class File;
|
||||
class ExternalNode;
|
||||
|
||||
// Used when add/new a node.
|
||||
struct NodeParameters
|
||||
@ -35,7 +36,9 @@ namespace vnotex
|
||||
Content = 0x1,
|
||||
// A node with children.
|
||||
Container = 0x2,
|
||||
ReadOnly = 0x4
|
||||
ReadOnly = 0x4,
|
||||
// Whether a node exists on disk.
|
||||
Exists = 0x10
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
@ -86,6 +89,11 @@ namespace vnotex
|
||||
|
||||
bool hasContent() const;
|
||||
|
||||
// Whether the node exists on disk.
|
||||
bool exists() const;
|
||||
|
||||
void setExists(bool p_exists);
|
||||
|
||||
Node::Flags getFlags() const;
|
||||
|
||||
Node::Use getUse() const;
|
||||
@ -98,7 +106,8 @@ namespace vnotex
|
||||
const QDateTime &getModifiedTimeUtc() const;
|
||||
void setModifiedTimeUtc();
|
||||
|
||||
const QVector<QSharedPointer<Node>> &getChildren() const;
|
||||
const QVector<QSharedPointer<Node>> &getChildrenRef() const;
|
||||
QVector<QSharedPointer<Node>> getChildren() const;
|
||||
int getChildrenCount() const;
|
||||
|
||||
QSharedPointer<Node> findChild(const QString &p_name, bool p_caseSensitive = true) const;
|
||||
@ -107,12 +116,20 @@ namespace vnotex
|
||||
|
||||
bool containsChild(const QSharedPointer<Node> &p_node) const;
|
||||
|
||||
// Case sensitive.
|
||||
bool containsContainerChild(const QString &p_name) const;
|
||||
|
||||
// Case sensitive.
|
||||
bool containsContentChild(const QString &p_name) const;
|
||||
|
||||
void addChild(const QSharedPointer<Node> &p_node);
|
||||
|
||||
void insertChild(int p_idx, const QSharedPointer<Node> &p_node);
|
||||
|
||||
void removeChild(const QSharedPointer<Node> &p_node);
|
||||
|
||||
QVector<QSharedPointer<ExternalNode>> fetchExternalChildren() const;
|
||||
|
||||
void setParent(Node *p_parent);
|
||||
Node *getParent() const;
|
||||
|
||||
|
@ -161,7 +161,7 @@ const QSharedPointer<Node> &Notebook::getRootNode() const
|
||||
QSharedPointer<Node> Notebook::getRecycleBinNode() const
|
||||
{
|
||||
auto root = getRootNode();
|
||||
auto children = root->getChildren();
|
||||
const auto &children = root->getChildrenRef();
|
||||
auto it = std::find_if(children.begin(),
|
||||
children.end(),
|
||||
[this](const QSharedPointer<Node> &p_node) {
|
||||
@ -203,7 +203,7 @@ QSharedPointer<Node> Notebook::loadNodeByPath(const QString &p_path)
|
||||
relativePath = p_path;
|
||||
}
|
||||
|
||||
return m_configMgr->loadNodeByPath(m_root, relativePath);
|
||||
return m_configMgr->loadNodeByPath(getRootNode(), relativePath);
|
||||
}
|
||||
|
||||
QSharedPointer<Node> Notebook::copyNodeAsChildOf(const QSharedPointer<Node> &p_src, Node *p_dest, bool p_move)
|
||||
@ -227,17 +227,15 @@ QSharedPointer<Node> Notebook::copyNodeAsChildOf(const QSharedPointer<Node> &p_s
|
||||
|
||||
void Notebook::removeNode(const QSharedPointer<Node> &p_node, bool p_force, bool p_configOnly)
|
||||
{
|
||||
Q_ASSERT(p_node && !p_node->isRoot());
|
||||
Q_ASSERT(p_node->getNotebook() == this);
|
||||
m_configMgr->removeNode(p_node, p_force, p_configOnly);
|
||||
}
|
||||
|
||||
void Notebook::removeNode(const Node *p_node, bool p_force, bool p_configOnly)
|
||||
void Notebook::removeNode(Node *p_node, bool p_force, bool p_configOnly)
|
||||
{
|
||||
Q_ASSERT(p_node && !p_node->isRoot());
|
||||
auto children = p_node->getParent()->getChildren();
|
||||
auto it = std::find(children.begin(), children.end(), p_node);
|
||||
Q_ASSERT(it != children.end());
|
||||
removeNode(*it, p_force, p_configOnly);
|
||||
Q_ASSERT(p_node);
|
||||
removeNode(p_node->sharedFromThis(), p_force, p_configOnly);
|
||||
}
|
||||
|
||||
bool Notebook::isRecycleBinNode(const Node *p_node) const
|
||||
@ -261,22 +259,14 @@ bool Notebook::isNodeInRecycleBin(const Node *p_node) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Notebook::moveNodeToRecycleBin(const Node *p_node)
|
||||
void Notebook::moveNodeToRecycleBin(Node *p_node)
|
||||
{
|
||||
Q_ASSERT(p_node && !p_node->isRoot());
|
||||
auto children = p_node->getParent()->getChildren();
|
||||
for (auto &child : children) {
|
||||
if (p_node == child) {
|
||||
moveNodeToRecycleBin(child);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Q_ASSERT(false);
|
||||
moveNodeToRecycleBin(p_node->sharedFromThis());
|
||||
}
|
||||
|
||||
void Notebook::moveNodeToRecycleBin(const QSharedPointer<Node> &p_node)
|
||||
{
|
||||
Q_ASSERT(p_node && !p_node->isRoot());
|
||||
auto destNode = getOrCreateRecycleBinDateNode();
|
||||
copyNodeAsChildOf(p_node, destNode.data(), true);
|
||||
}
|
||||
@ -299,8 +289,9 @@ QSharedPointer<Node> Notebook::getOrCreateRecycleBinDateNode()
|
||||
|
||||
void Notebook::emptyNode(const Node *p_node, bool p_force)
|
||||
{
|
||||
// Copy the children.
|
||||
auto children = p_node->getChildren();
|
||||
for (auto &child : children) {
|
||||
for (const auto &child : children) {
|
||||
removeNode(child, p_force);
|
||||
}
|
||||
}
|
||||
@ -355,3 +346,8 @@ QSharedPointer<Node> Notebook::copyAsNode(Node *p_parent,
|
||||
{
|
||||
return m_configMgr->copyAsNode(p_parent, p_flags, p_path);
|
||||
}
|
||||
|
||||
void Notebook::reloadNode(Node *p_node)
|
||||
{
|
||||
m_configMgr->reloadNode(p_node);
|
||||
}
|
||||
|
@ -99,11 +99,11 @@ namespace vnotex
|
||||
// @p_configOnly: if true, will just remove node from config.
|
||||
void removeNode(const QSharedPointer<Node> &p_node, bool p_force = false, bool p_configOnly = false);
|
||||
|
||||
void removeNode(const Node *p_node, bool p_force = false, bool p_configOnly = false);
|
||||
void removeNode(Node *p_node, bool p_force = false, bool p_configOnly = false);
|
||||
|
||||
void moveNodeToRecycleBin(const QSharedPointer<Node> &p_node);
|
||||
|
||||
void moveNodeToRecycleBin(const Node *p_node);
|
||||
void moveNodeToRecycleBin(Node *p_node);
|
||||
|
||||
// Move @p_filePath to the recycle bin, without adding it as a child node.
|
||||
void moveFileToRecycleBin(const QString &p_filePath);
|
||||
@ -127,6 +127,8 @@ namespace vnotex
|
||||
|
||||
bool isBuiltInFolder(const Node *p_node, const QString &p_name) const;
|
||||
|
||||
void reloadNode(Node *p_node);
|
||||
|
||||
static const QString c_defaultAttachmentFolder;
|
||||
|
||||
static const QString c_defaultImageFolder;
|
||||
|
@ -1,4 +1,5 @@
|
||||
SOURCES += \
|
||||
$$PWD/externalnode.cpp \
|
||||
$$PWD/notebook.cpp \
|
||||
$$PWD/bundlenotebookfactory.cpp \
|
||||
$$PWD/notebookparameters.cpp \
|
||||
@ -8,6 +9,7 @@ SOURCES += \
|
||||
$$PWD/vxnodefile.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/externalnode.h \
|
||||
$$PWD/notebook.h \
|
||||
$$PWD/inotebookfactory.h \
|
||||
$$PWD/bundlenotebookfactory.h \
|
||||
|
@ -67,6 +67,10 @@ namespace vnotex
|
||||
|
||||
virtual bool exists(const QString &p_path) const = 0;
|
||||
|
||||
virtual bool existsFile(const QString &p_path) const = 0;
|
||||
|
||||
virtual bool existsDir(const QString &p_path) const = 0;
|
||||
|
||||
virtual bool childExistsCaseInsensitive(const QString &p_dirPath, const QString &p_name) const = 0;
|
||||
|
||||
virtual bool isFile(const QString &p_path) const = 0;
|
||||
|
@ -86,6 +86,18 @@ bool LocalNotebookBackend::exists(const QString &p_path) const
|
||||
return QFileInfo::exists(getFullPath(p_path));
|
||||
}
|
||||
|
||||
bool LocalNotebookBackend::existsFile(const QString &p_path) const
|
||||
{
|
||||
QFileInfo fi(getFullPath(p_path));
|
||||
return fi.exists() && fi.isFile();
|
||||
}
|
||||
|
||||
bool LocalNotebookBackend::existsDir(const QString &p_path) const
|
||||
{
|
||||
QFileInfo fi(getFullPath(p_path));
|
||||
return fi.exists() && fi.isDir();
|
||||
}
|
||||
|
||||
bool LocalNotebookBackend::childExistsCaseInsensitive(const QString &p_dirPath, const QString &p_name) const
|
||||
{
|
||||
return FileUtils::childExistsCaseInsensitive(getFullPath(p_dirPath), p_name);
|
||||
|
@ -47,6 +47,10 @@ namespace vnotex
|
||||
|
||||
bool exists(const QString &p_path) const Q_DECL_OVERRIDE;
|
||||
|
||||
bool existsFile(const QString &p_path) const Q_DECL_OVERRIDE;
|
||||
|
||||
bool existsDir(const QString &p_path) const Q_DECL_OVERRIDE;
|
||||
|
||||
bool childExistsCaseInsensitive(const QString &p_dirPath, const QString &p_name) const Q_DECL_OVERRIDE;
|
||||
|
||||
bool isFile(const QString &p_path) const Q_DECL_OVERRIDE;
|
||||
|
@ -36,7 +36,7 @@ namespace vnotex
|
||||
|
||||
const QSharedPointer<INotebookBackend> &getBackend() const;
|
||||
|
||||
virtual QSharedPointer<Node> loadRootNode() const = 0;
|
||||
virtual QSharedPointer<Node> loadRootNode() = 0;
|
||||
|
||||
virtual void loadNode(Node *p_node) const = 0;
|
||||
virtual void saveNode(const Node *p_node) = 0;
|
||||
@ -75,6 +75,10 @@ namespace vnotex
|
||||
|
||||
virtual QString fetchNodeAttachmentFolderPath(Node *p_node) = 0;
|
||||
|
||||
virtual QVector<QSharedPointer<ExternalNode>> fetchExternalChildren(Node *p_node) const = 0;
|
||||
|
||||
virtual void reloadNode(Node *p_node) = 0;
|
||||
|
||||
protected:
|
||||
// Version of the config processing code.
|
||||
virtual QString getCodeVersion() const;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <notebookbackend/inotebookbackend.h>
|
||||
#include <notebook/notebookparameters.h>
|
||||
#include <notebook/vxnode.h>
|
||||
#include <notebook/externalnode.h>
|
||||
#include <notebook/bundlenotebook.h>
|
||||
#include <utils/utils.h>
|
||||
#include <utils/fileutils.h>
|
||||
@ -205,11 +206,12 @@ void VXNotebookConfigMgr::createEmptyRootNode()
|
||||
writeNodeConfig(c_nodeConfigName, node);
|
||||
}
|
||||
|
||||
QSharedPointer<Node> VXNotebookConfigMgr::loadRootNode() const
|
||||
QSharedPointer<Node> VXNotebookConfigMgr::loadRootNode()
|
||||
{
|
||||
auto nodeConfig = readNodeConfig("");
|
||||
QSharedPointer<Node> root = nodeConfigToNode(*nodeConfig, "", nullptr);
|
||||
root->setUse(Node::Use::Root);
|
||||
root->setExists(true);
|
||||
Q_ASSERT(root->isLoaded());
|
||||
|
||||
if (!markRecycleBinNode(root)) {
|
||||
@ -219,11 +221,16 @@ QSharedPointer<Node> VXNotebookConfigMgr::loadRootNode() const
|
||||
return root;
|
||||
}
|
||||
|
||||
bool VXNotebookConfigMgr::markRecycleBinNode(const QSharedPointer<Node> &p_root) const
|
||||
bool VXNotebookConfigMgr::markRecycleBinNode(const QSharedPointer<Node> &p_root)
|
||||
{
|
||||
auto node = p_root->findChild(c_recycleBinFolderName,
|
||||
FileUtils::isPlatformNameCaseSensitive());
|
||||
if (node) {
|
||||
if (!node->exists()) {
|
||||
removeNode(node, true, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
node->setUse(Node::Use::RecycleBin);
|
||||
markNodeReadOnly(node.data());
|
||||
return true;
|
||||
@ -239,7 +246,7 @@ void VXNotebookConfigMgr::markNodeReadOnly(Node *p_node) const
|
||||
}
|
||||
|
||||
p_node->setReadOnly(true);
|
||||
for (auto &child : p_node->getChildren()) {
|
||||
for (const auto &child : p_node->getChildrenRef()) {
|
||||
markNodeReadOnly(child.data());
|
||||
}
|
||||
}
|
||||
@ -305,16 +312,30 @@ void VXNotebookConfigMgr::loadFolderNode(Node *p_node, const NodeConfig &p_confi
|
||||
{
|
||||
QVector<QSharedPointer<Node>> children;
|
||||
children.reserve(p_config.m_files.size() + p_config.m_folders.size());
|
||||
const auto basePath = p_node->fetchPath();
|
||||
|
||||
for (const auto &folder : p_config.m_folders) {
|
||||
if (folder.m_name.isEmpty()) {
|
||||
// Skip empty name node.
|
||||
qWarning() << "skipped loading node with empty name under" << p_node->fetchPath();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto folderNode = QSharedPointer<VXNode>::create(folder.m_name,
|
||||
getNotebook(),
|
||||
p_node);
|
||||
inheritNodeFlags(p_node, folderNode.data());
|
||||
folderNode->setExists(getBackend()->existsDir(PathUtils::concatenateFilePath(basePath, folder.m_name)));
|
||||
children.push_back(folderNode);
|
||||
}
|
||||
|
||||
for (const auto &file : p_config.m_files) {
|
||||
if (file.m_name.isEmpty()) {
|
||||
// Skip empty name node.
|
||||
qWarning() << "skipped loading node with empty name under" << p_node->fetchPath();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fileNode = QSharedPointer<VXNode>::create(file.m_id,
|
||||
file.m_name,
|
||||
file.m_createdTimeUtc,
|
||||
@ -324,6 +345,7 @@ void VXNotebookConfigMgr::loadFolderNode(Node *p_node, const NodeConfig &p_confi
|
||||
getNotebook(),
|
||||
p_node);
|
||||
inheritNodeFlags(p_node, fileNode.data());
|
||||
fileNode->setExists(getBackend()->existsFile(PathUtils::concatenateFilePath(basePath, file.m_name)));
|
||||
children.push_back(fileNode);
|
||||
}
|
||||
|
||||
@ -338,7 +360,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::newNode(Node *p_parent,
|
||||
Node::Flags p_flags,
|
||||
const QString &p_name)
|
||||
{
|
||||
Q_ASSERT(p_parent && p_parent->isContainer());
|
||||
Q_ASSERT(p_parent && p_parent->isContainer() && !p_name.isEmpty());
|
||||
|
||||
QSharedPointer<Node> node;
|
||||
|
||||
@ -359,6 +381,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::addAsNode(Node *p_parent,
|
||||
{
|
||||
Q_ASSERT(p_parent && p_parent->isContainer());
|
||||
|
||||
// TODO: reuse the config if available.
|
||||
QSharedPointer<Node> node;
|
||||
if (p_flags & Node::Flag::Content) {
|
||||
Q_ASSERT(!(p_flags & Node::Flag::Container));
|
||||
@ -407,6 +430,9 @@ QSharedPointer<Node> VXNotebookConfigMgr::newFileNode(Node *p_parent,
|
||||
// Write empty file.
|
||||
if (p_create) {
|
||||
getBackend()->writeFile(node->fetchPath(), QString());
|
||||
node->setExists(true);
|
||||
} else {
|
||||
node->setExists(getBackend()->existsFile(node->fetchPath()));
|
||||
}
|
||||
|
||||
addChildNode(p_parent, node);
|
||||
@ -433,6 +459,9 @@ QSharedPointer<Node> VXNotebookConfigMgr::newFolderNode(Node *p_parent,
|
||||
// Make folder.
|
||||
if (p_create) {
|
||||
getBackend()->makePath(node->fetchPath());
|
||||
node->setExists(true);
|
||||
} else {
|
||||
node->setExists(getBackend()->existsDir(node->fetchPath()));
|
||||
}
|
||||
|
||||
writeNodeConfig(node.data());
|
||||
@ -452,7 +481,7 @@ QSharedPointer<VXNotebookConfigMgr::NodeConfig> VXNotebookConfigMgr::nodeToNodeC
|
||||
p_node->getCreatedTimeUtc(),
|
||||
p_node->getModifiedTimeUtc());
|
||||
|
||||
for (const auto &child : p_node->getChildren()) {
|
||||
for (const auto &child : p_node->getChildrenRef()) {
|
||||
if (child->hasContent()) {
|
||||
NodeFileConfig fileConfig;
|
||||
fileConfig.m_name = child->getName();
|
||||
@ -477,7 +506,7 @@ QSharedPointer<VXNotebookConfigMgr::NodeConfig> VXNotebookConfigMgr::nodeToNodeC
|
||||
|
||||
void VXNotebookConfigMgr::loadNode(Node *p_node) const
|
||||
{
|
||||
if (p_node->isLoaded()) {
|
||||
if (p_node->isLoaded() || !p_node->exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -513,7 +542,7 @@ void VXNotebookConfigMgr::addChildNode(Node *p_parent, const QSharedPointer<Node
|
||||
{
|
||||
if (p_child->isContainer()) {
|
||||
int idx = 0;
|
||||
auto children = p_parent->getChildren();
|
||||
const auto &children = p_parent->getChildrenRef();
|
||||
for (; idx < children.size(); ++idx) {
|
||||
if (!children[idx]->isContainer()) {
|
||||
break;
|
||||
@ -558,6 +587,13 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyNodeAsChildOf(const QSharedPointer
|
||||
{
|
||||
Q_ASSERT(p_dest->isContainer());
|
||||
|
||||
if (!p_src->exists()) {
|
||||
if (p_move) {
|
||||
p_src->getNotebook()->removeNode(p_src);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QSharedPointer<Node> node;
|
||||
if (p_src->isContainer()) {
|
||||
node = copyFolderNodeAsChildOf(p_src, p_dest, p_move);
|
||||
@ -605,6 +641,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyFileNodeAsChildOf(const QSharedPoi
|
||||
attachmentFolder,
|
||||
notebook,
|
||||
p_dest);
|
||||
destNode->setExists(true);
|
||||
addChildNode(p_dest, destNode);
|
||||
writeNodeConfig(p_dest);
|
||||
|
||||
@ -643,6 +680,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyFolderNodeAsChildOf(const QSharedP
|
||||
p_src->getModifiedTimeUtc(),
|
||||
QStringList(),
|
||||
QVector<QSharedPointer<Node>>());
|
||||
destNode->setExists(true);
|
||||
|
||||
writeNodeConfig(destNode.data());
|
||||
|
||||
@ -650,7 +688,8 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyFolderNodeAsChildOf(const QSharedP
|
||||
writeNodeConfig(p_dest);
|
||||
|
||||
// Copy children node.
|
||||
for (const auto &childNode : p_src->getChildren()) {
|
||||
auto children = p_src->getChildren();
|
||||
for (const auto &childNode : children) {
|
||||
copyNodeAsChildOf(childNode, destNode.data(), p_move);
|
||||
}
|
||||
|
||||
@ -664,13 +703,18 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyFolderNodeAsChildOf(const QSharedP
|
||||
void VXNotebookConfigMgr::removeNode(const QSharedPointer<Node> &p_node, bool p_force, bool p_configOnly)
|
||||
{
|
||||
auto parentNode = p_node->getParent();
|
||||
if (!p_configOnly) {
|
||||
if (!p_configOnly && p_node->exists()) {
|
||||
// Remove all children.
|
||||
for (auto &childNode : p_node->getChildren()) {
|
||||
auto children = p_node->getChildren();
|
||||
for (const auto &childNode : children) {
|
||||
removeNode(childNode, p_force, p_configOnly);
|
||||
}
|
||||
|
||||
removeFilesOfNode(p_node.data(), p_force);
|
||||
try {
|
||||
removeFilesOfNode(p_node.data(), p_force);
|
||||
} catch (Exception &p_e) {
|
||||
qWarning() << "failed to remove files of node" << p_node->fetchPath() << p_e.what();
|
||||
}
|
||||
}
|
||||
|
||||
if (parentNode) {
|
||||
@ -771,7 +815,9 @@ bool VXNotebookConfigMgr::isBuiltInFolder(const Node *p_node, const QString &p_n
|
||||
const auto name = p_name.toLower();
|
||||
if (name == c_recycleBinFolderName
|
||||
|| name == getNotebook()->getImageFolder().toLower()
|
||||
|| name == getNotebook()->getAttachmentFolder().toLower()) {
|
||||
|| name == getNotebook()->getAttachmentFolder().toLower()
|
||||
|| name == QStringLiteral("_v_images")
|
||||
|| name == QStringLiteral("_v_attachments")) {
|
||||
return true;
|
||||
}
|
||||
return BundleNotebookConfigMgr::isBuiltInFolder(p_node, p_name);
|
||||
@ -779,25 +825,36 @@ bool VXNotebookConfigMgr::isBuiltInFolder(const Node *p_node, const QString &p_n
|
||||
|
||||
QSharedPointer<Node> VXNotebookConfigMgr::copyFileAsChildOf(const QString &p_srcPath, Node *p_dest)
|
||||
{
|
||||
// Copy source file itself.
|
||||
auto destFilePath = PathUtils::concatenateFilePath(p_dest->fetchPath(),
|
||||
// Skip copy if it already locates in dest folder.
|
||||
auto destFilePath = PathUtils::concatenateFilePath(p_dest->fetchAbsolutePath(),
|
||||
PathUtils::fileName(p_srcPath));
|
||||
destFilePath = getBackend()->renameIfExistsCaseInsensitive(destFilePath);
|
||||
getBackend()->copyFile(p_srcPath, destFilePath);
|
||||
if (!PathUtils::areSamePaths(p_srcPath, destFilePath)) {
|
||||
// Copy source file itself.
|
||||
destFilePath = getBackend()->renameIfExistsCaseInsensitive(destFilePath);
|
||||
getBackend()->copyFile(p_srcPath, destFilePath);
|
||||
|
||||
// Copy media files fetched from content.
|
||||
ContentMediaUtils::copyMediaFiles(p_srcPath, getBackend().data(), destFilePath);
|
||||
// Copy media files fetched from content.
|
||||
ContentMediaUtils::copyMediaFiles(p_srcPath, getBackend().data(), destFilePath);
|
||||
}
|
||||
|
||||
const auto name = PathUtils::fileName(destFilePath);
|
||||
auto destNode = p_dest->findChild(name, true);
|
||||
if (destNode) {
|
||||
// Already have the node.
|
||||
return destNode;
|
||||
}
|
||||
|
||||
// Create a file node.
|
||||
auto currentTime = QDateTime::currentDateTimeUtc();
|
||||
auto destNode = QSharedPointer<VXNode>::create(getNotebook()->getAndUpdateNextNodeId(),
|
||||
PathUtils::fileName(destFilePath),
|
||||
currentTime,
|
||||
currentTime,
|
||||
QStringList(),
|
||||
QString(),
|
||||
getNotebook(),
|
||||
p_dest);
|
||||
destNode = QSharedPointer<VXNode>::create(getNotebook()->getAndUpdateNextNodeId(),
|
||||
name,
|
||||
currentTime,
|
||||
currentTime,
|
||||
QStringList(),
|
||||
QString(),
|
||||
getNotebook(),
|
||||
p_dest);
|
||||
destNode->setExists(true);
|
||||
addChildNode(p_dest, destNode);
|
||||
writeNodeConfig(p_dest);
|
||||
|
||||
@ -806,24 +863,33 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyFileAsChildOf(const QString &p_src
|
||||
|
||||
QSharedPointer<Node> VXNotebookConfigMgr::copyFolderAsChildOf(const QString &p_srcPath, Node *p_dest)
|
||||
{
|
||||
auto destFolderPath = PathUtils::concatenateFilePath(p_dest->fetchPath(),
|
||||
// Skip copy if it already locates in dest folder.
|
||||
auto destFolderPath = PathUtils::concatenateFilePath(p_dest->fetchAbsolutePath(),
|
||||
PathUtils::fileName(p_srcPath));
|
||||
destFolderPath = getBackend()->renameIfExistsCaseInsensitive(destFolderPath);
|
||||
if (!PathUtils::areSamePaths(p_srcPath, destFolderPath)) {
|
||||
destFolderPath = getBackend()->renameIfExistsCaseInsensitive(destFolderPath);
|
||||
|
||||
// Copy folder.
|
||||
getBackend()->copyDir(p_srcPath, destFolderPath);
|
||||
// Copy folder.
|
||||
getBackend()->copyDir(p_srcPath, destFolderPath);
|
||||
}
|
||||
|
||||
const auto name = PathUtils::fileName(destFolderPath);
|
||||
auto destNode = p_dest->findChild(name, true);
|
||||
if (destNode) {
|
||||
// Already have the node.
|
||||
return destNode;
|
||||
}
|
||||
|
||||
// Create a folder node.
|
||||
auto notebook = getNotebook();
|
||||
auto destNode = QSharedPointer<VXNode>::create(PathUtils::fileName(destFolderPath),
|
||||
notebook,
|
||||
p_dest);
|
||||
destNode = QSharedPointer<VXNode>::create(name, notebook, p_dest);
|
||||
auto currentTime = QDateTime::currentDateTimeUtc();
|
||||
destNode->loadCompleteInfo(notebook->getAndUpdateNextNodeId(),
|
||||
currentTime,
|
||||
currentTime,
|
||||
QStringList(),
|
||||
QVector<QSharedPointer<Node>>());
|
||||
destNode->setExists(true);
|
||||
|
||||
writeNodeConfig(destNode.data());
|
||||
|
||||
@ -839,3 +905,50 @@ void VXNotebookConfigMgr::inheritNodeFlags(const Node *p_node, Node *p_child) co
|
||||
markNodeReadOnly(p_child);
|
||||
}
|
||||
}
|
||||
|
||||
QVector<QSharedPointer<ExternalNode>> VXNotebookConfigMgr::fetchExternalChildren(Node *p_node) const
|
||||
{
|
||||
Q_ASSERT(p_node->isContainer());
|
||||
QVector<QSharedPointer<ExternalNode>> externalNodes;
|
||||
|
||||
auto dir = p_node->toDir();
|
||||
|
||||
// Folders.
|
||||
{
|
||||
const auto folders = dir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot);
|
||||
for (const auto &folder : folders) {
|
||||
if (isBuiltInFolder(p_node, folder)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_node->containsContainerChild(folder)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
externalNodes.push_back(QSharedPointer<ExternalNode>::create(p_node, folder, ExternalNode::Type::Folder));
|
||||
}
|
||||
}
|
||||
|
||||
// Files.
|
||||
{
|
||||
const auto files = dir.entryList(QDir::Files);
|
||||
for (const auto &file : files) {
|
||||
if (isBuiltInFile(p_node, file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_node->containsContentChild(file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
externalNodes.push_back(QSharedPointer<ExternalNode>::create(p_node, file, ExternalNode::Type::File));
|
||||
}
|
||||
}
|
||||
|
||||
return externalNodes;
|
||||
}
|
||||
|
||||
void VXNotebookConfigMgr::reloadNode(Node *p_node)
|
||||
{
|
||||
// TODO.
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ namespace vnotex
|
||||
|
||||
void createEmptySkeleton(const NotebookParameters &p_paras) Q_DECL_OVERRIDE;
|
||||
|
||||
QSharedPointer<Node> loadRootNode() const Q_DECL_OVERRIDE;
|
||||
QSharedPointer<Node> loadRootNode() Q_DECL_OVERRIDE;
|
||||
|
||||
void loadNode(Node *p_node) const Q_DECL_OVERRIDE;
|
||||
void saveNode(const Node *p_node) Q_DECL_OVERRIDE;
|
||||
@ -68,6 +68,10 @@ namespace vnotex
|
||||
|
||||
QString fetchNodeAttachmentFolderPath(Node *p_node) Q_DECL_OVERRIDE;
|
||||
|
||||
QVector<QSharedPointer<ExternalNode>> fetchExternalChildren(Node *p_node) const Q_DECL_OVERRIDE;
|
||||
|
||||
void reloadNode(Node *p_node) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Config of a file child.
|
||||
struct NodeFileConfig
|
||||
@ -173,7 +177,7 @@ namespace vnotex
|
||||
|
||||
void removeFilesOfNode(Node *p_node, bool p_force);
|
||||
|
||||
bool markRecycleBinNode(const QSharedPointer<Node> &p_root) const;
|
||||
bool markRecycleBinNode(const QSharedPointer<Node> &p_root);
|
||||
|
||||
void markNodeReadOnly(Node *p_node) const;
|
||||
|
||||
|
@ -91,6 +91,9 @@ namespace vnotex
|
||||
// @m_response of @p_event: true to continue the rename, false to cancel the rename.
|
||||
void nodeAboutToRename(Node *p_node, const QSharedPointer<Event> &p_event);
|
||||
|
||||
// @m_response of @p_event: true to continue the reload, false to cancel the reload.
|
||||
void nodeAboutToReload(Node *p_node, const QSharedPointer<Event> &p_event);
|
||||
|
||||
// Requested to open @p_filePath.
|
||||
void openFileRequested(const QString &p_filePath, const QSharedPointer<FileOpenParameters> &p_paras);
|
||||
|
||||
|
@ -24,8 +24,10 @@ void WidgetConfig::init(const QJsonObject &p_app,
|
||||
|
||||
m_findAndReplaceOptions = static_cast<FindOptions>(READINT(QStringLiteral("find_and_replace_options")));
|
||||
|
||||
m_noteExplorerViewOrder = READINT(QStringLiteral("note_explorer_view_order"));
|
||||
m_noteExplorerRecycleBinNodeShown = READBOOL(QStringLiteral("note_explorer_recycle_bin_node_shown"));
|
||||
m_nodeExplorerViewOrder = READINT(QStringLiteral("node_explorer_view_order"));
|
||||
m_nodeExplorerRecycleBinNodeVisible = READBOOL(QStringLiteral("node_explorer_recycle_bin_node_visible"));
|
||||
m_nodeExplorerExternalFilesVisible = READBOOL(QStringLiteral("node_explorer_external_files_visible"));
|
||||
m_nodeExplorerAutoImportExternalFilesEnabled = READBOOL(QStringLiteral("node_explorer_auto_import_external_files_enabled"));
|
||||
}
|
||||
|
||||
QJsonObject WidgetConfig::toJson() const
|
||||
@ -33,8 +35,10 @@ QJsonObject WidgetConfig::toJson() const
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("outline_auto_expanded_level")] = m_outlineAutoExpandedLevel;
|
||||
obj[QStringLiteral("find_and_replace_options")] = static_cast<int>(m_findAndReplaceOptions);
|
||||
obj[QStringLiteral("note_explorer_view_order")] = m_noteExplorerViewOrder;
|
||||
obj[QStringLiteral("note_explorer_recycle_bin_node_shown")] = m_noteExplorerRecycleBinNodeShown;
|
||||
obj[QStringLiteral("node_explorer_view_order")] = m_nodeExplorerViewOrder;
|
||||
obj[QStringLiteral("node_explorer_recycle_bin_node_visible")] = m_nodeExplorerRecycleBinNodeVisible;
|
||||
obj[QStringLiteral("node_explorer_external_files_visible")] = m_nodeExplorerExternalFilesVisible;
|
||||
obj[QStringLiteral("node_explorer_auto_import_external_files_enabled")] = m_nodeExplorerAutoImportExternalFilesEnabled;
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -58,22 +62,42 @@ void WidgetConfig::setFindAndReplaceOptions(FindOptions p_options)
|
||||
updateConfig(m_findAndReplaceOptions, p_options, this);
|
||||
}
|
||||
|
||||
int WidgetConfig::getNoteExplorerViewOrder() const
|
||||
int WidgetConfig::getNodeExplorerViewOrder() const
|
||||
{
|
||||
return m_noteExplorerViewOrder;
|
||||
return m_nodeExplorerViewOrder;
|
||||
}
|
||||
|
||||
void WidgetConfig::setNoteExplorerViewOrder(int p_viewOrder)
|
||||
void WidgetConfig::setNodeExplorerViewOrder(int p_viewOrder)
|
||||
{
|
||||
updateConfig(m_noteExplorerViewOrder, p_viewOrder, this);
|
||||
updateConfig(m_nodeExplorerViewOrder, p_viewOrder, this);
|
||||
}
|
||||
|
||||
bool WidgetConfig::isNoteExplorerRecycleBinNodeShown() const
|
||||
bool WidgetConfig::isNodeExplorerRecycleBinNodeVisible() const
|
||||
{
|
||||
return m_noteExplorerRecycleBinNodeShown;
|
||||
return m_nodeExplorerRecycleBinNodeVisible;
|
||||
}
|
||||
|
||||
void WidgetConfig::setNoteExplorerRecycleBinNodeShown(bool p_shown)
|
||||
void WidgetConfig::setNodeExplorerRecycleBinNodeVisible(bool p_visible)
|
||||
{
|
||||
updateConfig(m_noteExplorerRecycleBinNodeShown, p_shown, this);
|
||||
updateConfig(m_nodeExplorerRecycleBinNodeVisible, p_visible, this);
|
||||
}
|
||||
|
||||
bool WidgetConfig::isNodeExplorerExternalFilesVisible() const
|
||||
{
|
||||
return m_nodeExplorerExternalFilesVisible;
|
||||
}
|
||||
|
||||
void WidgetConfig::setNodeExplorerExternalFilesVisible(bool p_visible)
|
||||
{
|
||||
updateConfig(m_nodeExplorerExternalFilesVisible, p_visible, this);
|
||||
}
|
||||
|
||||
bool WidgetConfig::getNodeExplorerAutoImportExternalFilesEnabled() const
|
||||
{
|
||||
return m_nodeExplorerAutoImportExternalFilesEnabled;
|
||||
}
|
||||
|
||||
void WidgetConfig::setNodeExplorerAutoImportExternalFilesEnabled(bool p_enabled)
|
||||
{
|
||||
updateConfig(m_nodeExplorerAutoImportExternalFilesEnabled, p_enabled, this);
|
||||
}
|
||||
|
@ -24,20 +24,30 @@ namespace vnotex
|
||||
FindOptions getFindAndReplaceOptions() const;
|
||||
void setFindAndReplaceOptions(FindOptions p_options);
|
||||
|
||||
int getNoteExplorerViewOrder() const;
|
||||
void setNoteExplorerViewOrder(int p_viewOrder);
|
||||
int getNodeExplorerViewOrder() const;
|
||||
void setNodeExplorerViewOrder(int p_viewOrder);
|
||||
|
||||
bool isNoteExplorerRecycleBinNodeShown() const;
|
||||
void setNoteExplorerRecycleBinNodeShown(bool p_shown);
|
||||
bool isNodeExplorerRecycleBinNodeVisible() const;
|
||||
void setNodeExplorerRecycleBinNodeVisible(bool p_visible);
|
||||
|
||||
bool isNodeExplorerExternalFilesVisible() const;
|
||||
void setNodeExplorerExternalFilesVisible(bool p_visible);
|
||||
|
||||
bool getNodeExplorerAutoImportExternalFilesEnabled() const;
|
||||
void setNodeExplorerAutoImportExternalFilesEnabled(bool p_enabled);
|
||||
|
||||
private:
|
||||
int m_outlineAutoExpandedLevel = 6;
|
||||
|
||||
FindOptions m_findAndReplaceOptions = FindOption::None;
|
||||
|
||||
int m_noteExplorerViewOrder = 0;
|
||||
int m_nodeExplorerViewOrder = 0;
|
||||
|
||||
bool m_noteExplorerRecycleBinNodeShown = false;
|
||||
bool m_nodeExplorerRecycleBinNodeVisible = false;
|
||||
|
||||
bool m_nodeExplorerExternalFilesVisible = true;
|
||||
|
||||
bool m_nodeExplorerAutoImportExternalFilesEnabled = true;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -286,8 +286,10 @@
|
||||
"outline_auto_expanded_level" : 6,
|
||||
"//comment" : "Default find options in FindAndReplace",
|
||||
"find_and_replace_options" : 16,
|
||||
"//comment" : "View order of the note explorer",
|
||||
"note_explorer_view_order" : 0,
|
||||
"note_explorer_recycle_bin_node_shown" : false
|
||||
"//comment" : "View order of the node explorer",
|
||||
"node_explorer_view_order" : 0,
|
||||
"node_explorer_recycle_bin_node_visible" : false,
|
||||
"node_explorer_external_files_visible" : true,
|
||||
"node_explorer_auto_import_external_files_enabled" : true
|
||||
}
|
||||
}
|
||||
|
@ -224,7 +224,13 @@
|
||||
},
|
||||
"notebookexplorer" : {
|
||||
"node_icon" : {
|
||||
"fg" : "@base#icon#fg"
|
||||
"fg" : "@base#icon#fg",
|
||||
"invalid" : {
|
||||
"fg" : "@base#icon#warning#fg"
|
||||
}
|
||||
},
|
||||
"external_node_icon" : {
|
||||
"fg" : "@base#icon#inactive#fg"
|
||||
}
|
||||
},
|
||||
"viewsplit" : {
|
||||
|
@ -83,7 +83,13 @@
|
||||
},
|
||||
"notebookexplorer" : {
|
||||
"node_icon" : {
|
||||
"fg" : "@base#icon#fg"
|
||||
"fg" : "@base#icon#fg",
|
||||
"invalid" : {
|
||||
"fg" : "@base#icon#warning#fg"
|
||||
}
|
||||
},
|
||||
"external_node_icon" : {
|
||||
"fg" : "@base#icon#disabled#fg"
|
||||
}
|
||||
},
|
||||
"viewsplit" : {
|
||||
|
@ -220,7 +220,13 @@
|
||||
},
|
||||
"notebookexplorer" : {
|
||||
"node_icon" : {
|
||||
"fg" : "@base#icon#fg"
|
||||
"fg" : "@base#icon#fg",
|
||||
"invalid" : {
|
||||
"fg" : "@base#icon#warning#fg"
|
||||
}
|
||||
},
|
||||
"external_node_icon" : {
|
||||
"fg" : "@base#icon#inactive#fg"
|
||||
}
|
||||
},
|
||||
"viewsplit" : {
|
||||
|
@ -119,7 +119,7 @@ QStringList Exporter::doExport(const ExportOption &p_option, const QString &p_ou
|
||||
}
|
||||
|
||||
p_folder->load();
|
||||
const auto &children = p_folder->getChildren();
|
||||
const auto &children = p_folder->getChildrenRef();
|
||||
emit progressUpdated(0, children.size());
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
if (checkAskedToStop()) {
|
||||
@ -192,7 +192,7 @@ QStringList Exporter::doExport(const ExportOption &p_option, Notebook *p_noteboo
|
||||
auto rootNode = p_notebook->getRootNode();
|
||||
Q_ASSERT(rootNode->isLoaded());
|
||||
|
||||
const auto &children = rootNode->getChildren();
|
||||
const auto &children = rootNode->getChildrenRef();
|
||||
emit progressUpdated(0, children.size());
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
if (checkAskedToStop()) {
|
||||
|
@ -61,6 +61,7 @@ bool WebViewExporter::doExport(const ExportOption &p_option,
|
||||
m_webViewStates = WebViewState::Started;
|
||||
|
||||
auto baseUrl = PathUtils::pathToUrl(p_file->getContentPath());
|
||||
m_viewer->adapter()->reset();
|
||||
m_viewer->setHtml(m_htmlTemplate, baseUrl);
|
||||
|
||||
auto textContent = p_file->read();
|
||||
@ -93,7 +94,7 @@ bool WebViewExporter::doExport(const ExportOption &p_option,
|
||||
|
||||
switch (p_option.m_targetFormat) {
|
||||
case ExportFormat::HTML:
|
||||
// TODO: not supported yet.
|
||||
// TODO: MIME HTML format is not supported yet.
|
||||
Q_ASSERT(!p_option.m_htmlOption.m_useMimeHtmlFormat);
|
||||
ret = doExportHtml(p_option.m_htmlOption, p_outputFile, baseUrl);
|
||||
break;
|
||||
|
@ -48,7 +48,7 @@ bool PathUtils::isEmptyDir(const QString &p_path)
|
||||
|
||||
QString PathUtils::concatenateFilePath(const QString &p_dirPath, const QString &p_name)
|
||||
{
|
||||
auto dirPath = cleanPath(p_dirPath);
|
||||
QString dirPath = cleanPath(p_dirPath);
|
||||
if (p_name.isEmpty()) {
|
||||
return dirPath;
|
||||
}
|
||||
@ -57,7 +57,7 @@ QString PathUtils::concatenateFilePath(const QString &p_dirPath, const QString &
|
||||
return p_name;
|
||||
}
|
||||
|
||||
return dirPath + '/' + p_name;
|
||||
return dirPath + "/" + p_name;
|
||||
}
|
||||
|
||||
QString PathUtils::dirName(const QString &p_path)
|
||||
|
@ -356,3 +356,14 @@ void MarkdownViewerAdapter::setSavedContent(const QString &p_headContent,
|
||||
{
|
||||
emit contentReady(p_headContent, p_styleContent, p_content, p_bodyClassList);
|
||||
}
|
||||
|
||||
void MarkdownViewerAdapter::reset()
|
||||
{
|
||||
m_revision = 0;
|
||||
m_viewerReady = false;
|
||||
m_pendingData.reset();
|
||||
m_topLineNumber = -1;
|
||||
m_headings.clear();
|
||||
m_currentHeadingIndex = -1;
|
||||
m_crossCopyTargets.clear();
|
||||
}
|
||||
|
@ -123,6 +123,9 @@ namespace vnotex
|
||||
|
||||
void saveContent();
|
||||
|
||||
// Should be called before WebViewer.setHtml().
|
||||
void reset();
|
||||
|
||||
// Functions to be called from web side.
|
||||
public slots:
|
||||
void setReady(bool p_ready);
|
||||
|
@ -497,10 +497,12 @@ void MarkdownViewWindow::syncViewerFromBuffer(bool p_syncPositionFromEditMode)
|
||||
// TODO: Check buffer for last position recover.
|
||||
|
||||
// Use getPath() instead of getBasePath() to make in-page anchor work.
|
||||
adapter()->reset();
|
||||
m_viewer->setHtml(HtmlTemplateHelper::getMarkdownViewerTemplate(),
|
||||
PathUtils::pathToUrl(buffer->getContentPath()));
|
||||
adapter()->setText(m_bufferRevision, buffer->getContent(), lineNumber);
|
||||
} else {
|
||||
adapter()->reset();
|
||||
m_viewer->setHtml("");
|
||||
adapter()->setText(0, "", -1);
|
||||
}
|
||||
|
@ -63,10 +63,15 @@ void NotebookExplorer::setupUI()
|
||||
});
|
||||
mainLayout->addWidget(m_selector);
|
||||
|
||||
const auto &widgetConfig = ConfigMgr::getInst().getWidgetConfig();
|
||||
m_nodeExplorer = new NotebookNodeExplorer(this);
|
||||
m_nodeExplorer->setRecycleBinNodeVisible(ConfigMgr::getInst().getWidgetConfig().isNoteExplorerRecycleBinNodeShown());
|
||||
m_nodeExplorer->setRecycleBinNodeVisible(widgetConfig.isNodeExplorerRecycleBinNodeVisible());
|
||||
m_nodeExplorer->setViewOrder(widgetConfig.getNodeExplorerViewOrder());
|
||||
m_nodeExplorer->setExternalFilesVisible(widgetConfig.isNodeExplorerExternalFilesVisible());
|
||||
connect(m_nodeExplorer, &NotebookNodeExplorer::nodeActivated,
|
||||
&VNoteX::getInst(), &VNoteX::openNodeRequested);
|
||||
connect(m_nodeExplorer, &NotebookNodeExplorer::fileActivated,
|
||||
&VNoteX::getInst(), &VNoteX::openFileRequested);
|
||||
connect(m_nodeExplorer, &NotebookNodeExplorer::nodeAboutToMove,
|
||||
&VNoteX::getInst(), &VNoteX::nodeAboutToMove);
|
||||
connect(m_nodeExplorer, &NotebookNodeExplorer::nodeAboutToRemove,
|
||||
@ -78,6 +83,8 @@ void NotebookExplorer::setupUI()
|
||||
|
||||
TitleBar *NotebookExplorer::setupTitleBar(QWidget *p_parent)
|
||||
{
|
||||
const auto &widgetConfig = ConfigMgr::getInst().getWidgetConfig();
|
||||
|
||||
auto titleBar = new TitleBar(tr("Notebook"),
|
||||
TitleBar::Action::Menu,
|
||||
p_parent);
|
||||
@ -95,11 +102,11 @@ TitleBar *NotebookExplorer::setupTitleBar(QWidget *p_parent)
|
||||
{
|
||||
auto btn = titleBar->addActionButton(QStringLiteral("recycle_bin.svg"), tr("Toggle Recycle Bin Node"));
|
||||
btn->defaultAction()->setCheckable(true);
|
||||
btn->defaultAction()->setChecked(ConfigMgr::getInst().getWidgetConfig().isNoteExplorerRecycleBinNodeShown());
|
||||
btn->defaultAction()->setChecked(widgetConfig.isNodeExplorerRecycleBinNodeVisible());
|
||||
connect(btn, &QToolButton::triggered,
|
||||
this, [this](QAction *p_act) {
|
||||
const bool checked = p_act->isChecked();
|
||||
ConfigMgr::getInst().getWidgetConfig().setNoteExplorerRecycleBinNodeShown(checked);
|
||||
ConfigMgr::getInst().getWidgetConfig().setNodeExplorerRecycleBinNodeVisible(checked);
|
||||
m_nodeExplorer->setRecycleBinNodeVisible(checked);
|
||||
});
|
||||
}
|
||||
@ -113,6 +120,33 @@ TitleBar *NotebookExplorer::setupTitleBar(QWidget *p_parent)
|
||||
dialog.exec();
|
||||
});
|
||||
|
||||
titleBar->addMenuSeparator();
|
||||
|
||||
// External Files menu.
|
||||
{
|
||||
auto subMenu = titleBar->addMenuSubMenu(tr("External Files"));
|
||||
auto showAct = titleBar->addMenuAction(
|
||||
subMenu,
|
||||
tr("Show External Files"),
|
||||
titleBar,
|
||||
[this](bool p_checked) {
|
||||
ConfigMgr::getInst().getWidgetConfig().setNodeExplorerExternalFilesVisible(p_checked);
|
||||
m_nodeExplorer->setExternalFilesVisible(p_checked);
|
||||
});
|
||||
showAct->setCheckable(true);
|
||||
showAct->setChecked(widgetConfig.isNodeExplorerExternalFilesVisible());
|
||||
|
||||
auto importAct = titleBar->addMenuAction(
|
||||
subMenu,
|
||||
tr("Import External Files When Activated"),
|
||||
titleBar,
|
||||
[this](bool p_checked) {
|
||||
ConfigMgr::getInst().getWidgetConfig().setNodeExplorerAutoImportExternalFilesEnabled(p_checked);
|
||||
});
|
||||
importAct->setCheckable(true);
|
||||
importAct->setChecked(widgetConfig.getNodeExplorerAutoImportExternalFilesEnabled());
|
||||
}
|
||||
|
||||
return titleBar;
|
||||
}
|
||||
|
||||
@ -206,21 +240,7 @@ void NotebookExplorer::newNote()
|
||||
|
||||
Node *NotebookExplorer::currentExploredFolderNode() const
|
||||
{
|
||||
if (!m_currentNotebook) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto node = m_nodeExplorer->getCurrentNode();
|
||||
if (node) {
|
||||
if (!node->isContainer()) {
|
||||
node = node->getParent();
|
||||
}
|
||||
Q_ASSERT(node && node->isContainer());
|
||||
} else {
|
||||
node = m_currentNotebook->getRootNode().data();
|
||||
}
|
||||
|
||||
return node;
|
||||
return m_nodeExplorer->currentExploredFolderNode();
|
||||
}
|
||||
|
||||
Node *NotebookExplorer::checkNotebookAndGetCurrentExploredFolderNode() const
|
||||
@ -372,7 +392,7 @@ void NotebookExplorer::setupViewMenu(QMenu *p_menu)
|
||||
act->setData(NotebookNodeExplorer::ViewOrder::OrderedByModifiedTimeReversed);
|
||||
p_menu->addAction(act);
|
||||
|
||||
int viewOrder = ConfigMgr::getInst().getWidgetConfig().getNoteExplorerViewOrder();
|
||||
int viewOrder = ConfigMgr::getInst().getWidgetConfig().getNodeExplorerViewOrder();
|
||||
for (const auto &act : ag->actions()) {
|
||||
if (act->data().toInt() == viewOrder) {
|
||||
act->setChecked(true);
|
||||
@ -382,8 +402,7 @@ void NotebookExplorer::setupViewMenu(QMenu *p_menu)
|
||||
connect(ag, &QActionGroup::triggered,
|
||||
this, [this](QAction *p_action) {
|
||||
int order = p_action->data().toInt();
|
||||
ConfigMgr::getInst().getWidgetConfig().setNoteExplorerViewOrder(order);
|
||||
|
||||
m_nodeExplorer->reload();
|
||||
ConfigMgr::getInst().getWidgetConfig().setNodeExplorerViewOrder(order);
|
||||
m_nodeExplorer->setViewOrder(order);
|
||||
});
|
||||
}
|
||||
|
@ -6,9 +6,11 @@
|
||||
#include <QTreeWidget>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QSet>
|
||||
|
||||
#include <notebook/notebook.h>
|
||||
#include <notebook/node.h>
|
||||
#include <notebook/externalnode.h>
|
||||
#include "exception.h"
|
||||
#include "messageboxhelper.h"
|
||||
#include "vnotex.h"
|
||||
@ -29,18 +31,23 @@
|
||||
#include <core/fileopenparameters.h>
|
||||
#include <core/events.h>
|
||||
#include <core/configmgr.h>
|
||||
#include <core/widgetconfig.h>
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
const QString NotebookNodeExplorer::c_nodeIconForegroundName = "widgets#notebookexplorer#node_icon#fg";
|
||||
|
||||
QIcon NotebookNodeExplorer::s_folderNodeIcon;
|
||||
|
||||
QIcon NotebookNodeExplorer::s_fileNodeIcon;
|
||||
|
||||
QIcon NotebookNodeExplorer::s_invalidFolderNodeIcon;
|
||||
|
||||
QIcon NotebookNodeExplorer::s_invalidFileNodeIcon;
|
||||
|
||||
QIcon NotebookNodeExplorer::s_recycleBinNodeIcon;
|
||||
|
||||
QIcon NotebookNodeExplorer::s_externalFolderNodeIcon;
|
||||
|
||||
QIcon NotebookNodeExplorer::s_externalFileNodeIcon;
|
||||
|
||||
NotebookNodeExplorer::NodeData::NodeData()
|
||||
{
|
||||
}
|
||||
@ -52,9 +59,9 @@ NotebookNodeExplorer::NodeData::NodeData(Node *p_node, bool p_loaded)
|
||||
{
|
||||
}
|
||||
|
||||
NotebookNodeExplorer::NodeData::NodeData(const QString &p_name)
|
||||
: m_type(NodeType::Attachment),
|
||||
m_name(p_name),
|
||||
NotebookNodeExplorer::NodeData::NodeData(const QSharedPointer<ExternalNode> &p_externalNode)
|
||||
: m_type(NodeType::ExternalNode),
|
||||
m_externalNode(p_externalNode),
|
||||
m_loaded(true)
|
||||
{
|
||||
}
|
||||
@ -67,13 +74,12 @@ NotebookNodeExplorer::NodeData::NodeData(const NodeData &p_other)
|
||||
m_node = p_other.m_node;
|
||||
break;
|
||||
|
||||
case NodeType::Attachment:
|
||||
m_name = p_other.m_name;
|
||||
case NodeType::ExternalNode:
|
||||
m_externalNode = p_other.m_externalNode;
|
||||
break;
|
||||
|
||||
default:
|
||||
m_node = p_other.m_node;
|
||||
m_name = p_other.m_name;
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -96,13 +102,12 @@ NotebookNodeExplorer::NodeData &NotebookNodeExplorer::NodeData::operator=(const
|
||||
m_node = p_other.m_node;
|
||||
break;
|
||||
|
||||
case NodeType::Attachment:
|
||||
m_name = p_other.m_name;
|
||||
case NodeType::ExternalNode:
|
||||
m_externalNode = p_other.m_externalNode;
|
||||
break;
|
||||
|
||||
default:
|
||||
m_node = p_other.m_node;
|
||||
m_name = p_other.m_name;
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -121,9 +126,9 @@ bool NotebookNodeExplorer::NodeData::isNode() const
|
||||
return m_type == NodeType::Node;
|
||||
}
|
||||
|
||||
bool NotebookNodeExplorer::NodeData::isAttachment() const
|
||||
bool NotebookNodeExplorer::NodeData::isExternalNode() const
|
||||
{
|
||||
return m_type == NodeType::Attachment;
|
||||
return m_type == NodeType::ExternalNode;
|
||||
}
|
||||
|
||||
NotebookNodeExplorer::NodeData::NodeType NotebookNodeExplorer::NodeData::getType() const
|
||||
@ -137,17 +142,17 @@ Node *NotebookNodeExplorer::NodeData::getNode() const
|
||||
return m_node;
|
||||
}
|
||||
|
||||
const QString &NotebookNodeExplorer::NodeData::getName() const
|
||||
ExternalNode *NotebookNodeExplorer::NodeData::getExternalNode() const
|
||||
{
|
||||
Q_ASSERT(isAttachment());
|
||||
return m_name;
|
||||
Q_ASSERT(isExternalNode());
|
||||
return m_externalNode.data();
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::NodeData::clear()
|
||||
{
|
||||
m_type = NodeType::Invalid;
|
||||
m_node = nullptr;
|
||||
m_name.clear();
|
||||
m_externalNode.clear();
|
||||
m_loaded = false;
|
||||
}
|
||||
|
||||
@ -180,15 +185,26 @@ void NotebookNodeExplorer::initNodeIcons() const
|
||||
return;
|
||||
}
|
||||
|
||||
const QString nodeIconFgName = "widgets#notebookexplorer#node_icon#fg";
|
||||
const QString invalidNodeIconFgName = "widgets#notebookexplorer#node_icon#invalid#fg";
|
||||
const QString externalNodeIconFgName = "widgets#notebookexplorer#external_node_icon#fg";
|
||||
|
||||
const auto &themeMgr = VNoteX::getInst().getThemeMgr();
|
||||
const auto fg = themeMgr.paletteColor(c_nodeIconForegroundName);
|
||||
const auto fg = themeMgr.paletteColor(nodeIconFgName);
|
||||
const auto invalidFg = themeMgr.paletteColor(invalidNodeIconFgName);
|
||||
const auto externalFg = themeMgr.paletteColor(externalNodeIconFgName);
|
||||
|
||||
const QString folderIconName("folder_node.svg");
|
||||
const QString fileIconName("file_node.svg");
|
||||
const QString recycleBinIconName("recycle_bin.svg");
|
||||
|
||||
s_folderNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), fg);
|
||||
s_fileNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), fg);
|
||||
s_invalidFolderNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), invalidFg);
|
||||
s_invalidFileNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), invalidFg);
|
||||
s_recycleBinNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(recycleBinIconName), fg);
|
||||
s_externalFolderNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), externalFg);
|
||||
s_externalFileNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), externalFg);
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::setupUI()
|
||||
@ -244,8 +260,8 @@ void NotebookNodeExplorer::setupMasterExplorer(QWidget *p_parent)
|
||||
|
||||
if (data.isNode()) {
|
||||
createContextMenuOnNode(menu.data(), data.getNode());
|
||||
} else if (data.isAttachment()) {
|
||||
createContextMenuOnAttachment(menu.data(), data.getName());
|
||||
} else if (data.isExternalNode()) {
|
||||
createContextMenuOnExternalNode(menu.data(), data.getExternalNode());
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,9 +279,23 @@ void NotebookNodeExplorer::setupMasterExplorer(QWidget *p_parent)
|
||||
}
|
||||
|
||||
if (data.isNode()) {
|
||||
if (checkInvalidNode(data.getNode())) {
|
||||
return;
|
||||
}
|
||||
emit nodeActivated(data.getNode(), QSharedPointer<FileOpenParameters>::create());
|
||||
} else if (data.isAttachment()) {
|
||||
// TODO.
|
||||
} else if (data.isExternalNode()) {
|
||||
// Import to config first.
|
||||
if (m_autoImportExternalFiles) {
|
||||
auto importedNode = importToIndex(data.getExternalNode());
|
||||
if (importedNode) {
|
||||
emit nodeActivated(importedNode.data(), QSharedPointer<FileOpenParameters>::create());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Just open it.
|
||||
emit fileActivated(data.getExternalNode()->fetchAbsolutePath(),
|
||||
QSharedPointer<FileOpenParameters>::create());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -333,7 +363,7 @@ void NotebookNodeExplorer::generateNodeTree()
|
||||
|
||||
void NotebookNodeExplorer::loadRootNode(const Node *p_node) const
|
||||
{
|
||||
Q_ASSERT(p_node->isLoaded());
|
||||
Q_ASSERT(p_node->isLoaded() && p_node->isContainer());
|
||||
|
||||
// Render recycle bin node first.
|
||||
auto recycleBinNode = m_notebook->getRecycleBinNode();
|
||||
@ -341,9 +371,20 @@ void NotebookNodeExplorer::loadRootNode(const Node *p_node) const
|
||||
loadRecycleBinNode(recycleBinNode.data());
|
||||
}
|
||||
|
||||
// External children.
|
||||
if (m_externalFilesVisible) {
|
||||
auto externalChildren = p_node->fetchExternalChildren();
|
||||
// TODO: Sort external children.
|
||||
for (const auto &child : externalChildren) {
|
||||
auto item = new QTreeWidgetItem(m_masterExplorer);
|
||||
loadNode(item, child);
|
||||
}
|
||||
}
|
||||
|
||||
// Children.
|
||||
auto children = p_node->getChildren();
|
||||
sortNodes(children);
|
||||
for (auto &child : children) {
|
||||
for (const auto &child : children) {
|
||||
if (recycleBinNode == child) {
|
||||
continue;
|
||||
}
|
||||
@ -378,15 +419,34 @@ void NotebookNodeExplorer::loadNode(QTreeWidgetItem *p_item, Node *p_node, int p
|
||||
}
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::loadNode(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const
|
||||
{
|
||||
clearTreeWigetItemChildren(p_item);
|
||||
|
||||
fillTreeItem(p_item, p_node);
|
||||
|
||||
// No children for external node.
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::loadChildren(QTreeWidgetItem *p_item, Node *p_node, int p_level) const
|
||||
{
|
||||
if (p_level < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// External children.
|
||||
if (m_externalFilesVisible && p_node->isContainer()) {
|
||||
auto externalChildren = p_node->fetchExternalChildren();
|
||||
// TODO: Sort external children.
|
||||
for (const auto &child : externalChildren) {
|
||||
auto item = new QTreeWidgetItem(p_item);
|
||||
loadNode(item, child);
|
||||
}
|
||||
}
|
||||
|
||||
auto children = p_node->getChildren();
|
||||
sortNodes(children);
|
||||
for (auto &child : children) {
|
||||
for (const auto &child : children) {
|
||||
auto item = new QTreeWidgetItem(p_item);
|
||||
loadNode(item, child.data(), p_level);
|
||||
}
|
||||
@ -434,22 +494,33 @@ void NotebookNodeExplorer::fillTreeItem(QTreeWidgetItem *p_item, Node *p_node, b
|
||||
setItemNodeData(p_item, NodeData(p_node, p_loaded));
|
||||
p_item->setText(Column::Name, p_node->getName());
|
||||
p_item->setIcon(Column::Name, getNodeItemIcon(p_node));
|
||||
p_item->setToolTip(Column::Name, p_node->getName());
|
||||
p_item->setToolTip(Column::Name, p_node->exists() ? p_node->getName() : (tr("[Invalid] %1").arg(p_node->getName())));
|
||||
}
|
||||
|
||||
QIcon NotebookNodeExplorer::getNodeItemIcon(const Node *p_node) const
|
||||
void NotebookNodeExplorer::fillTreeItem(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const
|
||||
{
|
||||
setItemNodeData(p_item, NodeData(p_node));
|
||||
p_item->setText(Column::Name, p_node->getName());
|
||||
p_item->setIcon(Column::Name, getNodeItemIcon(p_node.data()));
|
||||
p_item->setToolTip(Column::Name, tr("[External] %1").arg(p_node->getName()));
|
||||
}
|
||||
|
||||
const QIcon &NotebookNodeExplorer::getNodeItemIcon(const Node *p_node) const
|
||||
{
|
||||
if (p_node->hasContent()) {
|
||||
return s_fileNodeIcon;
|
||||
return p_node->exists() ? s_fileNodeIcon : s_invalidFileNodeIcon;
|
||||
} else {
|
||||
if (p_node->getUse() == Node::Use::RecycleBin) {
|
||||
return s_recycleBinNodeIcon;
|
||||
}
|
||||
|
||||
return s_folderNodeIcon;
|
||||
return p_node->exists() ? s_folderNodeIcon : s_invalidFolderNodeIcon;
|
||||
}
|
||||
}
|
||||
|
||||
return QIcon();
|
||||
const QIcon &NotebookNodeExplorer::getNodeItemIcon(const ExternalNode *p_node) const
|
||||
{
|
||||
return p_node->isFolder() ? s_externalFolderNodeIcon : s_externalFileNodeIcon;
|
||||
}
|
||||
|
||||
Node *NotebookNodeExplorer::getCurrentNode() const
|
||||
@ -457,7 +528,7 @@ Node *NotebookNodeExplorer::getCurrentNode() const
|
||||
auto item = m_masterExplorer->currentItem();
|
||||
if (item) {
|
||||
auto data = getItemNodeData(item);
|
||||
while (data.isAttachment()) {
|
||||
while (item && !data.isNode()) {
|
||||
item = item->parent();
|
||||
if (item) {
|
||||
data = getItemNodeData(item);
|
||||
@ -687,6 +758,9 @@ void NotebookNodeExplorer::createContextMenuOnRoot(QMenu *p_menu)
|
||||
|
||||
p_menu->addSeparator();
|
||||
|
||||
act = createAction(Action::Reload, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
act = createAction(Action::OpenLocation, p_menu);
|
||||
p_menu->addAction(act);
|
||||
}
|
||||
@ -698,6 +772,9 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
||||
|
||||
if (m_notebook->isRecycleBinNode(p_node)) {
|
||||
// Recycle bin node.
|
||||
act = createAction(Action::Reload, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
if (selectedSize == 1) {
|
||||
act = createAction(Action::EmptyRecycleBin, p_menu);
|
||||
p_menu->addAction(act);
|
||||
@ -707,12 +784,22 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
||||
}
|
||||
} else if (m_notebook->isNodeInRecycleBin(p_node)) {
|
||||
// Node in recycle bin.
|
||||
act = createAction(Action::Open, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
p_menu->addSeparator();
|
||||
|
||||
act = createAction(Action::Cut, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
act = createAction(Action::DeleteFromRecycleBin, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
p_menu->addSeparator();
|
||||
|
||||
act = createAction(Action::Reload, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
if (selectedSize == 1) {
|
||||
p_menu->addSeparator();
|
||||
|
||||
@ -723,6 +810,11 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
||||
p_menu->addAction(act);
|
||||
}
|
||||
} else {
|
||||
act = createAction(Action::Open, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
p_menu->addSeparator();
|
||||
|
||||
act = createAction(Action::NewNote, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
@ -750,6 +842,9 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
||||
|
||||
p_menu->addSeparator();
|
||||
|
||||
act = createAction(Action::Reload, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
act = createAction(Action::Sort, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
@ -768,10 +863,28 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
||||
}
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::createContextMenuOnAttachment(QMenu *p_menu, const QString &p_name)
|
||||
void NotebookNodeExplorer::createContextMenuOnExternalNode(QMenu *p_menu, const ExternalNode *p_node)
|
||||
{
|
||||
Q_UNUSED(p_menu);
|
||||
Q_UNUSED(p_name);
|
||||
Q_UNUSED(p_node);
|
||||
|
||||
const int selectedSize = m_masterExplorer->selectedItems().size();
|
||||
QAction *act = nullptr;
|
||||
|
||||
act = createAction(Action::Open, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
act = createAction(Action::ImportToConfig, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
if (selectedSize == 1) {
|
||||
p_menu->addSeparator();
|
||||
|
||||
act = createAction(Action::CopyPath, p_menu);
|
||||
p_menu->addAction(act);
|
||||
|
||||
act = createAction(Action::OpenLocation, p_menu);
|
||||
p_menu->addAction(act);
|
||||
}
|
||||
}
|
||||
|
||||
static QIcon generateMenuActionIcon(const QString &p_name)
|
||||
@ -811,7 +924,7 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
||||
connect(act, &QAction::triggered,
|
||||
this, [this]() {
|
||||
auto node = getCurrentNode();
|
||||
if (!node) {
|
||||
if (checkInvalidNode(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -834,15 +947,32 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
||||
act = new QAction(tr("Open &Location"), p_parent);
|
||||
connect(act, &QAction::triggered,
|
||||
this, [this]() {
|
||||
auto item = m_masterExplorer->currentItem();
|
||||
if (!item) {
|
||||
if (m_notebook) {
|
||||
auto locationPath = m_notebook->getRootFolderAbsolutePath();
|
||||
WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(locationPath));
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto data = getItemNodeData(item);
|
||||
QString locationPath;
|
||||
auto node = getCurrentNode();
|
||||
if (node) {
|
||||
if (data.isNode()) {
|
||||
auto node = data.getNode();
|
||||
if (checkInvalidNode(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
locationPath = node->fetchAbsolutePath();
|
||||
if (!node->isContainer()) {
|
||||
locationPath = PathUtils::parentDirPath(locationPath);
|
||||
}
|
||||
} else if (m_notebook) {
|
||||
locationPath = m_notebook->getRootFolderAbsolutePath();
|
||||
} else if (data.isExternalNode()) {
|
||||
auto externalNode = data.getExternalNode();
|
||||
locationPath = externalNode->fetchAbsolutePath();
|
||||
if (!externalNode->isFolder()) {
|
||||
locationPath = PathUtils::parentDirPath(locationPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (!locationPath.isEmpty()) {
|
||||
@ -855,9 +985,22 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
||||
act = new QAction(tr("Cop&y Path"), p_parent);
|
||||
connect(act, &QAction::triggered,
|
||||
this, [this]() {
|
||||
auto node = getCurrentNode();
|
||||
if (node) {
|
||||
auto nodePath = node->fetchAbsolutePath();
|
||||
auto item = m_masterExplorer->currentItem();
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
auto data = getItemNodeData(item);
|
||||
QString nodePath;
|
||||
if (data.isNode()) {
|
||||
auto node = data.getNode();
|
||||
if (checkInvalidNode(node)) {
|
||||
return;
|
||||
}
|
||||
nodePath = node->fetchAbsolutePath();
|
||||
} else if (data.isExternalNode()) {
|
||||
nodePath = data.getExternalNode()->fetchAbsolutePath();
|
||||
}
|
||||
if (!nodePath.isEmpty()) {
|
||||
ClipboardUtils::setTextToClipboard(nodePath);
|
||||
VNoteX::getInst().showStatusMessageShort(tr("Copied path: %1").arg(nodePath));
|
||||
}
|
||||
@ -906,9 +1049,8 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
||||
m_notebook->emptyNode(rbNode, true);
|
||||
} catch (Exception &p_e) {
|
||||
MessageBoxHelper::notify(MessageBoxHelper::Critical,
|
||||
tr("Failed to empty recycle bin (%1) (%2).")
|
||||
.arg(rbNodePath, p_e.what()),
|
||||
VNoteX::getInst().getMainWindow());
|
||||
tr("Failed to empty recycle bin (%1) (%2).").arg(rbNodePath, p_e.what()),
|
||||
VNoteX::getInst().getMainWindow());
|
||||
}
|
||||
|
||||
updateNode(rbNode);
|
||||
@ -935,18 +1077,42 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
||||
case Action::RemoveFromConfig:
|
||||
act = new QAction(tr("&Remove From Index"), p_parent);
|
||||
connect(act, &QAction::triggered,
|
||||
this, [this]() {
|
||||
removeSelectedNodesFromConfig();
|
||||
});
|
||||
this, &NotebookNodeExplorer::removeSelectedNodesFromConfig);
|
||||
break;
|
||||
|
||||
case Action::Sort:
|
||||
act = new QAction(generateMenuActionIcon("sort.svg"), tr("&Sort"), p_parent);
|
||||
connect(act, &QAction::triggered,
|
||||
this, &NotebookNodeExplorer::manualSort);
|
||||
break;
|
||||
|
||||
case Action::Reload:
|
||||
act = new QAction(tr("Re&load"), p_parent);
|
||||
connect(act, &QAction::triggered,
|
||||
this, [this]() {
|
||||
manualSort();
|
||||
auto node = currentExploredFolderNode();
|
||||
if (m_notebook && node) {
|
||||
// TODO: emit signals to notify other components.
|
||||
m_notebook->reloadNode(node);
|
||||
}
|
||||
updateNode(node);
|
||||
});
|
||||
break;
|
||||
|
||||
case Action::ImportToConfig:
|
||||
act = new QAction(tr("&Import To Index"), p_parent);
|
||||
connect(act, &QAction::triggered,
|
||||
this, [this]() {
|
||||
auto nodes = getSelectedNodes().second;
|
||||
importToIndex(nodes);
|
||||
});
|
||||
break;
|
||||
|
||||
case Action::Open:
|
||||
act = new QAction(tr("&Open"), p_parent);
|
||||
connect(act, &QAction::triggered,
|
||||
this, &NotebookNodeExplorer::openSelectedNodes);
|
||||
break;
|
||||
}
|
||||
|
||||
return act;
|
||||
@ -954,7 +1120,7 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
||||
|
||||
void NotebookNodeExplorer::copySelectedNodes(bool p_move)
|
||||
{
|
||||
auto nodes = getSelectedNodes();
|
||||
auto nodes = getSelectedNodes().first;
|
||||
if (nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -964,6 +1130,10 @@ void NotebookNodeExplorer::copySelectedNodes(bool p_move)
|
||||
ClipboardData cdata(VNoteX::getInst().getInstanceId(),
|
||||
p_move ? ClipboardData::MoveNode : ClipboardData::CopyNode);
|
||||
for (auto node : nodes) {
|
||||
if (checkInvalidNode(node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto item = QSharedPointer<NodeClipboardDataItem>::create(node->getNotebook()->getId(),
|
||||
node->fetchPath());
|
||||
cdata.addItem(item);
|
||||
@ -976,15 +1146,17 @@ void NotebookNodeExplorer::copySelectedNodes(bool p_move)
|
||||
VNoteX::getInst().showStatusMessageShort(tr("Copied %n item(s)", "", static_cast<int>(nrItems)));
|
||||
}
|
||||
|
||||
QVector<Node *> NotebookNodeExplorer::getSelectedNodes() const
|
||||
QPair<QVector<Node *>, QVector<ExternalNode *>> NotebookNodeExplorer::getSelectedNodes() const
|
||||
{
|
||||
QVector<Node *> nodes;
|
||||
QPair<QVector<Node *>, QVector<ExternalNode *>> nodes;
|
||||
|
||||
auto items = m_masterExplorer->selectedItems();
|
||||
for (auto &item : items) {
|
||||
auto data = getItemNodeData(item);
|
||||
if (data.isNode()) {
|
||||
nodes.push_back(data.getNode());
|
||||
nodes.first.push_back(data.getNode());
|
||||
} else if (data.isExternalNode()) {
|
||||
nodes.second.push_back(data.getExternalNode());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1051,6 +1223,8 @@ void NotebookNodeExplorer::pasteNodesFromClipboard()
|
||||
// Current node may be a file node.
|
||||
if (!destNode->isContainer()) {
|
||||
destNode = destNode->getParent();
|
||||
} else if (checkInvalidNode(destNode)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1088,6 +1262,8 @@ void NotebookNodeExplorer::pasteNodesFromClipboard()
|
||||
QVector<const Node *> pastedNodes;
|
||||
QSet<Node *> nodesNeedUpdate;
|
||||
for (auto srcNode : srcNodes) {
|
||||
Q_ASSERT(srcNode->exists());
|
||||
|
||||
if (isMove) {
|
||||
// Notice the view area to close any opened view windows.
|
||||
auto event = QSharedPointer<Event>::create();
|
||||
@ -1176,7 +1352,7 @@ QVector<Node *> NotebookNodeExplorer::confirmSelectedNodes(const QString &p_titl
|
||||
const QString &p_text,
|
||||
const QString &p_info) const
|
||||
{
|
||||
auto nodes = getSelectedNodes();
|
||||
auto nodes = getSelectedNodes().first;
|
||||
if (nodes.isEmpty()) {
|
||||
return nodes;
|
||||
}
|
||||
@ -1270,7 +1446,7 @@ void NotebookNodeExplorer::removeSelectedNodesFromConfig()
|
||||
|
||||
void NotebookNodeExplorer::filterAwayChildrenNodes(QVector<Node *> &p_nodes)
|
||||
{
|
||||
for (int i = p_nodes.size() - 1; i > 0; --i) {
|
||||
for (int i = p_nodes.size() - 1; i >= 0; --i) {
|
||||
// Check if j is i's ancestor.
|
||||
for (int j = p_nodes.size() - 1; j >= 0; --j) {
|
||||
if (i == j) {
|
||||
@ -1351,8 +1527,7 @@ void NotebookNodeExplorer::focusNormalNode()
|
||||
|
||||
void NotebookNodeExplorer::sortNodes(QVector<QSharedPointer<Node>> &p_nodes) const
|
||||
{
|
||||
int viewOrder = ConfigMgr::getInst().getWidgetConfig().getNoteExplorerViewOrder();
|
||||
if (viewOrder == ViewOrder::OrderedByConfiguration) {
|
||||
if (m_viewOrder == ViewOrder::OrderedByConfiguration) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1369,10 +1544,10 @@ void NotebookNodeExplorer::sortNodes(QVector<QSharedPointer<Node>> &p_nodes) con
|
||||
}
|
||||
|
||||
// Sort containers.
|
||||
sortNodes(p_nodes, 0, firstFileIndex, viewOrder);
|
||||
sortNodes(p_nodes, 0, firstFileIndex, m_viewOrder);
|
||||
|
||||
// Sort non-containers.
|
||||
sortNodes(p_nodes, firstFileIndex, p_nodes.size(), viewOrder);
|
||||
sortNodes(p_nodes, firstFileIndex, p_nodes.size(), m_viewOrder);
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::sortNodes(QVector<QSharedPointer<Node>> &p_nodes, int p_start, int p_end, int p_viewOrder) const
|
||||
@ -1437,6 +1612,25 @@ void NotebookNodeExplorer::setRecycleBinNodeVisible(bool p_visible)
|
||||
reload();
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::setExternalFilesVisible(bool p_visible)
|
||||
{
|
||||
if (m_externalFilesVisible == p_visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_externalFilesVisible = p_visible;
|
||||
reload();
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::setAutoImportExternalFiles(bool p_enabled)
|
||||
{
|
||||
if (m_autoImportExternalFiles == p_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_autoImportExternalFiles = p_enabled;
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::manualSort()
|
||||
{
|
||||
auto node = getCurrentNode();
|
||||
@ -1465,7 +1659,7 @@ void NotebookNodeExplorer::manualSort()
|
||||
treeWidget->setColumnCount(2);
|
||||
treeWidget->setHeaderLabels({tr("Name"), tr("Created Time"), tr("Modified Time")});
|
||||
|
||||
const auto &children = parentNode->getChildren();
|
||||
const auto &children = parentNode->getChildrenRef();
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
const auto &child = children[i];
|
||||
if (m_notebook->isRecycleBinNode(child.data())) {
|
||||
@ -1498,3 +1692,107 @@ void NotebookNodeExplorer::manualSort()
|
||||
updateNode(parentNode);
|
||||
}
|
||||
}
|
||||
|
||||
Node *NotebookNodeExplorer::currentExploredFolderNode() const
|
||||
{
|
||||
if (!m_notebook) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto node = getCurrentNode();
|
||||
if (node) {
|
||||
if (!node->isContainer()) {
|
||||
node = node->getParent();
|
||||
}
|
||||
Q_ASSERT(node && node->isContainer());
|
||||
} else {
|
||||
node = m_notebook->getRootNode().data();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::setViewOrder(int p_order)
|
||||
{
|
||||
if (m_viewOrder == p_order) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_viewOrder = p_order;
|
||||
reload();
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::openSelectedNodes()
|
||||
{
|
||||
// Support nodes and external nodes.
|
||||
// Do nothing for folders.
|
||||
auto selectedNodes = getSelectedNodes();
|
||||
for (const auto &externalNode : selectedNodes.second) {
|
||||
if (!externalNode->isFolder()) {
|
||||
emit fileActivated(externalNode->fetchAbsolutePath(), QSharedPointer<FileOpenParameters>::create());
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &node : selectedNodes.first) {
|
||||
if (checkInvalidNode(node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node->hasContent()) {
|
||||
emit nodeActivated(node, QSharedPointer<FileOpenParameters>::create());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<Node> NotebookNodeExplorer::importToIndex(const ExternalNode *p_node)
|
||||
{
|
||||
auto node = m_notebook->addAsNode(p_node->getNode(),
|
||||
p_node->isFolder() ? Node::Flag::Container : Node::Flag::Content,
|
||||
p_node->getName(),
|
||||
NodeParameters());
|
||||
updateNode(p_node->getNode());
|
||||
if (node) {
|
||||
setCurrentNode(node.data());
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void NotebookNodeExplorer::importToIndex(const QVector<ExternalNode *> &p_nodes)
|
||||
{
|
||||
QSet<Node *> nodesToUpdate;
|
||||
Node *currentNode = nullptr;
|
||||
|
||||
for (auto externalNode : p_nodes) {
|
||||
auto node = m_notebook->addAsNode(externalNode->getNode(),
|
||||
externalNode->isFolder() ? Node::Flag::Container : Node::Flag::Content,
|
||||
externalNode->getName(),
|
||||
NodeParameters());
|
||||
nodesToUpdate.insert(externalNode->getNode());
|
||||
currentNode = node.data();
|
||||
}
|
||||
|
||||
for (auto node : nodesToUpdate) {
|
||||
updateNode(node);
|
||||
}
|
||||
if (currentNode) {
|
||||
setCurrentNode(currentNode);
|
||||
}
|
||||
}
|
||||
|
||||
bool NotebookNodeExplorer::checkInvalidNode(const Node *p_node) const
|
||||
{
|
||||
if (!p_node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!p_node->exists()) {
|
||||
MessageBoxHelper::notify(MessageBoxHelper::Warning,
|
||||
tr("Invalid node (%1).").arg(p_node->getName()),
|
||||
tr("Please check if the node exists on the disk."),
|
||||
p_node->fetchAbsolutePath(),
|
||||
VNoteX::getInst().getMainWindow());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <QSharedPointer>
|
||||
#include <QHash>
|
||||
#include <QScopedPointer>
|
||||
#include <QPair>
|
||||
|
||||
#include "qtreewidgetstatecache.h"
|
||||
#include "clipboarddata.h"
|
||||
@ -22,6 +23,7 @@ namespace vnotex
|
||||
class TreeWidget;
|
||||
struct FileOpenParameters;
|
||||
class Event;
|
||||
class ExternalNode;
|
||||
|
||||
class NotebookNodeExplorer : public QWidget
|
||||
{
|
||||
@ -32,13 +34,13 @@ namespace vnotex
|
||||
class NodeData
|
||||
{
|
||||
public:
|
||||
enum class NodeType { Node, Attachment, Invalid };
|
||||
enum class NodeType { Node, ExternalNode, Invalid };
|
||||
|
||||
NodeData();
|
||||
|
||||
explicit NodeData(Node *p_node, bool p_loaded);
|
||||
|
||||
explicit NodeData(const QString &p_name);
|
||||
explicit NodeData(const QSharedPointer<ExternalNode> &p_externalNode);
|
||||
|
||||
NodeData(const NodeData &p_other);
|
||||
|
||||
@ -50,13 +52,13 @@ namespace vnotex
|
||||
|
||||
bool isNode() const;
|
||||
|
||||
bool isAttachment() const;
|
||||
bool isExternalNode() const;
|
||||
|
||||
NodeData::NodeType getType() const;
|
||||
|
||||
Node *getNode() const;
|
||||
|
||||
const QString &getName() const;
|
||||
ExternalNode *getExternalNode() const;
|
||||
|
||||
void clear();
|
||||
|
||||
@ -67,11 +69,9 @@ namespace vnotex
|
||||
private:
|
||||
NodeType m_type = NodeType::Invalid;
|
||||
|
||||
union
|
||||
{
|
||||
Node *m_node = nullptr;
|
||||
QString m_name;
|
||||
};
|
||||
Node *m_node = nullptr;
|
||||
|
||||
QSharedPointer<ExternalNode> m_externalNode;
|
||||
|
||||
bool m_loaded = false;
|
||||
};
|
||||
@ -104,10 +104,18 @@ namespace vnotex
|
||||
|
||||
void setRecycleBinNodeVisible(bool p_visible);
|
||||
|
||||
void setViewOrder(int p_order);
|
||||
|
||||
void setExternalFilesVisible(bool p_visible);
|
||||
|
||||
void setAutoImportExternalFiles(bool p_enabled);
|
||||
|
||||
Node *currentExploredFolderNode() const;
|
||||
|
||||
signals:
|
||||
void nodeActivated(Node *p_node, const QSharedPointer<FileOpenParameters> &p_paras);
|
||||
|
||||
void fileActivated(const QString &p_path);
|
||||
void fileActivated(const QString &p_path, const QSharedPointer<FileOpenParameters> &p_paras);
|
||||
|
||||
// @m_response of @p_event: true to continue the move, false to cancel the move.
|
||||
void nodeAboutToMove(Node *p_node, const QSharedPointer<Event> &p_event);
|
||||
@ -132,7 +140,10 @@ namespace vnotex
|
||||
Delete,
|
||||
DeleteFromRecycleBin,
|
||||
RemoveFromConfig,
|
||||
Sort
|
||||
Sort,
|
||||
Reload,
|
||||
ImportToConfig,
|
||||
Open
|
||||
};
|
||||
|
||||
void setupUI();
|
||||
@ -149,13 +160,19 @@ namespace vnotex
|
||||
|
||||
void loadChildren(QTreeWidgetItem *p_item, Node *p_node, int p_level) const;
|
||||
|
||||
void loadNode(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const;
|
||||
|
||||
void loadRecycleBinNode(Node *p_node) const;
|
||||
|
||||
void loadRecycleBinNode(QTreeWidgetItem *p_item, Node *p_node, int p_level) const;
|
||||
|
||||
void fillTreeItem(QTreeWidgetItem *p_item, Node *p_node, bool p_loaded) const;
|
||||
|
||||
QIcon getNodeItemIcon(const Node *p_node) const;
|
||||
void fillTreeItem(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const;
|
||||
|
||||
const QIcon &getNodeItemIcon(const Node *p_node) const;
|
||||
|
||||
const QIcon &getNodeItemIcon(const ExternalNode *p_node) const;
|
||||
|
||||
void initNodeIcons() const;
|
||||
|
||||
@ -177,7 +194,7 @@ namespace vnotex
|
||||
|
||||
void createContextMenuOnNode(QMenu *p_menu, const Node *p_node);
|
||||
|
||||
void createContextMenuOnAttachment(QMenu *p_menu, const QString &p_name);
|
||||
void createContextMenuOnExternalNode(QMenu *p_menu, const ExternalNode *p_node);
|
||||
|
||||
// Factory function to create action.
|
||||
QAction *createAction(Action p_act, QObject *p_parent);
|
||||
@ -186,8 +203,7 @@ namespace vnotex
|
||||
|
||||
void pasteNodesFromClipboard();
|
||||
|
||||
// Only return selected Nodes.
|
||||
QVector<Node *> getSelectedNodes() const;
|
||||
QPair<QVector<Node *>, QVector<ExternalNode *>> getSelectedNodes() const;
|
||||
|
||||
void removeSelectedNodes(bool p_skipRecycleBin);
|
||||
|
||||
@ -226,6 +242,16 @@ namespace vnotex
|
||||
// Sort nodes in config file.
|
||||
void manualSort();
|
||||
|
||||
void openSelectedNodes();
|
||||
|
||||
QSharedPointer<Node> importToIndex(const ExternalNode *p_node);
|
||||
|
||||
void importToIndex(const QVector<ExternalNode *> &p_nodes);
|
||||
|
||||
// Check whether @p_node is a valid node. Will notify user.
|
||||
// Return true if it is invalid.
|
||||
bool checkInvalidNode(const Node *p_node) const;
|
||||
|
||||
static NotebookNodeExplorer::NodeData getItemNodeData(const QTreeWidgetItem *p_item);
|
||||
|
||||
static void setItemNodeData(QTreeWidgetItem *p_item, const NodeData &p_data);
|
||||
@ -242,11 +268,25 @@ namespace vnotex
|
||||
|
||||
bool m_recycleBinNodeVisible = false;
|
||||
|
||||
int m_viewOrder = ViewOrder::OrderedByConfiguration;
|
||||
|
||||
bool m_externalFilesVisible = true;
|
||||
|
||||
bool m_autoImportExternalFiles = true;
|
||||
|
||||
static QIcon s_folderNodeIcon;
|
||||
|
||||
static QIcon s_fileNodeIcon;
|
||||
|
||||
static QIcon s_invalidFolderNodeIcon;
|
||||
|
||||
static QIcon s_invalidFileNodeIcon;
|
||||
|
||||
static QIcon s_recycleBinNodeIcon;
|
||||
|
||||
static const QString c_nodeIconForegroundName;
|
||||
static QIcon s_externalFolderNodeIcon;
|
||||
|
||||
static QIcon s_externalFileNodeIcon;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,11 @@ QAction *TitleBar::addMenuAction(const QString &p_iconName, const QString &p_tex
|
||||
return act;
|
||||
}
|
||||
|
||||
QMenu *TitleBar::addMenuSubMenu(const QString &p_text)
|
||||
{
|
||||
return m_menu->addMenu(p_text);
|
||||
}
|
||||
|
||||
void TitleBar::addMenuSeparator()
|
||||
{
|
||||
Q_ASSERT(m_menu);
|
||||
|
@ -39,6 +39,11 @@ namespace vnotex
|
||||
template <typename Functor>
|
||||
QAction *addMenuAction(const QString &p_text, const QObject *p_context, Functor p_functor);
|
||||
|
||||
template <typename Functor>
|
||||
QAction *addMenuAction(QMenu *p_subMenu, const QString &p_text, const QObject *p_context, Functor p_functor);
|
||||
|
||||
QMenu *addMenuSubMenu(const QString &p_text);
|
||||
|
||||
void addMenuSeparator();
|
||||
|
||||
protected:
|
||||
@ -91,6 +96,14 @@ namespace vnotex
|
||||
auto act = m_menu->addAction(p_text, p_context, p_functor);
|
||||
return act;
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
QAction *TitleBar::addMenuAction(QMenu *p_subMenu, const QString &p_text, const QObject *p_context, Functor p_functor)
|
||||
{
|
||||
Q_ASSERT(p_subMenu->parent() == m_menu);
|
||||
auto act = p_subMenu->addAction(p_text, p_context, p_functor);
|
||||
return act;
|
||||
}
|
||||
} // ns vnotex
|
||||
|
||||
#endif // TITLEBAR_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user