remove recycle bin node

This commit is contained in:
Le Tan 2021-10-26 08:09:50 +08:00
parent c362facdd7
commit 964dfbb085
32 changed files with 349 additions and 544 deletions

View File

@ -23,6 +23,8 @@ namespace vnotex
FailToRemoveDir,
FileMissingOnDisk,
EssentialFileMissing,
FileExistsOnCreate,
DirExistsOnCreate,
InvalidArgument
};

View File

@ -254,3 +254,8 @@ TagI *BundleNotebook::tag()
{
return getTagMgr();
}
int BundleNotebook::getConfigVersion() const
{
return m_configVersion;
}

View File

@ -41,6 +41,8 @@ namespace vnotex
TagI *tag() Q_DECL_OVERRIDE;
int getConfigVersion() const;
// HistoryI.
public:
HistoryI *history() Q_DECL_OVERRIDE;

View File

@ -109,6 +109,24 @@ bool Node::containsChild(const QSharedPointer<Node> &p_node) const
return m_children.indexOf(p_node) != -1;
}
bool Node::isLegalNameForNewChild(const QString &p_name) const
{
if (p_name.isEmpty()) {
return false;
}
auto mgr = getConfigMgr();
if (mgr->isBuiltInFile(this, p_name) || mgr->isBuiltInFolder(this, p_name)) {
return false;
}
if (containsChild(p_name, false)) {
return false;
}
return true;
}
QSharedPointer<Node> Node::findChild(const QString &p_name, bool p_caseSensitive) const
{
auto targetName = p_caseSensitive ? p_name : p_name.toLower();
@ -356,7 +374,7 @@ bool Node::canRename(const QString &p_newName) const
}
}
if (m_parent->containsChild(p_newName, false)) {
if (!m_parent->isLegalNameForNewChild(p_newName)) {
return false;
}

View File

@ -36,7 +36,6 @@ namespace vnotex
enum Use {
Normal,
RecycleBin,
Root
};
@ -115,6 +114,8 @@ namespace vnotex
// Case sensitive.
bool containsContentChild(const QString &p_name) const;
bool isLegalNameForNewChild(const QString &p_name) const;
void addChild(const QSharedPointer<Node> &p_node);
void insertChild(int p_idx, const QSharedPointer<Node> &p_node);

View File

@ -16,6 +16,8 @@ const QString Notebook::c_defaultAttachmentFolder = QStringLiteral("vx_attachmen
const QString Notebook::c_defaultImageFolder = QStringLiteral("vx_images");
const QString Notebook::c_defaultRecycleBinFolder = QStringLiteral("vx_recycle_bin");
static vnotex::ID generateNotebookID()
{
static vnotex::ID id = Notebook::InvalidId;
@ -44,6 +46,9 @@ Notebook::Notebook(const NotebookParameters &p_paras,
if (m_attachmentFolder.isEmpty()) {
m_attachmentFolder = c_defaultAttachmentFolder;
}
if (m_recycleBinFolder.isEmpty()) {
m_recycleBinFolder = c_defaultRecycleBinFolder;
}
m_configMgr->setNotebook(this);
}
@ -151,6 +156,28 @@ const QString &Notebook::getAttachmentFolder() const
return m_attachmentFolder;
}
const QString &Notebook::getRecycleBinFolder() const
{
return m_recycleBinFolder;
}
QString Notebook::getRecycleBinFolderAbsolutePath() const
{
if (QDir::isAbsolutePath(m_recycleBinFolder)) {
if (!QFileInfo::exists(m_recycleBinFolder)) {
QDir dir(m_recycleBinFolder);
dir.mkpath(m_recycleBinFolder);
}
return m_recycleBinFolder;
} else {
auto folderPath = getBackend()->getFullPath(m_recycleBinFolder);
if (!getBackend()->exists(m_recycleBinFolder)) {
getBackend()->makePath(m_recycleBinFolder);
}
return folderPath;
}
}
const QSharedPointer<INotebookBackend> &Notebook::getBackend() const
{
return m_backend;
@ -176,23 +203,6 @@ const QSharedPointer<Node> &Notebook::getRootNode() const
return m_root;
}
QSharedPointer<Node> Notebook::getRecycleBinNode() const
{
auto root = getRootNode();
const auto &children = root->getChildrenRef();
auto it = std::find_if(children.begin(),
children.end(),
[this](const QSharedPointer<Node> &p_node) {
return isRecycleBinNode(p_node.data());
});
if (it != children.end()) {
return *it;
}
return nullptr;
}
QSharedPointer<Node> Notebook::newNode(Node *p_parent,
Node::Flags p_flags,
const QString &p_name,
@ -259,27 +269,6 @@ void Notebook::removeNode(Node *p_node, bool p_force, bool p_configOnly)
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());
@ -288,59 +277,41 @@ void Notebook::moveNodeToRecycleBin(Node *p_node)
void Notebook::moveNodeToRecycleBin(const QSharedPointer<Node> &p_node)
{
Q_ASSERT(p_node && !p_node->isRoot());
auto destNode = getOrCreateRecycleBinDateNode();
copyNodeAsChildOf(p_node, destNode.data(), true);
m_configMgr->removeNodeToFolder(p_node, getOrCreateRecycleBinDateFolder());
}
QSharedPointer<Node> Notebook::getOrCreateRecycleBinDateNode()
QString Notebook::getOrCreateRecycleBinDateFolder()
{
// 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);
auto dateFolderName = QDate::currentDate().toString(QStringLiteral("yyyyMMdd"));
auto folderPath = PathUtils::concatenateFilePath(getRecycleBinFolder(), dateFolderName);
if (QDir::isAbsolutePath(folderPath)) {
qDebug() << "using absolute recycle bin folder" << folderPath;
QDir dir(folderPath);
if (dir.exists()) {
dir.mkpath(folderPath);
}
} else {
if (!getBackend()->exists(folderPath)) {
getBackend()->makePath(folderPath);
}
}
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);
}
return folderPath;
}
void Notebook::moveFileToRecycleBin(const QString &p_filePath)
{
auto node = getOrCreateRecycleBinDateNode();
auto destFilePath = PathUtils::concatenateFilePath(node->fetchPath(),
PathUtils::fileName(p_filePath));
auto destFilePath = PathUtils::concatenateFilePath(getOrCreateRecycleBinDateFolder(), PathUtils::fileName(p_filePath));
destFilePath = getBackend()->renameIfExistsCaseInsensitive(destFilePath);
m_backend->copyFile(p_filePath, destFilePath);
getBackend()->removeFile(p_filePath);
emit nodeUpdated(node.data());
m_backend->copyFile(p_filePath, destFilePath, true);
}
void Notebook::moveDirToRecycleBin(const QString &p_dirPath)
{
auto node = getOrCreateRecycleBinDateNode();
auto destDirPath = PathUtils::concatenateFilePath(node->fetchPath(),
PathUtils::fileName(p_dirPath));
auto destDirPath = PathUtils::concatenateFilePath(getOrCreateRecycleBinDateFolder(), PathUtils::fileName(p_dirPath));
destDirPath = getBackend()->renameIfExistsCaseInsensitive(destDirPath);
m_backend->copyDir(p_dirPath, destDirPath);
getBackend()->removeDir(p_dirPath);
emit nodeUpdated(node.data());
m_backend->copyDir(p_dirPath, destDirPath, true);
}
QSharedPointer<Node> Notebook::addAsNode(Node *p_parent,
@ -416,3 +387,12 @@ TagI *Notebook::tag()
{
return nullptr;
}
void Notebook::emptyRecycleBin()
{
QDir dir(getRecycleBinFolderAbsolutePath());
auto children = dir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot);
for (const auto &child : children) {
FileUtils::removeDir(dir.filePath(child));
}
}

View File

