#include "notebook.h" #include #include #include #include #include #include #include #include "nodeparameters.h" using namespace vnotex; const QString Notebook::c_defaultAttachmentFolder = QStringLiteral("vx_attachments"); const QString Notebook::c_defaultImageFolder = QStringLiteral("vx_images"); static vnotex::ID generateNotebookID() { static vnotex::ID id = Notebook::InvalidId; return ++id; } Notebook::Notebook(const NotebookParameters &p_paras, QObject *p_parent) : QObject(p_parent), m_id(generateNotebookID()), m_type(p_paras.m_type), m_name(p_paras.m_name), m_description(p_paras.m_description), m_rootFolderPath(p_paras.m_rootFolderPath), m_icon(p_paras.m_icon), m_imageFolder(p_paras.m_imageFolder), m_attachmentFolder(p_paras.m_attachmentFolder), m_createdTimeUtc(p_paras.m_createdTimeUtc), m_backend(p_paras.m_notebookBackend), m_versionController(p_paras.m_versionController), m_configMgr(p_paras.m_notebookConfigMgr) { if (m_imageFolder.isEmpty()) { m_imageFolder = c_defaultImageFolder; } if (m_attachmentFolder.isEmpty()) { m_attachmentFolder = c_defaultAttachmentFolder; } m_configMgr->setNotebook(this); } Notebook::Notebook(const QString &p_name, QObject *p_parent) : QObject(p_parent), m_name(p_name) { } Notebook::~Notebook() { } void Notebook::initialize() { if (m_initialized) { return; } m_initialized = true; initializeInternal(); } vnotex::ID Notebook::getId() const { return m_id; } const QString &Notebook::getType() const { return m_type; } const QString &Notebook::getName() const { return m_name; } void Notebook::setName(const QString &p_name) { m_name = p_name; } void Notebook::updateName(const QString &p_name) { Q_ASSERT(!p_name.isEmpty()); if (p_name == m_name) { return; } m_name = p_name; updateNotebookConfig(); emit updated(); } const QString &Notebook::getDescription() const { return m_description; } void Notebook::setDescription(const QString &p_description) { m_description = p_description; } void Notebook::updateDescription(const QString &p_description) { if (p_description == m_description) { return; } m_description = p_description; updateNotebookConfig(); emit updated(); } const QString &Notebook::getRootFolderPath() const { return m_rootFolderPath; } QString Notebook::getRootFolderAbsolutePath() const { return PathUtils::absolutePath(m_rootFolderPath); } const QIcon &Notebook::getIcon() const { return m_icon; } void Notebook::setIcon(const QIcon &p_icon) { m_icon = p_icon; } const QString &Notebook::getImageFolder() const { return m_imageFolder; } const QString &Notebook::getAttachmentFolder() const { return m_attachmentFolder; } const QSharedPointer &Notebook::getBackend() const { return m_backend; } const QSharedPointer &Notebook::getVersionController() const { return m_versionController; } const QSharedPointer &Notebook::getConfigMgr() const { return m_configMgr; } const QSharedPointer &Notebook::getRootNode() const { if (!m_root) { const_cast(this)->m_root = m_configMgr->loadRootNode(); Q_ASSERT(m_root->isRoot()); } return m_root; } QSharedPointer Notebook::getRecycleBinNode() const { auto root = getRootNode(); const auto &children = root->getChildrenRef(); auto it = std::find_if(children.begin(), children.end(), [this](const QSharedPointer &p_node) { return isRecycleBinNode(p_node.data()); }); if (it != children.end()) { return *it; } return nullptr; } QSharedPointer Notebook::newNode(Node *p_parent, Node::Flags p_flags, const QString &p_name, const QString &p_content) { return m_configMgr->newNode(p_parent, p_flags, p_name, p_content); } const QDateTime &Notebook::getCreatedTimeUtc() const { return m_createdTimeUtc; } QSharedPointer Notebook::loadNodeByPath(const QString &p_path) { if (!PathUtils::pathContains(m_rootFolderPath, p_path)) { return nullptr; } QString relativePath; QFileInfo fi(p_path); if (fi.isAbsolute()) { if (!fi.exists()) { return nullptr; } relativePath = PathUtils::relativePath(m_rootFolderPath, p_path); } else { relativePath = p_path; } return m_configMgr->loadNodeByPath(getRootNode(), relativePath); } QSharedPointer Notebook::copyNodeAsChildOf(const QSharedPointer &p_src, Node *p_dest, bool p_move) { Q_ASSERT(p_src != p_dest); Q_ASSERT(p_dest->getNotebook() == this); if (Node::isAncestor(p_src.data(), p_dest)) { Exception::throwOne(Exception::Type::InvalidArgument, QString("source (%1) is the ancestor of destination (%2)") .arg(p_src->fetchPath(), p_dest->fetchPath())); return nullptr; } if (p_src->getParent() == p_dest && p_move) { return p_src; } return m_configMgr->copyNodeAsChildOf(p_src, p_dest, p_move); } void Notebook::removeNode(const QSharedPointer &p_node, bool p_force, bool p_configOnly) { Q_ASSERT(p_node && !p_node->isRoot()); Q_ASSERT(p_node->getNotebook() == this); m_configMgr->removeNode(p_node, p_force, p_configOnly); } void Notebook::removeNode(Node *p_node, bool p_force, bool p_configOnly) { Q_ASSERT(p_node); removeNode(p_node->sharedFromThis(), p_force, p_configOnly); } bool Notebook::isRecycleBinNode(const Node *p_node) const { return p_node && p_node->getUse() == Node::Use::RecycleBin; } bool Notebook::isNodeInRecycleBin(const Node *p_node) const { if (p_node) { p_node = p_node->getParent(); while (p_node) { if (isRecycleBinNode(p_node)) { return true; } p_node = p_node->getParent(); } } return false; } void Notebook::moveNodeToRecycleBin(Node *p_node) { moveNodeToRecycleBin(p_node->sharedFromThis()); } void Notebook::moveNodeToRecycleBin(const QSharedPointer &p_node) { Q_ASSERT(p_node && !p_node->isRoot()); auto destNode = getOrCreateRecycleBinDateNode(); copyNodeAsChildOf(p_node, destNode.data(), true); } QSharedPointer Notebook::getOrCreateRecycleBinDateNode() { // Name after date. auto dateNodeName = QDate::currentDate().toString(QStringLiteral("yyyyMMdd")); auto recycleBinNode = getRecycleBinNode(); auto dateNode = recycleBinNode->findChild(dateNodeName, FileUtils::isPlatformNameCaseSensitive()); if (!dateNode) { // Create a date node. dateNode = newNode(recycleBinNode.data(), Node::Flag::Container, dateNodeName); } return dateNode; } void Notebook::emptyNode(const Node *p_node, bool p_force) { // Empty the children. auto children = p_node->getChildren(); for (const auto &child : children) { removeNode(child, p_force); } } void Notebook::moveFileToRecycleBin(const QString &p_filePath) { auto node = getOrCreateRecycleBinDateNode(); auto destFilePath = PathUtils::concatenateFilePath(node->fetchPath(), PathUtils::fileName(p_filePath)); destFilePath = getBackend()->renameIfExistsCaseInsensitive(destFilePath); m_backend->copyFile(p_filePath, destFilePath); getBackend()->removeFile(p_filePath); emit nodeUpdated(node.data()); } void Notebook::moveDirToRecycleBin(const QString &p_dirPath) { auto node = getOrCreateRecycleBinDateNode(); auto destDirPath = PathUtils::concatenateFilePath(node->fetchPath(), PathUtils::fileName(p_dirPath)); destDirPath = getBackend()->renameIfExistsCaseInsensitive(destDirPath); m_backend->copyDir(p_dirPath, destDirPath); getBackend()->removeDir(p_dirPath); emit nodeUpdated(node.data()); } QSharedPointer Notebook::addAsNode(Node *p_parent, Node::Flags p_flags, const QString &p_name, const NodeParameters &p_paras) { return m_configMgr->addAsNode(p_parent, p_flags, p_name, p_paras); } bool Notebook::isBuiltInFile(const Node *p_node, const QString &p_name) const { return m_configMgr->isBuiltInFile(p_node, p_name); } bool Notebook::isBuiltInFolder(const Node *p_node, const QString &p_name) const { return m_configMgr->isBuiltInFolder(p_node, p_name); } QSharedPointer Notebook::copyAsNode(Node *p_parent, Node::Flags p_flags, const QString &p_path) { return m_configMgr->copyAsNode(p_parent, p_flags, p_path); } void Notebook::reloadNodes() { m_root.clear(); getRootNode(); } QJsonObject Notebook::getExtraConfig(const QString &p_key) const { const auto &configs = getExtraConfigs(); return configs.value(p_key).toObject(); } QList> Notebook::collectFiles() { QList> files; auto rootNode = getRootNode(); const auto &children = rootNode->getChildrenRef(); for (const auto &child : children) { if (child->getUse() != Node::Use::Normal) { continue; } files.append(child->collectFiles()); } return files; } QStringList Notebook::scanAndImportExternalFiles() { return m_configMgr->scanAndImportExternalFiles(getRootNode().data()); } bool Notebook::rebuildDatabase() { return false; } HistoryI *Notebook::history() { return nullptr; } TagI *Notebook::tag() { return nullptr; }