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