|
@@ -6,9 +6,11 @@
|
|
|
#include <QTreeWidget>
|
|
|
#include <QMenu>
|
|
|
#include <QAction>
|
|
|
+#include <QSet>
|
|
|
|
|
|
#include <notebook/notebook.h>
|
|
|
#include <notebook/node.h>
|
|
|
+#include <notebook/externalnode.h>
|
|
|
#include "exception.h"
|
|
|
#include "messageboxhelper.h"
|
|
|
#include "vnotex.h"
|
|
@@ -29,18 +31,23 @@
|
|
|
#include <core/fileopenparameters.h>
|
|
|
#include <core/events.h>
|
|
|
#include <core/configmgr.h>
|
|
|
-#include <core/widgetconfig.h>
|
|
|
|
|
|
using namespace vnotex;
|
|
|
|
|
|
-const QString NotebookNodeExplorer::c_nodeIconForegroundName = "widgets#notebookexplorer#node_icon#fg";
|
|
|
-
|
|
|
QIcon NotebookNodeExplorer::s_folderNodeIcon;
|
|
|
|
|
|
QIcon NotebookNodeExplorer::s_fileNodeIcon;
|
|
|
|
|
|
+QIcon NotebookNodeExplorer::s_invalidFolderNodeIcon;
|
|
|
+
|
|
|
+QIcon NotebookNodeExplorer::s_invalidFileNodeIcon;
|
|
|
+
|
|
|
QIcon NotebookNodeExplorer::s_recycleBinNodeIcon;
|
|
|
|
|
|
+QIcon NotebookNodeExplorer::s_externalFolderNodeIcon;
|
|
|
+
|
|
|
+QIcon NotebookNodeExplorer::s_externalFileNodeIcon;
|
|
|
+
|
|
|
NotebookNodeExplorer::NodeData::NodeData()
|
|
|
{
|
|
|
}
|
|
@@ -52,9 +59,9 @@ NotebookNodeExplorer::NodeData::NodeData(Node *p_node, bool p_loaded)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
-NotebookNodeExplorer::NodeData::NodeData(const QString &p_name)
|
|
|
- : m_type(NodeType::Attachment),
|
|
|
- m_name(p_name),
|
|
|
+NotebookNodeExplorer::NodeData::NodeData(const QSharedPointer<ExternalNode> &p_externalNode)
|
|
|
+ : m_type(NodeType::ExternalNode),
|
|
|
+ m_externalNode(p_externalNode),
|
|
|
m_loaded(true)
|
|
|
{
|
|
|
}
|
|
@@ -67,13 +74,12 @@ NotebookNodeExplorer::NodeData::NodeData(const NodeData &p_other)
|
|
|
m_node = p_other.m_node;
|
|
|
break;
|
|
|
|
|
|
- case NodeType::Attachment:
|
|
|
- m_name = p_other.m_name;
|
|
|
+ case NodeType::ExternalNode:
|
|
|
+ m_externalNode = p_other.m_externalNode;
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
- m_node = p_other.m_node;
|
|
|
- m_name = p_other.m_name;
|
|
|
+ Q_ASSERT(false);
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -96,13 +102,12 @@ NotebookNodeExplorer::NodeData &NotebookNodeExplorer::NodeData::operator=(const
|
|
|
m_node = p_other.m_node;
|
|
|
break;
|
|
|
|
|
|
- case NodeType::Attachment:
|
|
|
- m_name = p_other.m_name;
|
|
|
+ case NodeType::ExternalNode:
|
|
|
+ m_externalNode = p_other.m_externalNode;
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
- m_node = p_other.m_node;
|
|
|
- m_name = p_other.m_name;
|
|
|
+ Q_ASSERT(false);
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -121,9 +126,9 @@ bool NotebookNodeExplorer::NodeData::isNode() const
|
|
|
return m_type == NodeType::Node;
|
|
|
}
|
|
|
|
|
|
-bool NotebookNodeExplorer::NodeData::isAttachment() const
|
|
|
+bool NotebookNodeExplorer::NodeData::isExternalNode() const
|
|
|
{
|
|
|
- return m_type == NodeType::Attachment;
|
|
|
+ return m_type == NodeType::ExternalNode;
|
|
|
}
|
|
|
|
|
|
NotebookNodeExplorer::NodeData::NodeType NotebookNodeExplorer::NodeData::getType() const
|
|
@@ -137,17 +142,17 @@ Node *NotebookNodeExplorer::NodeData::getNode() const
|
|
|
return m_node;
|
|
|
}
|
|
|
|
|
|
-const QString &NotebookNodeExplorer::NodeData::getName() const
|
|
|
+ExternalNode *NotebookNodeExplorer::NodeData::getExternalNode() const
|
|
|
{
|
|
|
- Q_ASSERT(isAttachment());
|
|
|
- return m_name;
|
|
|
+ Q_ASSERT(isExternalNode());
|
|
|
+ return m_externalNode.data();
|
|
|
}
|
|
|
|
|
|
void NotebookNodeExplorer::NodeData::clear()
|
|
|
{
|
|
|
m_type = NodeType::Invalid;
|
|
|
m_node = nullptr;
|
|
|
- m_name.clear();
|
|
|
+ m_externalNode.clear();
|
|
|
m_loaded = false;
|
|
|
}
|
|
|
|
|
@@ -180,15 +185,26 @@ void NotebookNodeExplorer::initNodeIcons() const
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ const QString nodeIconFgName = "widgets#notebookexplorer#node_icon#fg";
|
|
|
+ const QString invalidNodeIconFgName = "widgets#notebookexplorer#node_icon#invalid#fg";
|
|
|
+ const QString externalNodeIconFgName = "widgets#notebookexplorer#external_node_icon#fg";
|
|
|
+
|
|
|
const auto &themeMgr = VNoteX::getInst().getThemeMgr();
|
|
|
- const auto fg = themeMgr.paletteColor(c_nodeIconForegroundName);
|
|
|
+ const auto fg = themeMgr.paletteColor(nodeIconFgName);
|
|
|
+ const auto invalidFg = themeMgr.paletteColor(invalidNodeIconFgName);
|
|
|
+ const auto externalFg = themeMgr.paletteColor(externalNodeIconFgName);
|
|
|
+
|
|
|
const QString folderIconName("folder_node.svg");
|
|
|
const QString fileIconName("file_node.svg");
|
|
|
const QString recycleBinIconName("recycle_bin.svg");
|
|
|
|
|
|
s_folderNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), fg);
|
|
|
s_fileNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), fg);
|
|
|
+ s_invalidFolderNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), invalidFg);
|
|
|
+ s_invalidFileNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), invalidFg);
|
|
|
s_recycleBinNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(recycleBinIconName), fg);
|
|
|
+ s_externalFolderNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(folderIconName), externalFg);
|
|
|
+ s_externalFileNodeIcon = IconUtils::fetchIcon(themeMgr.getIconFile(fileIconName), externalFg);
|
|
|
}
|
|
|
|
|
|
void NotebookNodeExplorer::setupUI()
|
|
@@ -244,8 +260,8 @@ void NotebookNodeExplorer::setupMasterExplorer(QWidget *p_parent)
|
|
|
|
|
|
if (data.isNode()) {
|
|
|
createContextMenuOnNode(menu.data(), data.getNode());
|
|
|
- } else if (data.isAttachment()) {
|
|
|
- createContextMenuOnAttachment(menu.data(), data.getName());
|
|
|
+ } else if (data.isExternalNode()) {
|
|
|
+ createContextMenuOnExternalNode(menu.data(), data.getExternalNode());
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -263,9 +279,23 @@ void NotebookNodeExplorer::setupMasterExplorer(QWidget *p_parent)
|
|
|
}
|
|
|
|
|
|
if (data.isNode()) {
|
|
|
+ if (checkInvalidNode(data.getNode())) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
emit nodeActivated(data.getNode(), QSharedPointer<FileOpenParameters>::create());
|
|
|
- } else if (data.isAttachment()) {
|
|
|
- // TODO.
|
|
|
+ } else if (data.isExternalNode()) {
|
|
|
+ // Import to config first.
|
|
|
+ if (m_autoImportExternalFiles) {
|
|
|
+ auto importedNode = importToIndex(data.getExternalNode());
|
|
|
+ if (importedNode) {
|
|
|
+ emit nodeActivated(importedNode.data(), QSharedPointer<FileOpenParameters>::create());
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Just open it.
|
|
|
+ emit fileActivated(data.getExternalNode()->fetchAbsolutePath(),
|
|
|
+ QSharedPointer<FileOpenParameters>::create());
|
|
|
}
|
|
|
});
|
|
|
}
|
|
@@ -333,7 +363,7 @@ void NotebookNodeExplorer::generateNodeTree()
|
|
|
|
|
|
void NotebookNodeExplorer::loadRootNode(const Node *p_node) const
|
|
|
{
|
|
|
- Q_ASSERT(p_node->isLoaded());
|
|
|
+ Q_ASSERT(p_node->isLoaded() && p_node->isContainer());
|
|
|
|
|
|
// Render recycle bin node first.
|
|
|
auto recycleBinNode = m_notebook->getRecycleBinNode();
|
|
@@ -341,9 +371,20 @@ void NotebookNodeExplorer::loadRootNode(const Node *p_node) const
|
|
|
loadRecycleBinNode(recycleBinNode.data());
|
|
|
}
|
|
|
|
|
|
+ // External children.
|
|
|
+ if (m_externalFilesVisible) {
|
|
|
+ auto externalChildren = p_node->fetchExternalChildren();
|
|
|
+ // TODO: Sort external children.
|
|
|
+ for (const auto &child : externalChildren) {
|
|
|
+ auto item = new QTreeWidgetItem(m_masterExplorer);
|
|
|
+ loadNode(item, child);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Children.
|
|
|
auto children = p_node->getChildren();
|
|
|
sortNodes(children);
|
|
|
- for (auto &child : children) {
|
|
|
+ for (const auto &child : children) {
|
|
|
if (recycleBinNode == child) {
|
|
|
continue;
|
|
|
}
|
|
@@ -378,15 +419,34 @@ void NotebookNodeExplorer::loadNode(QTreeWidgetItem *p_item, Node *p_node, int p
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void NotebookNodeExplorer::loadNode(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const
|
|
|
+{
|
|
|
+ clearTreeWigetItemChildren(p_item);
|
|
|
+
|
|
|
+ fillTreeItem(p_item, p_node);
|
|
|
+
|
|
|
+ // No children for external node.
|
|
|
+}
|
|
|
+
|
|
|
void NotebookNodeExplorer::loadChildren(QTreeWidgetItem *p_item, Node *p_node, int p_level) const
|
|
|
{
|
|
|
if (p_level < 0) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // External children.
|
|
|
+ if (m_externalFilesVisible && p_node->isContainer()) {
|
|
|
+ auto externalChildren = p_node->fetchExternalChildren();
|
|
|
+ // TODO: Sort external children.
|
|
|
+ for (const auto &child : externalChildren) {
|
|
|
+ auto item = new QTreeWidgetItem(p_item);
|
|
|
+ loadNode(item, child);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
auto children = p_node->getChildren();
|
|
|
sortNodes(children);
|
|
|
- for (auto &child : children) {
|
|
|
+ for (const auto &child : children) {
|
|
|
auto item = new QTreeWidgetItem(p_item);
|
|
|
loadNode(item, child.data(), p_level);
|
|
|
}
|
|
@@ -434,22 +494,33 @@ void NotebookNodeExplorer::fillTreeItem(QTreeWidgetItem *p_item, Node *p_node, b
|
|
|
setItemNodeData(p_item, NodeData(p_node, p_loaded));
|
|
|
p_item->setText(Column::Name, p_node->getName());
|
|
|
p_item->setIcon(Column::Name, getNodeItemIcon(p_node));
|
|
|
- p_item->setToolTip(Column::Name, p_node->getName());
|
|
|
+ p_item->setToolTip(Column::Name, p_node->exists() ? p_node->getName() : (tr("[Invalid] %1").arg(p_node->getName())));
|
|
|
+}
|
|
|
+
|
|
|
+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()));
|
|
|
}
|
|
|
|
|
|
-QIcon NotebookNodeExplorer::getNodeItemIcon(const Node *p_node) const
|
|
|
+const QIcon &NotebookNodeExplorer::getNodeItemIcon(const Node *p_node) const
|
|
|
{
|
|
|
if (p_node->hasContent()) {
|
|
|
- return s_fileNodeIcon;
|
|
|
+ return p_node->exists() ? s_fileNodeIcon : s_invalidFileNodeIcon;
|
|
|
} else {
|
|
|
if (p_node->getUse() == Node::Use::RecycleBin) {
|
|
|
return s_recycleBinNodeIcon;
|
|
|
}
|
|
|
|
|
|
- return s_folderNodeIcon;
|
|
|
+ return p_node->exists() ? s_folderNodeIcon : s_invalidFolderNodeIcon;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- return QIcon();
|
|
|
+const QIcon &NotebookNodeExplorer::getNodeItemIcon(const ExternalNode *p_node) const
|
|
|
+{
|
|
|
+ return p_node->isFolder() ? s_externalFolderNodeIcon : s_externalFileNodeIcon;
|
|
|
}
|
|
|
|
|
|
Node *NotebookNodeExplorer::getCurrentNode() const
|
|
@@ -457,7 +528,7 @@ Node *NotebookNodeExplorer::getCurrentNode() const
|
|
|
auto item = m_masterExplorer->currentItem();
|
|
|
if (item) {
|
|
|
auto data = getItemNodeData(item);
|
|
|
- while (data.isAttachment()) {
|
|
|
+ while (item && !data.isNode()) {
|
|
|
item = item->parent();
|
|
|
if (item) {
|
|
|
data = getItemNodeData(item);
|
|
@@ -687,6 +758,9 @@ void NotebookNodeExplorer::createContextMenuOnRoot(QMenu *p_menu)
|
|
|
|
|
|
p_menu->addSeparator();
|
|
|
|
|
|
+ act = createAction(Action::Reload, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
act = createAction(Action::OpenLocation, p_menu);
|
|
|
p_menu->addAction(act);
|
|
|
}
|
|
@@ -698,6 +772,9 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
|
|
|
|
|
if (m_notebook->isRecycleBinNode(p_node)) {
|
|
|
// Recycle bin node.
|
|
|
+ act = createAction(Action::Reload, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
if (selectedSize == 1) {
|
|
|
act = createAction(Action::EmptyRecycleBin, p_menu);
|
|
|
p_menu->addAction(act);
|
|
@@ -707,12 +784,22 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
|
|
}
|
|
|
} else if (m_notebook->isNodeInRecycleBin(p_node)) {
|
|
|
// Node in recycle bin.
|
|
|
+ act = createAction(Action::Open, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
+ p_menu->addSeparator();
|
|
|
+
|
|
|
act = createAction(Action::Cut, p_menu);
|
|
|
p_menu->addAction(act);
|
|
|
|
|
|
act = createAction(Action::DeleteFromRecycleBin, p_menu);
|
|
|
p_menu->addAction(act);
|
|
|
|
|
|
+ p_menu->addSeparator();
|
|
|
+
|
|
|
+ act = createAction(Action::Reload, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
if (selectedSize == 1) {
|
|
|
p_menu->addSeparator();
|
|
|
|
|
@@ -723,6 +810,11 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
|
|
p_menu->addAction(act);
|
|
|
}
|
|
|
} else {
|
|
|
+ act = createAction(Action::Open, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
+ p_menu->addSeparator();
|
|
|
+
|
|
|
act = createAction(Action::NewNote, p_menu);
|
|
|
p_menu->addAction(act);
|
|
|
|
|
@@ -750,6 +842,9 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
|
|
|
|
|
p_menu->addSeparator();
|
|
|
|
|
|
+ act = createAction(Action::Reload, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
act = createAction(Action::Sort, p_menu);
|
|
|
p_menu->addAction(act);
|
|
|
|
|
@@ -768,10 +863,28 @@ void NotebookNodeExplorer::createContextMenuOnNode(QMenu *p_menu, const Node *p_
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void NotebookNodeExplorer::createContextMenuOnAttachment(QMenu *p_menu, const QString &p_name)
|
|
|
+void NotebookNodeExplorer::createContextMenuOnExternalNode(QMenu *p_menu, const ExternalNode *p_node)
|
|
|
{
|
|
|
- Q_UNUSED(p_menu);
|
|
|
- Q_UNUSED(p_name);
|
|
|
+ Q_UNUSED(p_node);
|
|
|
+
|
|
|
+ const int selectedSize = m_masterExplorer->selectedItems().size();
|
|
|
+ QAction *act = nullptr;
|
|
|
+
|
|
|
+ act = createAction(Action::Open, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
+ act = createAction(Action::ImportToConfig, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
+ if (selectedSize == 1) {
|
|
|
+ p_menu->addSeparator();
|
|
|
+
|
|
|
+ act = createAction(Action::CopyPath, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+
|
|
|
+ act = createAction(Action::OpenLocation, p_menu);
|
|
|
+ p_menu->addAction(act);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static QIcon generateMenuActionIcon(const QString &p_name)
|
|
@@ -811,7 +924,7 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
|
|
connect(act, &QAction::triggered,
|
|
|
this, [this]() {
|
|
|
auto node = getCurrentNode();
|
|
|
- if (!node) {
|
|
|
+ if (checkInvalidNode(node)) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -834,15 +947,32 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
|
|
act = new QAction(tr("Open &Location"), p_parent);
|
|
|
connect(act, &QAction::triggered,
|
|
|
this, [this]() {
|
|
|
+ auto item = m_masterExplorer->currentItem();
|
|
|
+ if (!item) {
|
|
|
+ if (m_notebook) {
|
|
|
+ auto locationPath = m_notebook->getRootFolderAbsolutePath();
|
|
|
+ WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(locationPath));
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ auto data = getItemNodeData(item);
|
|
|
QString locationPath;
|
|
|
- auto node = getCurrentNode();
|
|
|
- if (node) {
|
|
|
+ if (data.isNode()) {
|
|
|
+ auto node = data.getNode();
|
|
|
+ if (checkInvalidNode(node)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
locationPath = node->fetchAbsolutePath();
|
|
|
if (!node->isContainer()) {
|
|
|
locationPath = PathUtils::parentDirPath(locationPath);
|
|
|
}
|
|
|
- } else if (m_notebook) {
|
|
|
- locationPath = m_notebook->getRootFolderAbsolutePath();
|
|
|
+ } else if (data.isExternalNode()) {
|
|
|
+ auto externalNode = data.getExternalNode();
|
|
|
+ locationPath = externalNode->fetchAbsolutePath();
|
|
|
+ if (!externalNode->isFolder()) {
|
|
|
+ locationPath = PathUtils::parentDirPath(locationPath);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (!locationPath.isEmpty()) {
|
|
@@ -855,9 +985,22 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
|
|
act = new QAction(tr("Cop&y Path"), p_parent);
|
|
|
connect(act, &QAction::triggered,
|
|
|
this, [this]() {
|
|
|
- auto node = getCurrentNode();
|
|
|
- if (node) {
|
|
|
- auto nodePath = node->fetchAbsolutePath();
|
|
|
+ auto item = m_masterExplorer->currentItem();
|
|
|
+ if (!item) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ auto data = getItemNodeData(item);
|
|
|
+ QString nodePath;
|
|
|
+ if (data.isNode()) {
|
|
|
+ auto node = data.getNode();
|
|
|
+ if (checkInvalidNode(node)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ nodePath = node->fetchAbsolutePath();
|
|
|
+ } else if (data.isExternalNode()) {
|
|
|
+ nodePath = data.getExternalNode()->fetchAbsolutePath();
|
|
|
+ }
|
|
|
+ if (!nodePath.isEmpty()) {
|
|
|
ClipboardUtils::setTextToClipboard(nodePath);
|
|
|
VNoteX::getInst().showStatusMessageShort(tr("Copied path: %1").arg(nodePath));
|
|
|
}
|
|
@@ -906,9 +1049,8 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
|
|
m_notebook->emptyNode(rbNode, true);
|
|
|
} catch (Exception &p_e) {
|
|
|
MessageBoxHelper::notify(MessageBoxHelper::Critical,
|
|
|
- tr("Failed to empty recycle bin (%1) (%2).")
|
|
|
- .arg(rbNodePath, p_e.what()),
|
|
|
- VNoteX::getInst().getMainWindow());
|
|
|
+ tr("Failed to empty recycle bin (%1) (%2).").arg(rbNodePath, p_e.what()),
|
|
|
+ VNoteX::getInst().getMainWindow());
|
|
|
}
|
|
|
|
|
|
updateNode(rbNode);
|
|
@@ -935,18 +1077,42 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
|
|
case Action::RemoveFromConfig:
|
|
|
act = new QAction(tr("&Remove From Index"), p_parent);
|
|
|
connect(act, &QAction::triggered,
|
|
|
- this, [this]() {
|
|
|
- removeSelectedNodesFromConfig();
|
|
|
- });
|
|
|
+ this, &NotebookNodeExplorer::removeSelectedNodesFromConfig);
|
|
|
break;
|
|
|
|
|
|
case Action::Sort:
|
|
|
act = new QAction(generateMenuActionIcon("sort.svg"), tr("&Sort"), p_parent);
|
|
|
+ connect(act, &QAction::triggered,
|
|
|
+ this, &NotebookNodeExplorer::manualSort);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Action::Reload:
|
|
|
+ act = new QAction(tr("Re&load"), p_parent);
|
|
|
connect(act, &QAction::triggered,
|
|
|
this, [this]() {
|
|
|
- manualSort();
|
|
|
+ auto node = currentExploredFolderNode();
|
|
|
+ if (m_notebook && node) {
|
|
|
+ // TODO: emit signals to notify other components.
|
|
|
+ m_notebook->reloadNode(node);
|
|
|
+ }
|
|
|
+ updateNode(node);
|
|
|
+ });
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Action::ImportToConfig:
|
|
|
+ act = new QAction(tr("&Import To Index"), p_parent);
|
|
|
+ connect(act, &QAction::triggered,
|
|
|
+ this, [this]() {
|
|
|
+ auto nodes = getSelectedNodes().second;
|
|
|
+ importToIndex(nodes);
|
|
|
});
|
|
|
break;
|
|
|
+
|
|
|
+ case Action::Open:
|
|
|
+ act = new QAction(tr("&Open"), p_parent);
|
|
|
+ connect(act, &QAction::triggered,
|
|
|
+ this, &NotebookNodeExplorer::openSelectedNodes);
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
return act;
|
|
@@ -954,7 +1120,7 @@ QAction *NotebookNodeExplorer::createAction(Action p_act, QObject *p_parent)
|
|
|
|
|
|
void NotebookNodeExplorer::copySelectedNodes(bool p_move)
|
|
|
{
|
|
|
- auto nodes = getSelectedNodes();
|
|
|
+ auto nodes = getSelectedNodes().first;
|
|
|
if (nodes.isEmpty()) {
|
|
|
return;
|
|
|
}
|
|
@@ -964,6 +1130,10 @@ void NotebookNodeExplorer::copySelectedNodes(bool p_move)
|
|
|
ClipboardData cdata(VNoteX::getInst().getInstanceId(),
|
|
|
p_move ? ClipboardData::MoveNode : ClipboardData::CopyNode);
|
|
|
for (auto node : nodes) {
|
|
|
+ if (checkInvalidNode(node)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
auto item = QSharedPointer<NodeClipboardDataItem>::create(node->getNotebook()->getId(),
|
|
|
node->fetchPath());
|
|
|
cdata.addItem(item);
|
|
@@ -976,15 +1146,17 @@ void NotebookNodeExplorer::copySelectedNodes(bool p_move)
|
|
|
VNoteX::getInst().showStatusMessageShort(tr("Copied %n item(s)", "", static_cast<int>(nrItems)));
|
|
|
}
|
|
|
|
|
|
-QVector<Node *> NotebookNodeExplorer::getSelectedNodes() const
|
|
|
+QPair<QVector<Node *>, QVector<ExternalNode *>> NotebookNodeExplorer::getSelectedNodes() const
|
|
|
{
|
|
|
- QVector<Node *> nodes;
|
|
|
+ QPair<QVector<Node *>, QVector<ExternalNode *>> nodes;
|
|
|
|
|
|
auto items = m_masterExplorer->selectedItems();
|
|
|
for (auto &item : items) {
|
|
|
auto data = getItemNodeData(item);
|
|
|
if (data.isNode()) {
|
|
|
- nodes.push_back(data.getNode());
|
|
|
+ nodes.first.push_back(data.getNode());
|
|
|
+ } else if (data.isExternalNode()) {
|
|
|
+ nodes.second.push_back(data.getExternalNode());
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1051,6 +1223,8 @@ void NotebookNodeExplorer::pasteNodesFromClipboard()
|
|
|
// Current node may be a file node.
|
|
|
if (!destNode->isContainer()) {
|
|
|
destNode = destNode->getParent();
|
|
|
+ } else if (checkInvalidNode(destNode)) {
|
|
|
+ return;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1088,6 +1262,8 @@ void NotebookNodeExplorer::pasteNodesFromClipboard()
|
|
|
QVector<const Node *> pastedNodes;
|
|
|
QSet<Node *> nodesNeedUpdate;
|
|
|
for (auto srcNode : srcNodes) {
|
|
|
+ Q_ASSERT(srcNode->exists());
|
|
|
+
|
|
|
if (isMove) {
|
|
|
// Notice the view area to close any opened view windows.
|
|
|
auto event = QSharedPointer<Event>::create();
|
|
@@ -1176,7 +1352,7 @@ QVector<Node *> NotebookNodeExplorer::confirmSelectedNodes(const QString &p_titl
|
|
|
const QString &p_text,
|
|
|
const QString &p_info) const
|
|
|
{
|
|
|
- auto nodes = getSelectedNodes();
|
|
|
+ auto nodes = getSelectedNodes().first;
|
|
|
if (nodes.isEmpty()) {
|
|
|
return nodes;
|
|
|
}
|
|
@@ -1270,7 +1446,7 @@ void NotebookNodeExplorer::removeSelectedNodesFromConfig()
|
|
|
|
|
|
void NotebookNodeExplorer::filterAwayChildrenNodes(QVector<Node *> &p_nodes)
|
|
|
{
|
|
|
- for (int i = p_nodes.size() - 1; i > 0; --i) {
|
|
|
+ for (int i = p_nodes.size() - 1; i >= 0; --i) {
|
|
|
// Check if j is i's ancestor.
|
|
|
for (int j = p_nodes.size() - 1; j >= 0; --j) {
|
|
|
if (i == j) {
|
|
@@ -1351,8 +1527,7 @@ void NotebookNodeExplorer::focusNormalNode()
|
|
|
|
|
|
void NotebookNodeExplorer::sortNodes(QVector<QSharedPointer<Node>> &p_nodes) const
|
|
|
{
|
|
|
- int viewOrder = ConfigMgr::getInst().getWidgetConfig().getNoteExplorerViewOrder();
|
|
|
- if (viewOrder == ViewOrder::OrderedByConfiguration) {
|
|
|
+ if (m_viewOrder == ViewOrder::OrderedByConfiguration) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -1369,10 +1544,10 @@ void NotebookNodeExplorer::sortNodes(QVector<QSharedPointer<Node>> &p_nodes) con
|
|
|
}
|
|
|
|
|
|
// Sort containers.
|
|
|
- sortNodes(p_nodes, 0, firstFileIndex, viewOrder);
|
|
|
+ sortNodes(p_nodes, 0, firstFileIndex, m_viewOrder);
|
|
|
|
|
|
// Sort non-containers.
|
|
|
- sortNodes(p_nodes, firstFileIndex, p_nodes.size(), viewOrder);
|
|
|
+ sortNodes(p_nodes, firstFileIndex, p_nodes.size(), m_viewOrder);
|
|
|
}
|
|
|
|
|
|
void NotebookNodeExplorer::sortNodes(QVector<QSharedPointer<Node>> &p_nodes, int p_start, int p_end, int p_viewOrder) const
|
|
@@ -1437,6 +1612,25 @@ void NotebookNodeExplorer::setRecycleBinNodeVisible(bool p_visible)
|
|
|
reload();
|
|
|
}
|
|
|
|
|
|
+void NotebookNodeExplorer::setExternalFilesVisible(bool p_visible)
|
|
|
+{
|
|
|
+ if (m_externalFilesVisible == p_visible) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ m_externalFilesVisible = p_visible;
|
|
|
+ reload();
|
|
|
+}
|
|
|
+
|
|
|
+void NotebookNodeExplorer::setAutoImportExternalFiles(bool p_enabled)
|
|
|
+{
|
|
|
+ if (m_autoImportExternalFiles == p_enabled) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ m_autoImportExternalFiles = p_enabled;
|
|
|
+}
|
|
|
+
|
|
|
void NotebookNodeExplorer::manualSort()
|
|
|
{
|
|
|
auto node = getCurrentNode();
|
|
@@ -1465,7 +1659,7 @@ void NotebookNodeExplorer::manualSort()
|
|
|
treeWidget->setColumnCount(2);
|
|
|
treeWidget->setHeaderLabels({tr("Name"), tr("Created Time"), tr("Modified Time")});
|
|
|
|
|
|
- const auto &children = parentNode->getChildren();
|
|
|
+ const auto &children = parentNode->getChildrenRef();
|
|
|
for (int i = 0; i < children.size(); ++i) {
|
|
|
const auto &child = children[i];
|
|
|
if (m_notebook->isRecycleBinNode(child.data())) {
|
|
@@ -1498,3 +1692,107 @@ void NotebookNodeExplorer::manualSort()
|
|
|
updateNode(parentNode);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+Node *NotebookNodeExplorer::currentExploredFolderNode() const
|
|
|
+{
|
|
|
+ if (!m_notebook) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto node = getCurrentNode();
|
|
|
+ if (node) {
|
|
|
+ if (!node->isContainer()) {
|
|
|
+ node = node->getParent();
|
|
|
+ }
|
|
|
+ Q_ASSERT(node && node->isContainer());
|
|
|
+ } else {
|
|
|
+ node = m_notebook->getRootNode().data();
|
|
|
+ }
|
|
|
+
|
|
|
+ return node;
|
|
|
+}
|
|
|
+
|
|
|
+void NotebookNodeExplorer::setViewOrder(int p_order)
|
|
|
+{
|
|
|
+ if (m_viewOrder == p_order) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ m_viewOrder = p_order;
|
|
|
+ reload();
|
|
|
+}
|
|
|
+
|
|
|
+void NotebookNodeExplorer::openSelectedNodes()
|
|
|
+{
|
|
|
+ // Support nodes and external nodes.
|
|
|
+ // Do nothing for folders.
|
|
|
+ auto selectedNodes = getSelectedNodes();
|
|
|
+ for (const auto &externalNode : selectedNodes.second) {
|
|
|
+ if (!externalNode->isFolder()) {
|
|
|
+ emit fileActivated(externalNode->fetchAbsolutePath(), QSharedPointer<FileOpenParameters>::create());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const auto &node : selectedNodes.first) {
|
|
|
+ if (checkInvalidNode(node)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node->hasContent()) {
|
|
|
+ emit nodeActivated(node, QSharedPointer<FileOpenParameters>::create());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+QSharedPointer<Node> NotebookNodeExplorer::importToIndex(const ExternalNode *p_node)
|
|
|
+{
|
|
|
+ auto node = m_notebook->addAsNode(p_node->getNode(),
|
|
|
+ p_node->isFolder() ? Node::Flag::Container : Node::Flag::Content,
|
|
|
+ p_node->getName(),
|
|
|
+ NodeParameters());
|
|
|
+ updateNode(p_node->getNode());
|
|
|
+ if (node) {
|
|
|
+ setCurrentNode(node.data());
|
|
|
+ }
|
|
|
+ return node;
|
|
|
+}
|
|
|
+
|
|
|
+void NotebookNodeExplorer::importToIndex(const QVector<ExternalNode *> &p_nodes)
|
|
|
+{
|
|
|
+ QSet<Node *> nodesToUpdate;
|
|
|
+ Node *currentNode = nullptr;
|
|
|
+
|
|
|
+ for (auto externalNode : p_nodes) {
|
|
|
+ auto node = m_notebook->addAsNode(externalNode->getNode(),
|
|
|
+ externalNode->isFolder() ? Node::Flag::Container : Node::Flag::Content,
|
|
|
+ externalNode->getName(),
|
|
|
+ NodeParameters());
|
|
|
+ nodesToUpdate.insert(externalNode->getNode());
|
|
|
+ currentNode = node.data();
|
|
|
+ }
|
|
|
+
|
|
|
+ for (auto node : nodesToUpdate) {
|
|
|
+ updateNode(node);
|
|
|
+ }
|
|
|
+ if (currentNode) {
|
|
|
+ setCurrentNode(currentNode);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool NotebookNodeExplorer::checkInvalidNode(const Node *p_node) const
|
|
|
+{
|
|
|
+ if (!p_node) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!p_node->exists()) {
|
|
|
+ MessageBoxHelper::notify(MessageBoxHelper::Warning,
|
|
|
+ tr("Invalid node (%1).").arg(p_node->getName()),
|
|
|
+ tr("Please check if the node exists on the disk."),
|
|
|
+ p_node->fetchAbsolutePath(),
|
|
|
+ VNoteX::getInst().getMainWindow());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|