@ -61,6 +61,10 @@ namespace vnotex
const QString &getAttachmentFolder() const;
const QString &getRecycleBinFolder() const;
QString getRecycleBinFolderAbsolutePath() const;
const QDateTime &getCreatedTimeUtc() const;
const QSharedPointer<INotebookBackend> &getBackend() const;
@ -71,8 +75,6 @@ namespace vnotex
const QSharedPointer<Node> &getRootNode() const;
QSharedPointer<Node> getRecycleBinNode() const;
QSharedPointer<Node> newNode(Node *p_parent,
Node::Flags p_flags,
const QString &p_name,
@ -116,17 +118,11 @@ namespace vnotex
// Move @p_dirPath to the recycle bin, without adding it as a child node.
void moveDirToRecycleBin(const QString &p_dirPath);
virtual void emptyRecycleBin();
// Remove all files of this notebook from disk.
virtual void remove() = 0;
bool isRecycleBinNode(const Node *p_node) const;
bool isNodeInRecycleBin(const Node *p_node) const;
// Remove all children node of @p_node.
// @p_force: if true, just delete all folders and files under @p_node.
void emptyNode(const Node *p_node, bool p_force = false);
// Whether @p_name is a built-in file under @p_node.
bool isBuiltInFile(const Node *p_node, const QString &p_name) const;
@ -150,6 +146,8 @@ namespace vnotex
static const QString c_defaultImageFolder;
static const QString c_defaultRecycleBinFolder;
public:
// Return null if history is not suported.
virtual HistoryI *history();
@ -168,7 +166,7 @@ namespace vnotex
virtual void initializeInternal() = 0;
private:
QSharedPointer<Node> getOrCreateRecycleBinDateNode();
QString getOrCreateRecycleBinDateFolder();
bool m_initialized = false;
@ -196,6 +194,9 @@ namespace vnotex
// Name of the folder to hold attachments.
QString m_attachmentFolder;
// Name or path of the folder to hold deleted files.
QString m_recycleBinFolder;
QDateTime m_createdTimeUtc;
// Backend for file access and synchronization.

View File

@ -83,13 +83,13 @@ namespace vnotex
// Copy @p_filePath to @p_destPath.
// @p_filePath could be outside notebook.
virtual void copyFile(const QString &p_filePath, const QString &p_destPath) = 0;
virtual void copyFile(const QString &p_filePath, const QString &p_destPath, bool p_move = false) = 0;
// Delete @p_filePath from disk.
virtual void removeFile(const QString &p_filePath) = 0;
// Copy @p_dirPath to as @p_destPath.
virtual void copyDir(const QString &p_dirPath, const QString &p_destPath) = 0;
virtual void copyDir(const QString &p_dirPath, const QString &p_destPath, bool p_move = false) = 0;
// Delete @p_dirPath from disk if it is empty.
// Return false if it is not deleted due to non-empty.

View File

@ -123,7 +123,7 @@ void LocalNotebookBackend::renameDir(const QString &p_dirPath, const QString &p_
FileUtils::renameFile(dirPath, p_name);
}
void LocalNotebookBackend::copyFile(const QString &p_filePath, const QString &p_destPath)
void LocalNotebookBackend::copyFile(const QString &p_filePath, const QString &p_destPath, bool p_move)
{
auto filePath = p_filePath;
if (QFileInfo(filePath).isRelative()) {
@ -132,10 +132,10 @@ void LocalNotebookBackend::copyFile(const QString &p_filePath, const QString &p_
Q_ASSERT(QFileInfo(filePath).isFile());
FileUtils::copyFile(filePath, getFullPath(p_destPath));
FileUtils::copyFile(filePath, getFullPath(p_destPath), p_move);
}
void LocalNotebookBackend::copyDir(const QString &p_dirPath, const QString &p_destPath)
void LocalNotebookBackend::copyDir(const QString &p_dirPath, const QString &p_destPath, bool p_move)
{
auto dirPath = p_dirPath;
if (QFileInfo(dirPath).isRelative()) {
@ -144,7 +144,7 @@ void LocalNotebookBackend::copyDir(const QString &p_dirPath, const QString &p_de
Q_ASSERT(QFileInfo(dirPath).isDir());
FileUtils::copyDir(dirPath, getFullPath(p_destPath));
FileUtils::copyDir(dirPath, getFullPath(p_destPath), p_move);
}
void LocalNotebookBackend::removeFile(const QString &p_filePath)

View File

@ -69,10 +69,10 @@ namespace vnotex
// Copy @p_filePath to @p_destPath.
// @p_filePath may beyond this notebook backend.
void copyFile(const QString &p_filePath, const QString &p_destPath) Q_DECL_OVERRIDE;
void copyFile(const QString &p_filePath, const QString &p_destPath, bool p_move = false) Q_DECL_OVERRIDE;
// Copy @p_dirPath to as @p_destPath.
void copyDir(const QString &p_dirPath, const QString &p_destPath) Q_DECL_OVERRIDE;
void copyDir(const QString &p_dirPath, const QString &p_destPath, bool p_move = false) Q_DECL_OVERRIDE;
QString renameIfExistsCaseInsensitive(const QString &p_path) const Q_DECL_OVERRIDE;

View File

@ -95,12 +95,14 @@ bool BundleNotebookConfigMgr::isBuiltInFile(const Node *p_node, const QString &p
bool BundleNotebookConfigMgr::isBuiltInFolder(const Node *p_node, const QString &p_name) const
{
if (p_node->isRoot()) {
return p_name.toLower() == c_configFolderName;
const auto name = p_name.toLower();
return (name == c_configFolderName
|| name == getNotebook()->getRecycleBinFolder().toLower());
}
return false;
}
int BundleNotebookConfigMgr::getCodeVersion() const
{
return 2;
return 3;
}

View File

@ -69,6 +69,8 @@ namespace vnotex
virtual void removeNode(const QSharedPointer<Node> &p_node, bool p_force, bool p_configOnly) = 0;
virtual void removeNodeToFolder(const QSharedPointer<Node> &p_node, const QString &p_destFolder) = 0;
// Whether @p_name is a built-in file under @p_node.
virtual bool isBuiltInFile(const Node *p_node, const QString &p_name) const = 0;

View File

@ -22,6 +22,7 @@
#include <utils/contentmediautils.h>
#include "vxnodeconfig.h"
#include "vxnotebookconfigmgrfactory.h"
using namespace vnotex;
@ -29,19 +30,12 @@ using namespace vnotex::vx_node_config;
const QString VXNotebookConfigMgr::c_nodeConfigName = "vx.json";
const QString VXNotebookConfigMgr::c_recycleBinFolderName = "vx_recycle_bin";
bool VXNotebookConfigMgr::s_initialized = false;
QVector<QRegExp> VXNotebookConfigMgr::s_externalNodeExcludePatterns;
VXNotebookConfigMgr::VXNotebookConfigMgr(const QString &p_name,
const QString &p_displayName,
const QString &p_description,
const QSharedPointer<INotebookBackend> &p_backend,
QObject *p_parent)
: BundleNotebookConfigMgr(p_backend, p_parent),
m_info(p_name, p_displayName, p_description)
VXNotebookConfigMgr::VXNotebookConfigMgr(const QSharedPointer<INotebookBackend> &p_backend, QObject *p_parent)
: BundleNotebookConfigMgr(p_backend, p_parent)
{
if (!s_initialized) {
s_initialized = true;
@ -58,17 +52,17 @@ VXNotebookConfigMgr::VXNotebookConfigMgr(const QString &p_name,
QString VXNotebookConfigMgr::getName() const
{
return m_info.m_name;
return VXNotebookConfigMgrFactory::c_name;
}
QString VXNotebookConfigMgr::getDisplayName() const
{
return m_info.m_displayName;
return VXNotebookConfigMgrFactory::c_displayName;
}
QString VXNotebookConfigMgr::getDescription() const
{
return m_info.m_description;
return VXNotebookConfigMgrFactory::c_description;
}
void VXNotebookConfigMgr::createEmptySkeleton(const NotebookParameters &p_paras)
@ -97,29 +91,21 @@ QSharedPointer<Node> VXNotebookConfigMgr::loadRootNode()
root->setExists(true);
Q_ASSERT(root->isLoaded());
if (!markRecycleBinNode(root)) {
const_cast<VXNotebookConfigMgr *>(this)->createRecycleBinNode(root);
if (static_cast<BundleNotebook *>(getNotebook())->getConfigVersion() < 3) {
removeLegacyRecycleBinNode(root);
}
return root;
}
bool VXNotebookConfigMgr::markRecycleBinNode(const QSharedPointer<Node> &p_root)
void VXNotebookConfigMgr::removeLegacyRecycleBinNode(const QSharedPointer<Node> &p_root)
{
auto node = p_root->findChild(c_recycleBinFolderName,
// Do not support recycle bin node as it complicates everything.
auto node = p_root->findChild(QStringLiteral("vx_recycle_bin"),
FileUtils::isPlatformNameCaseSensitive());
if (node) {
if (!node->exists()) {
removeNode(node, true, true);
return false;
}
node->setUse(Node::Use::RecycleBin);
markNodeReadOnly(node.data());
return true;
removeNode(node, true, true);
}
return false;
}
void VXNotebookConfigMgr::markNodeReadOnly(Node *p_node) const
@ -134,15 +120,6 @@ void VXNotebookConfigMgr::markNodeReadOnly(Node *p_node) const
}
}
void VXNotebookConfigMgr::createRecycleBinNode(const QSharedPointer<Node> &p_root)
{
Q_ASSERT(p_root->isRoot());
auto node = newNode(p_root.data(), Node::Flag::Container, c_recycleBinFolderName, "");
node->setUse(Node::Use::RecycleBin);
markNodeReadOnly(node.data());
}
QSharedPointer<NodeConfig> VXNotebookConfigMgr::readNodeConfig(const QString &p_path) const
{
auto backend = getBackend();
@ -314,6 +291,13 @@ QSharedPointer<Node> VXNotebookConfigMgr::newFileNode(Node *p_parent,
// Write empty file.
if (p_create) {
if (getBackend()->childExistsCaseInsensitive(p_parent->fetchPath(), p_name)) {
// File already exists. Exception.
Exception::throwOne(Exception::Type::FileExistsOnCreate,
QString("file (%1) already exists when creating new node").arg(node->fetchPath()));
return nullptr;
}
getBackend()->writeFile(node->fetchPath(), p_content);
node->setExists(true);
} else {
@ -343,6 +327,13 @@ QSharedPointer<Node> VXNotebookConfigMgr::newFolderNode(Node *p_parent,
// Make folder.
if (p_create) {
if (getBackend()->childExistsCaseInsensitive(p_parent->fetchPath(), p_name)) {
// Dir already exists. Exception.
Exception::throwOne(Exception::Type::DirExistsOnCreate,
QString("dir (%1) already exists when creating new node").arg(node->fetchPath()));
return nullptr;
}
getBackend()->makePath(node->fetchPath());
node->setExists(true);
} else {
@ -513,22 +504,9 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyFileNodeAsChildOf(const QSharedPoi
bool p_move,
bool p_updateDatabase)
{
// Copy source file itself.
auto srcFilePath = p_src->fetchAbsolutePath();
auto destFilePath = PathUtils::concatenateFilePath(p_dest->fetchPath(),
PathUtils::fileName(srcFilePath));
destFilePath = getBackend()->renameIfExistsCaseInsensitive(destFilePath);
getBackend()->copyFile(srcFilePath, destFilePath);
// Copy media files fetched from content.
ContentMediaUtils::copyMediaFiles(p_src.data(), getBackend().data(), destFilePath);
// Copy attachment folder. Rename attachment folder if conflicts.
QString attachmentFolder = p_src->getAttachmentFolder();
if (!attachmentFolder.isEmpty()) {
auto destAttachmentFolderPath = fetchNodeAttachmentFolder(destFilePath, attachmentFolder);
ContentMediaUtils::copyAttachment(p_src.data(), getBackend().data(), destFilePath, destAttachmentFolderPath);
}
QString destFilePath;
QString attachmentFolder;
copyFilesOfFileNode(p_src, p_dest->fetchPath(), destFilePath, attachmentFolder);
// Create a file node.
auto notebook = getNotebook();
@ -571,7 +549,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyFileNodeAsChildOf(const QSharedPoi
if (p_move) {
if (sameNotebook) {
// The same notebook. Do not directly call removeNode() since we need to update the record
// The same notebook. Do not directly call removeNode() since we already update the record
// in database directly.
removeNode(p_src, false, false, false);
} else {
@ -587,9 +565,7 @@ QSharedPointer<Node> VXNotebookConfigMgr::copyFolderNodeAsChildOf(const QSharedP
bool p_move,
bool p_updateDatabase)
{
auto srcFolderPath = p_src->fetchAbsolutePath();
auto destFolderPath = PathUtils::concatenateFilePath(p_dest->fetchPath(),
PathUtils::fileName(srcFolderPath));
auto destFolderPath = PathUtils::concatenateFilePath(p_dest->fetchPath(), p_src->getName());
destFolderPath = getBackend()->renameIfExistsCaseInsensitive(destFolderPath);
// Make folder.
@ -662,7 +638,6 @@ void VXNotebookConfigMgr::removeNode(const QSharedPointer<Node> &p_node,
bool p_configOnly,
bool p_updateDatabase)
{
auto parentNode = p_node->getParent();
if (!p_configOnly && p_node->exists()) {
// Remove all children.
auto children = p_node->getChildren();
@ -683,7 +658,7 @@ void VXNotebookConfigMgr::removeNode(const QSharedPointer<Node> &p_node,
removeNodeFromDatabase(p_node.data());
}
if (parentNode) {
if (auto parentNode = p_node->getParent()) {
parentNode->removeChild(p_node);
writeNodeConfig(parentNode);
}
@ -722,10 +697,74 @@ void VXNotebookConfigMgr::removeFilesOfNode(Node *p_node, bool p_force)
}
}
void VXNotebookConfigMgr::removeNodeToFolder(const QSharedPointer<Node> &p_node, const QString &p_destFolder)
{
if (p_node->isContainer()) {
removeFolderNodeToFolder(p_node, p_destFolder);
} else {
removeFileNodeToFolder(p_node, p_destFolder);
}
}
void VXNotebookConfigMgr::removeFolderNodeToFolder(const QSharedPointer<Node> &p_node, const QString &p_destFolder)
{
auto destFolderPath = PathUtils::concatenateFilePath(p_destFolder, p_node->getName());
destFolderPath = getBackend()->renameIfExistsCaseInsensitive(destFolderPath);
// Make folder.
getBackend()->makePath(destFolderPath);
// Children.
auto children = p_node->getChildren();
for (const auto &child : children) {
removeNodeToFolder(child, destFolderPath);
}
removeNode(p_node, false, false);
}
void VXNotebookConfigMgr::removeFileNodeToFolder(const QSharedPointer<Node> &p_node, const QString &p_destFolder)
{
// Use a wrapper folder.
auto destFolderPath = PathUtils::concatenateFilePath(p_destFolder, p_node->getName());
destFolderPath = getBackend()->renameIfExistsCaseInsensitive(destFolderPath);
// Make folder.
getBackend()->makePath(destFolderPath);
QString destFilePath;
QString attachmentFolder;
copyFilesOfFileNode(p_node, destFolderPath, destFilePath, attachmentFolder);
removeNode(p_node, false, false);
}
void VXNotebookConfigMgr::copyFilesOfFileNode(const QSharedPointer<Node> &p_node,
const QString &p_destFolder,
QString &p_destFilePath,
QString &p_attachmentFolder)
{
// Copy source file itself.
auto nodeFilePath = p_node->fetchAbsolutePath();
p_destFilePath = PathUtils::concatenateFilePath(p_destFolder, PathUtils::fileName(nodeFilePath));
p_destFilePath = getBackend()->renameIfExistsCaseInsensitive(p_destFilePath);
getBackend()->copyFile(nodeFilePath, p_destFilePath);
// Copy media files fetched from content.
ContentMediaUtils::copyMediaFiles(p_node.data(), getBackend().data(), p_destFilePath);
// Copy attachment folder. Rename attachment folder if conflicts.
p_attachmentFolder = p_node->getAttachmentFolder();
if (!p_attachmentFolder.isEmpty()) {
auto destAttachmentFolderPath = fetchNodeAttachmentFolder(p_destFilePath, p_attachmentFolder);
ContentMediaUtils::copyAttachment(p_node.data(), getBackend().data(), p_destFilePath, destAttachmentFolderPath);
}
}
QString VXNotebookConfigMgr::fetchNodeImageFolderPath(Node *p_node)
{
auto pa = PathUtils::concatenateFilePath(PathUtils::parentDirPath(p_node->fetchAbsolutePath()),
getNotebook()->getImageFolder());
getNotebook()->getImageFolder());
// Do not make the folder when it is a folder node request.
if (p_node->hasContent()) {
getBackend()->makePath(pa);
@ -736,7 +775,7 @@ QString VXNotebookConfigMgr::fetchNodeImageFolderPath(Node *p_node)
QString VXNotebookConfigMgr::fetchNodeAttachmentFolderPath(Node *p_node)
{
auto notebookFolder = PathUtils::concatenateFilePath(PathUtils::parentDirPath(p_node->fetchAbsolutePath()),
getNotebook()->getAttachmentFolder());
getNotebook()->getAttachmentFolder());
if (p_node->hasContent()) {
auto nodeFolder = p_node->getAttachmentFolder();
if (nodeFolder.isEmpty()) {
@ -783,9 +822,9 @@ bool VXNotebookConfigMgr::isBuiltInFile(const Node *p_node, const QString &p_nam
bool VXNotebookConfigMgr::isBuiltInFolder(const Node *p_node, const QString &p_name) const
{
const auto name = p_name.toLower();
if (name == c_recycleBinFolderName
|| name == getNotebook()->getImageFolder().toLower()
|| name == getNotebook()->getAttachmentFolder().toLower()
const auto &nb = getNotebook();
if (name == nb->getImageFolder().toLower()
|| name == nb->getAttachmentFolder().toLower()
|| name == QStringLiteral("_v_images")
|| name == QStringLiteral("_v_attachments")) {
return true;
@ -946,7 +985,7 @@ bool VXNotebookConfigMgr::checkNodeExists(Node *p_node)
QStringList VXNotebookConfigMgr::scanAndImportExternalFiles(Node *p_node)
{
QStringList files;
if (!p_node->isContainer() || p_node->getUse() == Node::Use::RecycleBin) {
if (!p_node->isContainer()) {
return files;
}

View File

@ -27,11 +27,7 @@ namespace vnotex
{
Q_OBJECT
public:
explicit VXNotebookConfigMgr(const QString &p_name,
const QString &p_displayName,
const QString &p_description,
const QSharedPointer<INotebookBackend> &p_backend,
QObject *p_parent = nullptr);
VXNotebookConfigMgr(const QSharedPointer<INotebookBackend> &p_backend, QObject *p_parent = nullptr);
QString getName() const Q_DECL_OVERRIDE;
@ -71,6 +67,8 @@ namespace vnotex
void removeNode(const QSharedPointer<Node> &p_node, bool p_force = false, bool p_configOnly = false) Q_DECL_OVERRIDE;
void removeNodeToFolder(const QSharedPointer<Node> &p_node, const QString &p_destFolder) Q_DECL_OVERRIDE;
bool isBuiltInFile(const Node *p_node, const QString &p_name) const Q_DECL_OVERRIDE;
bool isBuiltInFolder(const Node *p_node, const QString &p_name) const Q_DECL_OVERRIDE;
@ -137,11 +135,9 @@ namespace vnotex
void removeFilesOfNode(Node *p_node, bool p_force);
bool markRecycleBinNode(const QSharedPointer<Node> &p_root);
void markNodeReadOnly(Node *p_node) const;
void createRecycleBinNode(const QSharedPointer<Node> &p_root);
void removeLegacyRecycleBinNode(const QSharedPointer<Node> &p_root);
// Generate node attachment folder.
// @p_folderName: suggested folder name if not empty, may be renamed due to conflicts.
@ -171,9 +167,16 @@ namespace vnotex
bool sameNotebook(const Node *p_node) const;
static bool isLikelyImageFolder(const QString &p_dirPath);
void removeFolderNodeToFolder(const QSharedPointer<Node> &p_node, const QString &p_destFolder);
Info m_info;
void removeFileNodeToFolder(const QSharedPointer<Node> &p_node, const QString &p_destFolder);
void copyFilesOfFileNode(const QSharedPointer<Node> &p_node,
const QString &p_destFolder,
QString &p_destFilePath,
QString &p_attachmentFolder);
static bool isLikelyImageFolder(const QString &p_dirPath);
static bool s_initialized;
@ -181,9 +184,6 @@ namespace vnotex
// Name of the node's config file.
static const QString c_nodeConfigName;
// Name of the recycle bin folder which should be a child of the root node.
static const QString c_recycleBinFolderName;
};
} // ns vnotex

View File

@ -7,29 +7,32 @@
using namespace vnotex;
const QString VXNotebookConfigMgrFactory::c_name = QStringLiteral("vx.vnotex");
const QString VXNotebookConfigMgrFactory::c_displayName = QObject::tr("VNoteX Notebook Configuration");
const QString VXNotebookConfigMgrFactory::c_description = QObject::tr("Built-in VNoteX notebook configuration");
VXNotebookConfigMgrFactory::VXNotebookConfigMgrFactory()
{
}
QString VXNotebookConfigMgrFactory::getName() const
{
return QStringLiteral("vx.vnotex");
return c_name;
}
QString VXNotebookConfigMgrFactory::getDisplayName() const
{
return QObject::tr("VNoteX Notebook Configuration");
return c_displayName;
}
QString VXNotebookConfigMgrFactory::getDescription() const
{
return QObject::tr("Built-in VNoteX notebook configuration");
return c_description;
}
QSharedPointer<INotebookConfigMgr> VXNotebookConfigMgrFactory::createNotebookConfigMgr(const QSharedPointer<INotebookBackend> &p_backend)
{
return QSharedPointer<VXNotebookConfigMgr>::create(getName(),
getDisplayName(),
getDescription(),
p_backend);
return QSharedPointer<VXNotebookConfigMgr>::create(p_backend);
}

View File

@ -19,6 +19,12 @@ namespace vnotex
QString getDescription()const Q_DECL_OVERRIDE;
QSharedPointer<INotebookConfigMgr> createNotebookConfigMgr(const QSharedPointer<INotebookBackend> &p_backend) Q_DECL_OVERRIDE;
static const QString c_name;
static const QString c_displayName;
static const QString c_description;
};
} // ns vnotex

View File

@ -114,11 +114,7 @@ void SessionConfig::loadCore(const QJsonObject &p_session)
if (!isUndefinedKey(coreObj, QStringLiteral("system_title_bar"))) {
m_systemTitleBarEnabled = readBool(coreObj, QStringLiteral("system_title_bar"));
} else {
#ifdef Q_OS_WIN
m_systemTitleBarEnabled = false;
#else
m_systemTitleBarEnabled = true;
#endif
}
if (!isUndefinedKey(coreObj, QStringLiteral("minimize_to_system_tray"))) {
@ -318,9 +314,6 @@ void SessionConfig::doVersionSpecificOverride()
{
// In a new version, we may want to change one value by force.
// SHOULD set the in memory variable only, or will override the notebook list.
#ifdef Q_OS_WIN
m_systemTitleBarEnabled = false;
#endif
}
const ExportOption &SessionConfig::getExportOption() const

View File

@ -31,7 +31,6 @@ void WidgetConfig::init(const QJsonObject &p_app,
{
m_nodeExplorerViewOrder = READINT(QStringLiteral("node_explorer_view_order"));
m_nodeExplorerRecycleBinNodeVisible = READBOOL(QStringLiteral("node_explorer_recycle_bin_node_visible"));
m_nodeExplorerExternalFilesVisible = READBOOL(QStringLiteral("node_explorer_external_files_visible"));
m_nodeExplorerAutoImportExternalFilesEnabled = READBOOL(QStringLiteral("node_explorer_auto_import_external_files_enabled"));
m_nodeExplorerCloseBeforeOpenWithEnabled = READBOOL(QStringLiteral("node_explorer_close_before_open_with_enabled"));
@ -55,7 +54,6 @@ QJsonObject WidgetConfig::toJson() const
obj[QStringLiteral("find_and_replace_options")] = static_cast<int>(m_findAndReplaceOptions);
obj[QStringLiteral("node_explorer_view_order")] = m_nodeExplorerViewOrder;
obj[QStringLiteral("node_explorer_recycle_bin_node_visible")] = m_nodeExplorerRecycleBinNodeVisible;
obj[QStringLiteral("node_explorer_external_files_visible")] = m_nodeExplorerExternalFilesVisible;
obj[QStringLiteral("node_explorer_auto_import_external_files_enabled")] = m_nodeExplorerAutoImportExternalFilesEnabled;
obj[QStringLiteral("node_explorer_close_before_open_with_enabled")] = m_nodeExplorerCloseBeforeOpenWithEnabled;
@ -108,16 +106,6 @@ void WidgetConfig::setNodeExplorerViewOrder(int p_viewOrder)
updateConfig(m_nodeExplorerViewOrder, p_viewOrder, this);
}
bool WidgetConfig::isNodeExplorerRecycleBinNodeVisible() const
{
return m_nodeExplorerRecycleBinNodeVisible;
}
void WidgetConfig::setNodeExplorerRecycleBinNodeVisible(bool p_visible)
{
updateConfig(m_nodeExplorerRecycleBinNodeVisible, p_visible, this);
}
bool WidgetConfig::isNodeExplorerExternalFilesVisible() const
{
return m_nodeExplorerExternalFilesVisible;

View File

@ -30,9 +30,6 @@ namespace vnotex
int getNodeExplorerViewOrder() const;
void setNodeExplorerViewOrder(int p_viewOrder);
bool isNodeExplorerRecycleBinNodeVisible() const;
void setNodeExplorerRecycleBinNodeVisible(bool p_visible);
bool isNodeExplorerExternalFilesVisible() const;
void setNodeExplorerExternalFilesVisible(bool p_visible);
@ -63,8 +60,6 @@ namespace vnotex
int m_nodeExplorerViewOrder = 0;
bool m_nodeExplorerRecycleBinNodeVisible = false;
bool m_nodeExplorerExternalFilesVisible = true;
bool m_nodeExplorerAutoImportExternalFilesEnabled = true;

View File

@ -373,7 +373,6 @@
"find_and_replace_options" : 16,
"//comment" : "View order of the node explorer",
"node_explorer_view_order" : 0,
"node_explorer_recycle_bin_node_visible" : false,
"node_explorer_external_files_visible" : true,
"node_explorer_auto_import_external_files_enabled" : true,
"//comment" : "Whether close the file before opening it with external program",

View File

@ -470,11 +470,6 @@ bool Searcher::firstPhaseSearch(Notebook *p_notebook, QVector<SearchSecondPhaseI
return true;
}
if (p_notebook->isRecycleBinNode(child.data())) {
qDebug() << "skipped searching recycle bin";
continue;
}
if (child->hasContent() && testTarget(SearchTarget::SearchFile)) {
if (!firstPhaseSearch(child.data(), p_secondPhaseItems)) {
return false;

View File

@ -118,7 +118,7 @@ void FileUtils::copyFile(const QString &p_filePath,
QDir dir;
if (!dir.mkpath(PathUtils::parentDirPath(p_destPath))) {
Exception::throwOne(Exception::Type::FailToCreateDir,
QString("failed to create directory: %1").arg(PathUtils::parentDirPath(p_destPath)));
QString("failed to create directory: %1").arg(PathUtils::parentDirPath(p_destPath)));
}
bool failed = false;

View File

@ -260,7 +260,7 @@ void ManageNotebooksDialog::closeNotebook(const Notebook *p_notebook)
int ret = MessageBoxHelper::questionOkCancel(MessageBoxHelper::Question,
tr("Close notebook (%1)?")
.arg(p_notebook->getName()),
tr("The notebook could be imported again later."),
tr("The notebook could be opened by VNote again."),
tr("Notebook location: %1").arg(p_notebook->getRootFolderAbsolutePath()),
this);
if (ret != QMessageBox::Ok) {
@ -289,14 +289,18 @@ void ManageNotebooksDialog::removeNotebook(const Notebook *p_notebook)
int ret = MessageBoxHelper::questionOkCancel(MessageBoxHelper::Warning,
tr("Please close the notebook in VNote first and delete the notebook root folder files manually."),
tr("Press \"Ok\" to open the location of the notebook root folder."),
tr("Press \"Ok\" to close the notebook and open the location of the notebook root folder."),
tr("Notebook location: %1").arg(p_notebook->getRootFolderAbsolutePath()),
this);
if (ret != QMessageBox::Ok) {
return;
}
WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(p_notebook->getRootFolderAbsolutePath()));
const auto rootFolder = p_notebook->getRootFolderAbsolutePath();
closeNotebook(p_notebook);
WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(rootFolder));
}
bool ManageNotebooksDialog::checkUnsavedChanges()

View File

@ -57,8 +57,8 @@ bool NewFolderDialog::validateNameInput(QString &p_msg)
return false;
}
if (m_infoWidget->getParentNode()->containsChild(name, false)) {
p_msg = tr("Name conflicts with existing folder.");
if (!m_infoWidget->getParentNode()->isLegalNameForNewChild(name)) {
p_msg = tr("Name conflicts with existing or built-in folder.");
return false;
}

View File

@ -93,8 +93,8 @@ bool NewNoteDialog::validateNameInput(QString &p_msg)
return false;
}
if (m_infoWidget->getParentNode()->containsChild(name, false)) {
p_msg = tr("Name conflicts with existing note.");
if (!m_infoWidget->getParentNode()->isLegalNameForNewChild(name)) {
p_msg = tr("Name conflicts with existing or built-in note.");
return false;
}

View File

@ -629,7 +629,7 @@ void MainWindow::exportNotes()
auto currentNotebook = m_notebookExplorer->currentNotebook().data();
auto viewWindow = m_viewArea->getCurrentViewWindow();
auto folderNode = m_notebookExplorer->currentExploredFolderNode();
if (folderNode && (folderNode->isRoot() || currentNotebook->isRecycleBinNode(folderNode))) {
if (folderNode && (folderNode->isRoot())) {
folderNode = nullptr;
}
auto noteNode = m_notebookExplorer->currentExploredNode();

View File

@ -81,7 +81,6 @@ void NotebookExplorer::setupUI()
const auto &widgetConfig = ConfigMgr::getInst().getWidgetConfig();
m_nodeExplorer = new NotebookNodeExplorer(this);
m_nodeExplorer->setRecycleBinNodeVisible(widgetConfig.isNodeExplorerRecycleBinNodeVisible());
m_nodeExplorer->setViewOrder(widgetConfig.getNodeExplorerViewOrder());
m_nodeExplorer->setExternalFilesVisible(widgetConfig.isNodeExplorerExternalFilesVisible());
connect(m_nodeExplorer, &NotebookNodeExplorer::nodeActivated,
@ -122,15 +121,9 @@ TitleBar *NotebookExplorer::setupTitleBar(QWidget *p_parent)
}
{
auto btn = titleBar->addActionButton(QStringLiteral("recycle_bin.svg"), tr("Toggle Recycle Bin Node"));
btn->defaultAction()->setCheckable(true);
btn->defaultAction()->setChecked(widgetConfig.isNodeExplorerRecycleBinNodeVisible());
connect(btn, &QToolButton::triggered,
this, [this](QAction *p_act) {
const bool checked = p_act->isChecked();
ConfigMgr::getInst().getWidgetConfig().setNodeExplorerRecycleBinNodeVisible(checked);
m_nodeExplorer->setRecycleBinNodeVisible(checked);
});
auto recycleBinMenu = WidgetsFactory::createMenu(titleBar);
setupRecycleBinMenu(recycleBinMenu);
titleBar->addActionButton(QStringLiteral("recycle_bin.svg"), tr("Recycle Bin"), recycleBinMenu);
}
{
@ -260,15 +253,6 @@ void NotebookExplorer::newFolder()
return;
}
if (m_currentNotebook->isRecycleBinNode(node)) {
node = m_currentNotebook->getRootNode().data();
} else if (m_currentNotebook->isNodeInRecycleBin(node)) {
MessageBoxHelper::notify(MessageBoxHelper::Information,
tr("Could not create folder within Recycle Bin."),
VNoteX::getInst().getMainWindow());
return;
}
NewFolderDialog dialog(node, VNoteX::getInst().getMainWindow());
if (dialog.exec() == QDialog::Accepted) {
m_nodeExplorer->setCurrentNode(dialog.getNewNode().data());
@ -282,15 +266,6 @@ void NotebookExplorer::newNote()
return;
}
if (m_currentNotebook->isRecycleBinNode(node)) {
node = m_currentNotebook->getRootNode().data();
} else if (m_currentNotebook->isNodeInRecycleBin(node)) {
MessageBoxHelper::notify(MessageBoxHelper::Information,
tr("Could not create note within Recycle Bin."),
VNoteX::getInst().getMainWindow());
return;
}
NewNoteDialog dialog(node, VNoteX::getInst().getMainWindow());
if (dialog.exec() == QDialog::Accepted) {
m_nodeExplorer->setCurrentNode(dialog.getNewNode().data());
@ -340,15 +315,6 @@ void NotebookExplorer::importFile()
return;
}
if (m_currentNotebook->isRecycleBinNode(node)) {
node = m_currentNotebook->getRootNode().data();
} else if (m_currentNotebook->isNodeInRecycleBin(node)) {
MessageBoxHelper::notify(MessageBoxHelper::Information,
tr("Could not create note within Recycle Bin."),
VNoteX::getInst().getMainWindow());
return;
}
static QString lastFolderPath = QDir::homePath();
QStringList files = QFileDialog::getOpenFileNames(VNoteX::getInst().getMainWindow(),
tr("Select Files To Import"),
@ -381,15 +347,6 @@ void NotebookExplorer::importFolder()
return;
}
if (m_currentNotebook->isRecycleBinNode(node)) {
node = m_currentNotebook->getRootNode().data();
} else if (m_currentNotebook->isNodeInRecycleBin(node)) {
MessageBoxHelper::notify(MessageBoxHelper::Information,
tr("Could not create folder within Recycle Bin."),
VNoteX::getInst().getMainWindow());
return;
}
ImportFolderDialog dialog(node, VNoteX::getInst().getMainWindow());
if (dialog.exec() == QDialog::Accepted) {
m_nodeExplorer->setCurrentNode(dialog.getNewNode().data());
@ -483,6 +440,33 @@ void NotebookExplorer::setupViewMenu(QMenu *p_menu)
});
}
void NotebookExplorer::setupRecycleBinMenu(QMenu *p_menu)
{
p_menu->addAction(tr("Open Recycle Bin"),
this,
[this]() {
if (m_currentNotebook) {
WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(m_currentNotebook->getRecycleBinFolderAbsolutePath()));
}
});
p_menu->addAction(tr("Empty Recycle Bin"),
this,
[this]() {
if (!m_currentNotebook) {
return;
}
int okRet = MessageBoxHelper::questionOkCancel(MessageBoxHelper::Warning,
tr("Empty the recycle bin of notebook (%1)?").arg(m_currentNotebook->getName()),
tr("CAUTION! All the files under the recycle bin folder will be deleted and unrecoverable!"),
tr("Recycle bin folder: %1").arg(m_currentNotebook->getRecycleBinFolderAbsolutePath()),
VNoteX::getInst().getMainWindow());
if (okRet == QMessageBox::Ok) {
m_currentNotebook->emptyRecycleBin();
}
});
}
void NotebookExplorer::saveSession()
{
updateSession();

View File

@ -69,6 +69,8 @@ namespace vnotex
void setupViewMenu(QMenu *p_menu);
void setupRecycleBinMenu(QMenu *p_menu);
void saveSession();
void loadSession();

View File

@ -192,13 +192,11 @@ void NotebookNodeExplorer::initNodeIcons() const
const QString folderIconName("folder_node.svg");
const QString fileIconName("file_node.svg");
const QString recycleBinIconName("recycle_bin.svg");
s_nodeIcons[NodeIcon::FolderNode] = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), fg);
s_nodeIcons[NodeIcon::FileNode] = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), fg);
s_nodeIcons[NodeIcon::InvalidFolderNode] = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), invalidFg);
s_nodeIcons[NodeIcon::InvalidFileNode] = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), invalidFg);
s_nodeIcons[NodeIcon::RecycleBinNode] = IconUtils::fetchIcon(themeMgr.getIconFile(recycleBinIconName), fg);
s_nodeIcons[NodeIcon::ExternalFolderNode] = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), externalFg);
s_nodeIcons[NodeIcon::ExternalFileNode] = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), externalFg);
}
@ -341,7 +339,6 @@ void NotebookNodeExplorer::generateNodeTree()
if (currentNode) {
setCurrentNode(currentNode);
} else {
// Do not focus the recycle bin.
focusNormalNode();
}
@ -352,12 +349,6 @@ void NotebookNodeExplorer::loadRootNode(const Node *p_node) const
{
Q_ASSERT(p_node->isLoaded() && p_node->isContainer());
// Render recycle bin node first.
auto recycleBinNode = m_notebook->getRecycleBinNode();
if (recycleBinNode) {
loadRecycleBinNode(recycleBinNode.data());
}
// External children.
if (m_externalFilesVisible) {
auto externalChildren = p_node->fetchExternalChildren();
@ -372,10 +363,6 @@ void NotebookNodeExplorer::loadRootNode(const Node *p_node) const
auto children = p_node->getChildren();
sortNodes(children);
for (const auto &child : children) {
if (recycleBinNode == child) {
continue;
}
auto item = new QTreeWidgetItem(m_masterExplorer);
loadNode(item, child.data(), 1);
}
@ -444,43 +431,6 @@ void NotebookNodeExplorer::loadChildren(QTreeWidgetItem *p_item, Node *p_node, i
}
}
void NotebookNodeExplorer::loadRecycleBinNode(Node *p_node) const
{
if (!m_recycleBinNodeVisible) {
return;
}
auto item = new QTreeWidgetItem();
item->setWhatsThis(Column::Name,
tr("Recycle bin of this notebook. Deleted files could be found here. "
"It is organized in folders named by date. Nodes could be moved to "
"other folders by Cut and Paste."));
m_masterExplorer->insertTopLevelItem(0, item);
loadRecycleBinNode(item, p_node, 1);
}
void NotebookNodeExplorer::loadRecycleBinNode(QTreeWidgetItem *p_item, Node *p_node, int p_level) const
{
if (!m_recycleBinNodeVisible) {
return;
}
if (!p_node->isLoaded()) {
p_node->load();
}
clearTreeWigetItemChildren(p_item);
setItemNodeData(p_item, NodeData(p_node, true));
p_item->setText(Column::Name, tr("Recycle Bin"));
p_item->setIcon(Column::Name, getNodeItemIcon(p_node));
loadChildren(p_item, p_node, p_level - 1);
// No need to restore state.
}
void NotebookNodeExplorer::fillTreeItem(QTreeWidgetItem *p_item, Node *p_node, bool p_loaded) const
{
setItemNodeData(p_item, NodeData(p_node, p_loaded));
@ -502,10 +452,6 @@ const QIcon &NotebookNodeExplorer::getNodeItemIcon(const Node *p_node) const
if (p_node->hasContent()) {
return p_node->exists() ? s_nodeIcons[NodeIcon::FileNode] : s_nodeIcons[NodeIcon::InvalidFileNode];
} else {
if (p_node->getUse() == Node::Use::RecycleBin) {
return s_nodeIcons[NodeIcon::RecycleBinNode];
}
return p_node->exists() ? s_nodeIcons[NodeIcon::FolderNode] : s_nodeIcons[NodeIcon::InvalidFolderNode];
}
}
@ -561,20 +507,9 @@ void NotebookNodeExplorer::updateNode(Node *p_node)
if (item) {
bool expanded = item->isExpanded();
item->setExpanded(false);
if (m_notebook->isRecycleBinNode(p_node)) {
loadRecycleBinNode(item, p_node, 1);
} else {
loadNode(item, p_node, 1);
}
loadNode(item, p_node, 1);
item->setExpanded(expanded);
} else {
if (m_notebook->isRecycleBinNode(p_node) && !m_recycleBinNodeVisible) {
// No need to update.
return;
}
saveNotebookTreeState(false);
generateNodeTree();
@ -762,106 +697,63 @@ void NotebookNodeExplorer::createContextMenuOnRoot(QMenu *p_menu)
void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_node)
{
const int selectedSize = m_masterExplorer->selectedItems().size();
if (m_notebook->isRecycleBinNode(p_node)) {
// Recycle bin node.
createAndAddAction(Action::Reload, p_menu);
createAndAddAction(Action::ReloadIndex, p_menu);
createAndAddAction(Action::Open, p_menu);
if (selectedSize == 1) {
createAndAddAction(Action::EmptyRecycleBin, p_menu);
addOpenWithMenu(p_menu);
createAndAddAction(Action::OpenLocation, p_menu);
}
} else if (m_notebook->isNodeInRecycleBin(p_node)) {
// Node in recycle bin.
createAndAddAction(Action::Open, p_menu);
p_menu->addSeparator();
addOpenWithMenu(p_menu);
if (selectedSize == 1 && p_node->isContainer()) {
createAndAddAction(Action::ExpandAll, p_menu);
}
p_menu->addSeparator();
createAndAddAction(Action::NewNote, p_menu);
createAndAddAction(Action::NewFolder, p_menu);
p_menu->addSeparator();
createAndAddAction(Action::Copy, p_menu);
createAndAddAction(Action::Cut, p_menu);
if (selectedSize == 1 && isPasteOnNodeAvailable(p_node)) {
createAndAddAction(Action::Paste, p_menu);
}
createAndAddAction(Action::Delete, p_menu);
createAndAddAction(Action::RemoveFromConfig, p_menu);
p_menu->addSeparator();
createAndAddAction(Action::Reload, p_menu);
createAndAddAction(Action::ReloadIndex, p_menu);
createAndAddAction(Action::Sort, p_menu);
if (selectedSize == 1
&& m_notebook->tag()
&& !p_node->isContainer()) {
p_menu->addSeparator();
if (selectedSize == 1 && p_node->isContainer()) {
createAndAddAction(Action::ExpandAll, p_menu);
}
createAndAddAction(Action::Tag, p_menu);
}
p_menu->addSeparator();
p_menu->addSeparator();
createAndAddAction(Action::Cut, p_menu);
createAndAddAction(Action::PinToQuickAccess, p_menu);
createAndAddAction(Action::DeleteFromRecycleBin, p_menu);
if (selectedSize == 1) {
createAndAddAction(Action::CopyPath, p_menu);
p_menu->addSeparator();
createAndAddAction(Action::OpenLocation, p_menu);
createAndAddAction(Action::Reload, p_menu);
createAndAddAction(Action::ReloadIndex, p_menu);
if (selectedSize == 1) {
p_menu->addSeparator();
createAndAddAction(Action::CopyPath, p_menu);
createAndAddAction(Action::OpenLocation, p_menu);
}
} else {
createAndAddAction(Action::Open, p_menu);
addOpenWithMenu(p_menu);
p_menu->addSeparator();
if (selectedSize == 1 && p_node->isContainer()) {
createAndAddAction(Action::ExpandAll, p_menu);
}
p_menu->addSeparator();
createAndAddAction(Action::NewNote, p_menu);
createAndAddAction(Action::NewFolder, p_menu);
p_menu->addSeparator();
createAndAddAction(Action::Copy, p_menu);
createAndAddAction(Action::Cut, p_menu);
if (selectedSize == 1 && isPasteOnNodeAvailable(p_node)) {
createAndAddAction(Action::Paste, p_menu);
}
createAndAddAction(Action::Delete, p_menu);
createAndAddAction(Action::RemoveFromConfig, p_menu);
p_menu->addSeparator();
createAndAddAction(Action::Reload, p_menu);
createAndAddAction(Action::ReloadIndex, p_menu);
createAndAddAction(Action::Sort, p_menu);
if (selectedSize == 1
&& m_notebook->tag()
&& !p_node->isContainer()) {
p_menu->addSeparator();
createAndAddAction(Action::Tag, p_menu);
}
p_menu->addSeparator();
createAndAddAction(Action::PinToQuickAccess, p_menu);
if (selectedSize == 1) {
createAndAddAction(Action::CopyPath, p_menu);
createAndAddAction(Action::OpenLocation, p_menu);
createAndAddAction(Action::Properties, p_menu);
}
createAndAddAction(Action::Properties, p_menu);
}
}
@ -901,7 +793,7 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
switch (p_act) {
case Action::NewNote:
act = new QAction(generateMenuActionIcon("new_note.svg"),
tr("New N&ote"),
tr("New &Note"),
p_parent);
connect(act, &QAction::triggered,
this, []() {
@ -1033,47 +925,10 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
});
break;
case Action::EmptyRecycleBin:
act = new QAction(tr("&Empty"), p_parent);
connect(act, &QAction::triggered,
this, [this]() {
auto rbNode = m_notebook->getRecycleBinNode().data();
auto rbNodePath = rbNode->fetchAbsolutePath();
int ret = MessageBoxHelper::questionOkCancel(MessageBoxHelper::Warning,
tr("Empty the recycle bin of this notebook?"),
tr("All files in recycle bin will be deleted permanently."),
tr("Location of recycle bin: %1").arg(rbNodePath));
if (ret != QMessageBox::Ok) {
return;
}
try {
m_notebook->emptyNode(rbNode, true);
} catch (Exception &p_e) {
MessageBoxHelper::notify(MessageBoxHelper::Critical,
tr("Failed to empty recycle bin (%1) (%2).").arg(rbNodePath, p_e.what()),
VNoteX::getInst().getMainWindow());
}
updateNode(rbNode);
});
break;
case Action::Delete:
act = new QAction(tr("&Delete"), p_parent);
connect(act, &QAction::triggered,
this, [this]() {
removeSelectedNodes(false);
});
break;
case Action::DeleteFromRecycleBin:
// It is fine to have &D with Action::Delete since they won't be at the same context.
act = new QAction(tr("&Delete From Recycle Bin"), p_parent);
connect(act, &QAction::triggered,
this, [this]() {
removeSelectedNodes(true);
});
this, &NotebookNodeExplorer::removeSelectedNodes);
break;
case Action::RemoveFromConfig:
@ -1417,21 +1272,12 @@ void NotebookNodeExplorer::selectNodes(const QVector<const Node *> &p_nodes)
}
}
void NotebookNodeExplorer::removeSelectedNodes(bool p_skipRecycleBin)
void NotebookNodeExplorer::removeSelectedNodes()
{
QString text;
QString info;
if (p_skipRecycleBin) {
text = tr("Delete these folders and notes permanently?");
info = tr("Files will be deleted permanently and could not be found even "
"in operating system's recycle bin.");
} else {
text = tr("Delete these folders and notes?");
info = tr("Deleted files could be found in the recycle bin of notebook.");
}
const QString text = tr("Delete these folders and notes?");
const QString info = tr("Deleted files could be found in the recycle bin of notebook.");
auto nodes = confirmSelectedNodes(tr("Confirm Deletion"), text, info);
removeNodes(nodes, p_skipRecycleBin, false);
removeNodes(nodes, false);
}
QVector<Node *> NotebookNodeExplorer::confirmSelectedNodes(const QString &p_title,
@ -1471,9 +1317,7 @@ QVector<Node *> NotebookNodeExplorer::confirmSelectedNodes(const QString &p_titl
return nodesToDelete;
}
void NotebookNodeExplorer::removeNodes(QVector<Node *> p_nodes,
bool p_skipRecycleBin,
bool p_configOnly)
void NotebookNodeExplorer::removeNodes(QVector<Node *> p_nodes, bool p_configOnly)
{
if (p_nodes.isEmpty()) {
return;
@ -1494,8 +1338,8 @@ void NotebookNodeExplorer::removeNodes(QVector<Node *> p_nodes,
continue;
}
if (p_configOnly || p_skipRecycleBin) {
m_notebook->removeNode(node, false, p_configOnly);
if (p_configOnly) {
m_notebook->removeNode(node, false, true);
} else {
m_notebook->moveNodeToRecycleBin(node);
}
@ -1515,10 +1359,6 @@ void NotebookNodeExplorer::removeNodes(QVector<Node *> p_nodes,
updateNode(node);
}
if (!p_configOnly && !p_skipRecycleBin && m_recycleBinNodeVisible) {
updateNode(m_notebook->getRecycleBinNode().data());
}
VNoteX::getInst().showStatusMessageShort(tr("Deleted/Removed %n item(s)", "", nrDeleted));
}
@ -1527,7 +1367,7 @@ void NotebookNodeExplorer::removeSelectedNodesFromConfig()
auto nodes = confirmSelectedNodes(tr("Confirm Removal"),
tr("Remove these folders and notes from index?"),
tr("Files are not touched but just removed from notebook index."));
removeNodes(nodes, false, true);
removeNodes(nodes, true);
}
void NotebookNodeExplorer::filterAwayChildrenNodes(QVector<Node *> &p_nodes)
@ -1569,29 +1409,6 @@ bool NotebookNodeExplorer::allSelectedItemsSameType() const
}
}
if (type == NodeData::NodeType::Node) {
bool hasNormalNode = false;
bool hasNodeInRecycleBin = false;
for (auto &item : items) {
auto node = getItemNodeData(item).getNode();
if (m_notebook->isRecycleBinNode(node)) {
return false;
} else if (m_notebook->isNodeInRecycleBin(node)) {
if (hasNormalNode) {
return false;
}
hasNodeInRecycleBin = true;
} else {
if (hasNodeInRecycleBin) {
return false;
}
hasNormalNode = true;
}
}
}
return true;
}
@ -1603,12 +1420,11 @@ void NotebookNodeExplorer::reload()
void NotebookNodeExplorer::focusNormalNode()
{
auto item = m_masterExplorer->currentItem();
if (item && (!m_recycleBinNodeVisible || item != m_masterExplorer->topLevelItem(0))) {
// Not recycle bin.
if (item) {
return;
}
m_masterExplorer->setCurrentItem(m_masterExplorer->topLevelItem(m_recycleBinNodeVisible ? 1 : 0));
m_masterExplorer->setCurrentItem(m_masterExplorer->topLevelItem(0));
}
void NotebookNodeExplorer::sortNodes(QVector<QSharedPointer<Node>> &p_nodes) const
@ -1688,16 +1504,6 @@ void NotebookNodeExplorer::sortNodes(QVector<QSharedPointer<Node>> &p_nodes, int
}
}
void NotebookNodeExplorer::setRecycleBinNodeVisible(bool p_visible)
{
if (m_recycleBinNodeVisible == p_visible) {
return;
}
m_recycleBinNodeVisible = p_visible;
reload();
}
void NotebookNodeExplorer::setExternalFilesVisible(bool p_visible)
{
if (m_externalFilesVisible == p_visible) {
@ -1748,11 +1554,7 @@ void NotebookNodeExplorer::manualSort()
const auto &children = parentNode->getChildrenRef();
for (int i = 0; i < children.size(); ++i) {
const auto &child = children[i];
if (m_notebook->isRecycleBinNode(child.data())) {
continue;
}
bool selected = sortFolders ? child->isContainer() : !child->isContainer();
const bool selected = sortFolders ? child->isContainer() : !child->isContainer();
if (selected) {
selectedIdx.push_back(i);

View File

@ -103,8 +103,6 @@ namespace vnotex
void reload();
void setRecycleBinNodeVisible(bool p_visible);
void setViewOrder(int p_order);
void setExternalFilesVisible(bool p_visible);
@ -146,9 +144,7 @@ namespace vnotex
Copy,
Cut,
Paste,
EmptyRecycleBin,
Delete,
DeleteFromRecycleBin,
RemoveFromConfig,
Sort,
Reload,
@ -180,10 +176,6 @@ namespace vnotex
void loadNode(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const;
void loadRecycleBinNode(Node *p_node) const;
void loadRecycleBinNode(QTreeWidgetItem *p_item, Node *p_node, int p_level) const;
void fillTreeItem(QTreeWidgetItem *p_item, Node *p_node, bool p_loaded) const;
void fillTreeItem(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const;
@ -225,7 +217,7 @@ namespace vnotex
QPair<QVector<Node *>, QVector<QSharedPointer<ExternalNode>>> getSelectedNodes() const;
void removeSelectedNodes(bool p_skipRecycleBin);
void removeSelectedNodes();
void removeSelectedNodesFromConfig();
@ -241,8 +233,7 @@ namespace vnotex
void selectNodes(const QVector<const Node *> &p_nodes);
// @p_skipRecycleBin is irrelevant if @p_configOnly is true.
void removeNodes(QVector<Node *> p_nodes, bool p_skipRecycleBin, bool p_configOnly);
void removeNodes(QVector<Node *> p_nodes, bool p_configOnly);
void filterAwayChildrenNodes(QVector<Node *> &p_nodes);
@ -251,7 +242,6 @@ namespace vnotex
// Check if all selected items are the same type for operations.
bool allSelectedItemsSameType() const;
// Skip the recycle bin node if possible.
void focusNormalNode();
void sortNodes(QVector<QSharedPointer<Node>> &p_nodes) const;
@ -298,8 +288,6 @@ namespace vnotex
QScopedPointer<NavigationModeWrapper<QTreeWidget, QTreeWidgetItem>> m_navigationWrapper;
bool m_recycleBinNodeVisible = false;
int m_viewOrder = ViewOrder::OrderedByConfiguration;
bool m_externalFilesVisible = true;
@ -312,7 +300,6 @@ namespace vnotex
FileNode,
InvalidFolderNode,
InvalidFileNode,
RecycleBinNode,
ExternalFolderNode,
ExternalFileNode,
MaxIcons

View File

@ -448,7 +448,7 @@ SearchState SearchPanel::search(const QSharedPointer<SearchOption> &p_option)
break;
}
auto folder = m_provider->getCurrentFolder();
if (folder && (folder->isRoot() || notebook->isRecycleBinNode(folder))) {
if (folder && (folder->isRoot())) {
folder = nullptr;
}
if (!folder) {

View File

@ -239,11 +239,6 @@ void TagExplorer::updateNodeList(const QString &p_tag)
continue;
}
if (m_notebook->isNodeInRecycleBin(node.data())) {
qDebug() << "skipped node in recycle bin" << p_tag << pa;
continue;
}
auto item = new QListWidgetItem(m_nodeList);
item->setText(node->getName());
item->setToolTip(NotebookNodeExplorer::generateToolTip(node.data()));