NotebookExplorer: support separated node explorer

This commit is contained in:
Le Tan 2022-01-14 20:33:17 +08:00
parent a4a5dea3d7
commit 2630999acf
18 changed files with 1058 additions and 385 deletions

View File

@ -25,7 +25,7 @@
using namespace vnotex; using namespace vnotex;
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
#define VX_DEBUG_WEB // #define VX_DEBUG_WEB
#endif #endif
const QString ConfigMgr::c_orgName = "VNote"; const QString ConfigMgr::c_orgName = "VNote";

View File

@ -119,5 +119,7 @@ QString MainConfig::getVersion(const QJsonObject &p_jobj)
void MainConfig::doVersionSpecificOverride() void MainConfig::doVersionSpecificOverride()
{ {
// In a new version, we may want to change one value by force. // In a new version, we may want to change one value by force.
// For 3.12.0.
m_editorConfig->getTextEditorConfig().m_highlightWhitespace = false; m_editorConfig->getTextEditorConfig().m_highlightWhitespace = false;
m_editorConfig->getMarkdownEditorConfig().m_imageAlignCenterEnabled = false;
} }

View File

@ -211,7 +211,7 @@ namespace vnotex
// Whether enable image width constraint. // Whether enable image width constraint.
bool m_constrainImageWidthEnabled = true; bool m_constrainImageWidthEnabled = true;
bool m_imageAlignCenterEnabled = true; bool m_imageAlignCenterEnabled = false;
// Whether enable in-place preview width constraint. // Whether enable in-place preview width constraint.
bool m_constrainInplacePreviewWidthEnabled = false; bool m_constrainInplacePreviewWidthEnabled = false;

View File

@ -222,6 +222,7 @@ QJsonObject SessionConfig::saveStateAndGeometry() const
writeByteArray(obj, QStringLiteral("main_window_geometry"), m_mainWindowStateGeometry.m_mainGeometry); writeByteArray(obj, QStringLiteral("main_window_geometry"), m_mainWindowStateGeometry.m_mainGeometry);
writeStringList(obj, QStringLiteral("visible_docks_before_expand"), m_mainWindowStateGeometry.m_visibleDocksBeforeExpand); writeStringList(obj, QStringLiteral("visible_docks_before_expand"), m_mainWindowStateGeometry.m_visibleDocksBeforeExpand);
writeByteArray(obj, QStringLiteral("tag_explorer_state"), m_mainWindowStateGeometry.m_tagExplorerState); writeByteArray(obj, QStringLiteral("tag_explorer_state"), m_mainWindowStateGeometry.m_tagExplorerState);
writeByteArray(obj, QStringLiteral("notebook_explorer_state"), m_mainWindowStateGeometry.m_notebookExplorerState);
return obj; return obj;
} }
@ -353,6 +354,7 @@ void SessionConfig::loadStateAndGeometry(const QJsonObject &p_session)
m_mainWindowStateGeometry.m_mainGeometry = readByteArray(obj, QStringLiteral("main_window_geometry")); m_mainWindowStateGeometry.m_mainGeometry = readByteArray(obj, QStringLiteral("main_window_geometry"));
m_mainWindowStateGeometry.m_visibleDocksBeforeExpand = readStringList(obj, QStringLiteral("visible_docks_before_expand")); m_mainWindowStateGeometry.m_visibleDocksBeforeExpand = readStringList(obj, QStringLiteral("visible_docks_before_expand"));
m_mainWindowStateGeometry.m_tagExplorerState = readByteArray(obj, QStringLiteral("tag_explorer_state")); m_mainWindowStateGeometry.m_tagExplorerState = readByteArray(obj, QStringLiteral("tag_explorer_state"));
m_mainWindowStateGeometry.m_notebookExplorerState = readByteArray(obj, QStringLiteral("notebook_explorer_state"));
} }
QByteArray SessionConfig::getViewAreaSessionAndClear() QByteArray SessionConfig::getViewAreaSessionAndClear()

View File

@ -37,7 +37,8 @@ namespace vnotex
return m_mainState == p_other.m_mainState return m_mainState == p_other.m_mainState
&& m_mainGeometry == p_other.m_mainGeometry && m_mainGeometry == p_other.m_mainGeometry
&& m_visibleDocksBeforeExpand == p_other.m_visibleDocksBeforeExpand && m_visibleDocksBeforeExpand == p_other.m_visibleDocksBeforeExpand
&& m_tagExplorerState == p_other.m_tagExplorerState; && m_tagExplorerState == p_other.m_tagExplorerState
&& m_notebookExplorerState == p_other.m_notebookExplorerState;
} }
QByteArray m_mainState; QByteArray m_mainState;
@ -47,6 +48,8 @@ namespace vnotex
QStringList m_visibleDocksBeforeExpand; QStringList m_visibleDocksBeforeExpand;
QByteArray m_tagExplorerState; QByteArray m_tagExplorerState;
QByteArray m_notebookExplorerState;
}; };
enum OpenGL enum OpenGL

View File

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

View File

@ -30,6 +30,9 @@ namespace vnotex
int getNodeExplorerViewOrder() const; int getNodeExplorerViewOrder() const;
void setNodeExplorerViewOrder(int p_viewOrder); void setNodeExplorerViewOrder(int p_viewOrder);
int getNodeExplorerExploreMode() const;
void setNodeExplorerExploreMode(int p_mode);
bool isNodeExplorerExternalFilesVisible() const; bool isNodeExplorerExternalFilesVisible() const;
void setNodeExplorerExternalFilesVisible(bool p_visible); void setNodeExplorerExternalFilesVisible(bool p_visible);
@ -60,6 +63,8 @@ namespace vnotex
int m_nodeExplorerViewOrder = 0; int m_nodeExplorerViewOrder = 0;
int m_nodeExplorerExploreMode = 1;
bool m_nodeExplorerExternalFilesVisible = true; bool m_nodeExplorerExternalFilesVisible = true;
bool m_nodeExplorerAutoImportExternalFilesEnabled = true; bool m_nodeExplorerAutoImportExternalFilesEnabled = true;

View File

@ -335,7 +335,7 @@
"section_number_style" : "digdotdigdot", "section_number_style" : "digdotdigdot",
"//comment" : "Whether enable image width constraint", "//comment" : "Whether enable image width constraint",
"constrain_image_width" : true, "constrain_image_width" : true,
"image_align_center" : true, "image_align_center" : false,
"//comment" : "Whether enable in-place preview width constraint", "//comment" : "Whether enable in-place preview width constraint",
"constrain_inplace_preview_width" : false, "constrain_inplace_preview_width" : false,
"//comment" : "Zoom factor in read mode", "//comment" : "Zoom factor in read mode",
@ -383,12 +383,14 @@
"outline_section_number_enabled" : false, "outline_section_number_enabled" : false,
"//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 node explorer", "//comment" : "View order of the node explorer (NotebookNodeExplorer::ViewOrder)",
"node_explorer_view_order" : 0, "node_explorer_view_order" : 0,
"node_explorer_external_files_visible" : true, "node_explorer_external_files_visible" : true,
"node_explorer_auto_import_external_files_enabled" : true, "node_explorer_auto_import_external_files_enabled" : true,
"//comment" : "Whether close the file before opening it with external program", "//comment" : "Whether close the file before opening it with external program",
"node_explorer_close_before_open_with_enabled" : true, "node_explorer_close_before_open_with_enabled" : true,
"//comment" : "0 - combined/1 - separate_single/2 - separate_double",
"node_explorer_explore_mode" : 1,
"search_panel_advanced_settings_visible" : true, "search_panel_advanced_settings_visible" : true,
"//comment" : "Docks to ignore when expanding content area of main window", "//comment" : "Docks to ignore when expanding content area of main window",
"main_window_keep_docks_expanding_content_area": ["OutlineDock.vnotex"], "main_window_keep_docks_expanding_content_area": ["OutlineDock.vnotex"],

View File

@ -30,7 +30,7 @@
}, },
"IndicatorsBorder" : { "IndicatorsBorder" : {
"text-color" : "#8a93a6", "text-color" : "#8a93a6",
"background-color" : "#2d323b" "background-color" : "#3c414d"
}, },
"CurrentLineNumber" : { "CurrentLineNumber" : {
"text-color" : "#ccd1d8" "text-color" : "#ccd1d8"

View File

@ -42,6 +42,44 @@ bool ExportHtmlOption::operator==(const ExportHtmlOption &p_other) const
&& m_scrollable == p_other.m_scrollable; && m_scrollable == p_other.m_scrollable;
} }
static QJsonObject pageLayoutToJsonObject(const QPageLayout &p_layout)
{
QJsonObject obj;
obj["page_size"] = static_cast<int>(p_layout.pageSize().id());
obj["orientation"] = static_cast<int>(p_layout.orientation());
obj["units"] = static_cast<int>(p_layout.units());
{
QStringList marginsStr;
const auto margins = p_layout.margins();
marginsStr << QString::number(margins.left());
marginsStr << QString::number(margins.top());
marginsStr << QString::number(margins.right());
marginsStr << QString::number(margins.bottom());
obj["margins"] = marginsStr.join(QLatin1Char(','));
}
return obj;
}
static void jsonObjectToPageLayout(const QJsonObject &p_obj, QPageLayout &p_layout)
{
const int pageSize = p_obj["page_size"].toInt(static_cast<int>(QPageSize::A4));
p_layout.setPageSize(QPageSize(static_cast<QPageSize::PageSizeId>(pageSize)));
const int orientation = p_obj["orientation"].toInt(static_cast<int>(QPageLayout::Portrait));
p_layout.setOrientation(static_cast<QPageLayout::Orientation>(orientation));
const int units = p_obj["units"].toInt(static_cast<int>(QPageLayout::Millimeter));
p_layout.setUnits(static_cast<QPageLayout::Unit>(units));
auto marginsStr = p_obj["margins"].toString().split(QLatin1Char(','));
if (marginsStr.size() == 4) {
p_layout.setMargins(QMarginsF(marginsStr[0].toDouble(),
marginsStr[1].toDouble(),
marginsStr[2].toDouble(),
marginsStr[3].toDouble()));
}
}
ExportPdfOption::ExportPdfOption() ExportPdfOption::ExportPdfOption()
: m_layout(new QPageLayout(QPageSize(QPageSize::A4), : m_layout(new QPageLayout(QPageSize(QPageSize::A4),
QPageLayout::Portrait, QPageLayout::Portrait,
@ -58,6 +96,7 @@ QJsonObject ExportPdfOption::toJson() const
obj["all_in_one"] = m_allInOne; obj["all_in_one"] = m_allInOne;
obj["wkhtmltopdf_exe_path"] = m_wkhtmltopdfExePath; obj["wkhtmltopdf_exe_path"] = m_wkhtmltopdfExePath;
obj["wkhtmltopdf_args"] = m_wkhtmltopdfArgs; obj["wkhtmltopdf_args"] = m_wkhtmltopdfArgs;
obj["layout"] = pageLayoutToJsonObject(*m_layout);
return obj; return obj;
} }
@ -72,6 +111,7 @@ void ExportPdfOption::fromJson(const QJsonObject &p_obj)
m_allInOne = p_obj["all_in_one"].toBool(); m_allInOne = p_obj["all_in_one"].toBool();
m_wkhtmltopdfExePath = p_obj["wkhtmltopdf_exe_path"].toString(); m_wkhtmltopdfExePath = p_obj["wkhtmltopdf_exe_path"].toString();
m_wkhtmltopdfArgs = p_obj["wkhtmltopdf_args"].toString(); m_wkhtmltopdfArgs = p_obj["wkhtmltopdf_args"].toString();
jsonObjectToPageLayout(p_obj["layout"].toObject(), *m_layout);
} }
bool ExportPdfOption::operator==(const ExportPdfOption &p_other) const bool ExportPdfOption::operator==(const ExportPdfOption &p_other) const

View File

@ -10,6 +10,7 @@ QAccessibleInterface *FakeAccessible::accessibleFactory(const QString &p_classNa
// Try to fix non-responsible issue caused by Youdao Dict. // Try to fix non-responsible issue caused by Youdao Dict.
if (p_className.startsWith(QStringLiteral("vnotex::")) if (p_className.startsWith(QStringLiteral("vnotex::"))
|| p_className.startsWith(QStringLiteral("vte::"))) { || p_className.startsWith(QStringLiteral("vte::"))) {
// Qt's docs: All interfaces are managed by an internal cache and should not be deleted.
return new FakeAccessibleInterface(p_obj); return new FakeAccessibleInterface(p_obj);
} }

View File

@ -427,6 +427,7 @@ void MainWindow::saveStateAndGeometry()
sg.m_mainGeometry = saveGeometry(); sg.m_mainGeometry = saveGeometry();
sg.m_visibleDocksBeforeExpand = m_visibleDocksBeforeExpand; sg.m_visibleDocksBeforeExpand = m_visibleDocksBeforeExpand;
sg.m_tagExplorerState = m_tagExplorer->saveState(); sg.m_tagExplorerState = m_tagExplorer->saveState();
sg.m_notebookExplorerState = m_notebookExplorer->saveState();
auto& sessionConfig = ConfigMgr::getInst().getSessionConfig(); auto& sessionConfig = ConfigMgr::getInst().getSessionConfig();
sessionConfig.setMainWindowStateGeometry(sg); sessionConfig.setMainWindowStateGeometry(sg);
@ -457,6 +458,10 @@ void MainWindow::loadStateAndGeometry(bool p_stateOnly)
if (!sg.m_tagExplorerState.isEmpty()) { if (!sg.m_tagExplorerState.isEmpty()) {
m_tagExplorer->restoreState(sg.m_tagExplorerState); m_tagExplorer->restoreState(sg.m_tagExplorerState);
} }
if (!sg.m_notebookExplorerState.isEmpty()) {
m_notebookExplorer->restoreState(sg.m_notebookExplorerState);
}
} }
void MainWindow::resetStateAndGeometry() void MainWindow::resetStateAndGeometry()

View File

@ -82,6 +82,7 @@ void NotebookExplorer::setupUI()
const auto &widgetConfig = ConfigMgr::getInst().getWidgetConfig(); const auto &widgetConfig = ConfigMgr::getInst().getWidgetConfig();
m_nodeExplorer = new NotebookNodeExplorer(this); m_nodeExplorer = new NotebookNodeExplorer(this);
m_nodeExplorer->setViewOrder(widgetConfig.getNodeExplorerViewOrder()); m_nodeExplorer->setViewOrder(widgetConfig.getNodeExplorerViewOrder());
m_nodeExplorer->setExploreMode(widgetConfig.getNodeExplorerExploreMode());
m_nodeExplorer->setExternalFilesVisible(widgetConfig.isNodeExplorerExternalFilesVisible()); m_nodeExplorer->setExternalFilesVisible(widgetConfig.isNodeExplorerExternalFilesVisible());
connect(m_nodeExplorer, &NotebookNodeExplorer::nodeActivated, connect(m_nodeExplorer, &NotebookNodeExplorer::nodeActivated,
&VNoteX::getInst(), &VNoteX::openNodeRequested); &VNoteX::getInst(), &VNoteX::openNodeRequested);
@ -113,11 +114,8 @@ TitleBar *NotebookExplorer::setupTitleBar(QWidget *p_parent)
{ {
auto viewMenu = WidgetsFactory::createMenu(titleBar); auto viewMenu = WidgetsFactory::createMenu(titleBar);
titleBar->addActionButton(QStringLiteral("view.svg"), tr("View"), viewMenu);
connect(viewMenu, &QMenu::aboutToShow,
this, [this, viewMenu]() {
setupViewMenu(viewMenu); setupViewMenu(viewMenu);
}); titleBar->addActionButton(QStringLiteral("view.svg"), tr("View"), viewMenu);
} }
{ {
@ -205,6 +203,8 @@ TitleBar *NotebookExplorer::setupTitleBar(QWidget *p_parent)
act->setChecked(widgetConfig.getNodeExplorerCloseBeforeOpenWithEnabled()); act->setChecked(widgetConfig.getNodeExplorerCloseBeforeOpenWithEnabled());
} }
setupExploreModeMenu(titleBar);
return titleBar; return titleBar;
} }
@ -383,10 +383,6 @@ const QSharedPointer<Notebook> &NotebookExplorer::currentNotebook() const
void NotebookExplorer::setupViewMenu(QMenu *p_menu) void NotebookExplorer::setupViewMenu(QMenu *p_menu)
{ {
if (!p_menu->isEmpty()) {
return;
}
auto ag = new QActionGroup(p_menu); auto ag = new QActionGroup(p_menu);
auto act = ag->addAction(tr("View By Configuration")); auto act = ag->addAction(tr("View By Configuration"));
@ -467,6 +463,45 @@ void NotebookExplorer::setupRecycleBinMenu(QMenu *p_menu)
}); });
} }
void NotebookExplorer::setupExploreModeMenu(TitleBar *p_titleBar)
{
auto menu = p_titleBar->addMenuSubMenu(tr("Explore Mode"));
auto ag = new QActionGroup(menu);
auto act = ag->addAction(tr("Combined"));
act->setCheckable(true);
act->setChecked(true);
act->setData(NotebookNodeExplorer::ExploreMode::Combined);
menu->addAction(act);
act = ag->addAction(tr("Separate, Single Column"));
act->setCheckable(true);
act->setChecked(true);
act->setData(NotebookNodeExplorer::ExploreMode::SeparateSingle);
menu->addAction(act);
act = ag->addAction(tr("Separate, Double Columns"));
act->setCheckable(true);
act->setChecked(true);
act->setData(NotebookNodeExplorer::ExploreMode::SeparateDouble);
menu->addAction(act);
int mode = ConfigMgr::getInst().getWidgetConfig().getNodeExplorerExploreMode();
for (const auto &act : ag->actions()) {
if (act->data().toInt() == mode) {
act->setChecked(true);
}
}
connect(ag, &QActionGroup::triggered,
this, [this](QAction *action) {
int mode = action->data().toInt();
ConfigMgr::getInst().getWidgetConfig().setNodeExplorerExploreMode(mode);
m_nodeExplorer->setExploreMode(mode);
});
}
void NotebookExplorer::saveSession() void NotebookExplorer::saveSession()
{ {
updateSession(); updateSession();
@ -560,3 +595,13 @@ void NotebookExplorer::rebuildDatabase()
} }
} }
} }
QByteArray NotebookExplorer::saveState() const
{
return m_nodeExplorer->saveState();
}
void NotebookExplorer::restoreState(const QByteArray &p_data)
{
m_nodeExplorer->restoreState(p_data);
}

View File

@ -30,6 +30,10 @@ namespace vnotex
Node *currentExploredNode() const; Node *currentExploredNode() const;
QByteArray saveState() const;
void restoreState(const QByteArray &p_data);
public slots: public slots:
void newNotebook(); void newNotebook();
@ -71,6 +75,8 @@ namespace vnotex
void setupRecycleBinMenu(QMenu *p_menu); void setupRecycleBinMenu(QMenu *p_menu);
void setupExploreModeMenu(TitleBar *p_titleBar);
void saveSession(); void saveSession();
void loadSession(); void loadSession();

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,6 @@
#include "navigationmodewrapper.h" #include "navigationmodewrapper.h"
class QSplitter; class QSplitter;
class QTreeWidget;
class QTreeWidgetItem;
class QMenu; class QMenu;
namespace vnotex namespace vnotex
@ -21,6 +19,7 @@ namespace vnotex
class Notebook; class Notebook;
class Node; class Node;
class TreeWidget; class TreeWidget;
class ListWidget;
struct FileOpenParameters; struct FileOpenParameters;
class Event; class Event;
class ExternalNode; class ExternalNode;
@ -65,6 +64,8 @@ namespace vnotex
bool matched(const Node *p_node) const; bool matched(const Node *p_node) const;
bool matched(const QString &p_name) const;
bool isLoaded() const; bool isLoaded() const;
private: private:
@ -89,22 +90,26 @@ namespace vnotex
ViewOrderMax ViewOrderMax
}; };
enum ExploreMode
{
Combined = 0,
SeparateSingle,
SeparateDouble,
ExploreModeMax
};
explicit NotebookNodeExplorer(QWidget *p_parent = nullptr); explicit NotebookNodeExplorer(QWidget *p_parent = nullptr);
void setNotebook(const QSharedPointer<Notebook> &p_notebook); void setNotebook(const QSharedPointer<Notebook> &p_notebook);
Node *getCurrentNode() const;
// Update the tree of @p_node.
// If @p_node is null, update the whole tree.
void updateNode(Node *p_node);
void setCurrentNode(Node *p_node); void setCurrentNode(Node *p_node);
void reload(); void reload();
void setViewOrder(int p_order); void setViewOrder(int p_order);
void setExploreMode(int p_mode);
void setExternalFilesVisible(bool p_visible); void setExternalFilesVisible(bool p_visible);
void setAutoImportExternalFiles(bool p_enabled); void setAutoImportExternalFiles(bool p_enabled);
@ -113,6 +118,10 @@ namespace vnotex
Node *currentExploredNode() const; Node *currentExploredNode() const;
QByteArray saveState() const;
void restoreState(const QByteArray &p_data);
static QString generateToolTip(const Node *p_node); static QString generateToolTip(const Node *p_node);
signals: signals:
@ -156,81 +165,103 @@ namespace vnotex
Tag Tag
}; };
struct CacheData
{
void clear();
QSharedPointer<QTreeWidgetStateCache<Node *>> m_masterStateCache;
QString m_currentSlaveName;
};
void setupUI(); void setupUI();
void setupShortcuts(); void setupShortcuts();
void setupMasterExplorer(QWidget *p_parent = nullptr); void setupMasterExplorer(QWidget *p_parent = nullptr);
void clearExplorer(); void setupSlaveExplorer();
void generateNodeTree(); void generateMasterNodeTree();
void loadRootNode(const Node *p_node) const; void loadRootNode(const Node *p_node) const;
void loadNode(QTreeWidgetItem *p_item, Node *p_node, int p_level) const; void loadMasterNode(QTreeWidgetItem *p_item, Node *p_node, int p_level) const;
void loadChildren(QTreeWidgetItem *p_item, Node *p_node, int p_level) const; void loadMasterNodeChildren(QTreeWidgetItem *p_item, Node *p_node, int p_level) const;
void loadItemChildren(QTreeWidgetItem *p_item) const; void loadMasterItemChildren(QTreeWidgetItem *p_item) const;
void loadNode(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const; void loadMasterExternalNode(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const;
void fillTreeItem(QTreeWidgetItem *p_item, Node *p_node, bool p_loaded) const; void fillMasterItem(QTreeWidgetItem *p_item, Node *p_node, bool p_loaded) const;
void fillTreeItem(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const; void fillMasterItem(QTreeWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const;
const QIcon &getNodeItemIcon(const Node *p_node) const; void fillSlaveItem(QListWidgetItem *p_item, Node *p_node) const;
const QIcon &getNodeItemIcon(const ExternalNode *p_node) const; void fillSlaveItem(QListWidgetItem *p_item, const QSharedPointer<ExternalNode> &p_node) const;
const QIcon &getIcon(const Node *p_node) const;
const QIcon &getIcon(const ExternalNode *p_node) const;
void initNodeIcons() const; void initNodeIcons() const;
QTreeWidgetItem *findNode(const Node *p_node) const; QTreeWidgetItem *findMasterNode(const Node *p_node) const;
QTreeWidgetItem *findNode(QTreeWidgetItem *p_item, const Node *p_node) const; QTreeWidgetItem *findMasterNode(QTreeWidgetItem *p_item, const Node *p_node) const;
QTreeWidgetItem *findNodeChild(QTreeWidgetItem *p_item, const Node *p_node) const; QTreeWidgetItem *findMasterNodeInDirectChildren(QTreeWidgetItem *p_item, const Node *p_node) const;
QTreeWidgetItem *findNodeTopLevelItem(QTreeWidget *p_tree, const Node *p_node) const; QTreeWidgetItem *findMasterNodeInTopLevelItems(QTreeWidget *p_tree, const Node *p_node) const;
void saveNotebookTreeState(bool p_saveCurrentItem = true); QListWidgetItem *findSlaveNode(const Node *p_node) const;
QSharedPointer<QTreeWidgetStateCache<Node *>> stateCache() const; void cacheState(bool p_saveCurrent);
void clearStateCache(const Notebook *p_notebook); // Get cache data of current notebook.
CacheData &getCache() const;
void createContextMenuOnRoot(QMenu *p_menu); void clearCache(const Notebook *p_notebook);
void createContextMenuOnNode(QMenu *p_menu, const Node *p_node); void createMasterContextMenuOnRoot(QMenu *p_menu);
void createContextMenuOnExternalNode(QMenu *p_menu, const ExternalNode *p_node); void createContextMenuOnNode(QMenu *p_menu, const Node *p_node, bool p_master);
void createContextMenuOnExternalNode(QMenu *p_menu, const ExternalNode *p_node, bool p_master);
void createSlaveContextMenuOnMasterNode(QMenu *p_menu);
// 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, bool p_master);
QAction *createAndAddAction(Action p_act, QMenu *p_menu); QAction *createAndAddAction(Action p_act, QMenu *p_menu, bool p_master = true);
void copySelectedNodes(bool p_move); void copySelectedNodes(bool p_move, bool p_master);
void pasteNodesFromClipboard(); void pasteNodesFromClipboard();
QPair<QVector<Node *>, QVector<QSharedPointer<ExternalNode>>> getSelectedNodes() const; QPair<QVector<Node *>, QVector<QSharedPointer<ExternalNode>>> getMasterSelectedNodesAndExternalNodes() const;
void removeSelectedNodes(); QPair<QVector<Node *>, QVector<QSharedPointer<ExternalNode>>> getSlaveSelectedNodesAndExternalNodes() const;
void removeSelectedNodesFromConfig(); void removeSelectedNodes(bool p_master);
void removeSelectedNodesFromConfig(bool p_master);
QVector<Node *> confirmSelectedNodes(const QString &p_title, QVector<Node *> confirmSelectedNodes(const QString &p_title,
const QString &p_text, const QString &p_text,
const QString &p_info) const; const QString &p_info,
bool p_master) const;
static QSharedPointer<ClipboardData> tryFetchClipboardData(); static QSharedPointer<ClipboardData> tryFetchClipboardData();
bool isPasteOnNodeAvailable(const Node *p_node) const; bool isPasteOnNodeAvailable(const Node *p_node) const;
void setNodeExpanded(const Node *p_node, bool p_expanded); void setMasterNodeExpanded(const Node *p_node, bool p_expanded);
// Select both master and slave nodes.
void selectNodes(const QVector<const Node *> &p_nodes); void selectNodes(const QVector<const Node *> &p_nodes);
void removeNodes(QVector<Node *> p_nodes, bool p_configOnly); void removeNodes(QVector<Node *> p_nodes, bool p_configOnly);
@ -240,19 +271,19 @@ namespace vnotex
void updateAndExpandNode(Node *p_node); void updateAndExpandNode(Node *p_node);
// Check if all selected items are the same type for operations. // Check if all selected items are the same type for operations.
bool allSelectedItemsSameType() const; bool isMasterAllSelectedItemsSameType() const;
bool isSlaveAllSelectedItemsSameType() const;
void focusNormalNode(); void focusNormalNode();
void sortNodes(QVector<QSharedPointer<Node>> &p_nodes) const; void sortNodes(QVector<QSharedPointer<Node>> &p_nodes) const;
// [p_start, p_end). // [p_start, p_end).
void sortNodes(QVector<QSharedPointer<Node>> &p_nodes, int p_start, int p_end, int p_viewOrder) const; void sortNodes(QVector<QSharedPointer<Node>> &p_nodes, int p_start, int p_end, ViewOrder p_viewOrder) const;
// Sort nodes in config file. // Sort nodes in config file.
void manualSort(); void manualSort(bool p_master);
void openSelectedNodes();
QSharedPointer<Node> importToIndex(QSharedPointer<ExternalNode> p_node); QSharedPointer<Node> importToIndex(QSharedPointer<ExternalNode> p_node);
@ -262,33 +293,67 @@ namespace vnotex
// Return true if it is invalid. // Return true if it is invalid.
bool checkInvalidNode(Node *p_node) const; bool checkInvalidNode(Node *p_node) const;
void expandCurrentNodeAll(); void addOpenWithMenu(QMenu *p_menu, bool p_master);
void expandItemRecursively(QTreeWidgetItem *p_item); QStringList getSelectedNodesPath(bool p_master) const;
void addOpenWithMenu(QMenu *p_menu); void openSelectedNodesWithCommand(const QString &p_command, bool p_master);
QStringList getSelectedNodesPath() const; bool belongsToMasterExplorer(const Node *p_node) const;
void openSelectedNodesWithDefaultProgram(); bool belongsToMasterExplorer(const ExternalNode *p_node) const;
void openSelectedNodesWithExternalProgram(const QString &p_command); void updateSlaveExplorer();
Node *getCurrentMasterNode() const;
Node *getCurrentSlaveNode() const;
NodeData getCurrentMasterNodeData() const;
NodeData getCurrentSlaveNodeData() const;
Node *getSlaveExplorerMasterNode() const;
bool isCombinedExploreMode() const;
// Update the tree of @p_node if there is any. Or update the node itself if it is in slave explorer.
// If @p_node is null, update the whole tree.
void updateNode(Node *p_node);
void setCurrentMasterNode(Node *p_node);
void setCurrentSlaveNode(const Node *p_node);
void setCurrentSlaveNode(const QString &p_name);
void activateItemNode(const NodeData &p_data);
static NotebookNodeExplorer::NodeData getItemNodeData(const QTreeWidgetItem *p_item); static NotebookNodeExplorer::NodeData getItemNodeData(const QTreeWidgetItem *p_item);
static NotebookNodeExplorer::NodeData getItemNodeData(const QListWidgetItem *p_item);
static void setItemNodeData(QTreeWidgetItem *p_item, const NodeData &p_data); static void setItemNodeData(QTreeWidgetItem *p_item, const NodeData &p_data);
static void setItemNodeData(QListWidgetItem *p_item, const NodeData &p_data);
QSplitter *m_splitter = nullptr; QSplitter *m_splitter = nullptr;
TreeWidget *m_masterExplorer = nullptr; TreeWidget *m_masterExplorer = nullptr;
ListWidget *m_slaveExplorer = nullptr;
QSharedPointer<Notebook> m_notebook; QSharedPointer<Notebook> m_notebook;
QHash<const Notebook *, QSharedPointer<QTreeWidgetStateCache<Node *>>> m_stateCache; QHash<const Notebook *, CacheData> m_cache;
QScopedPointer<NavigationModeWrapper<QTreeWidget, QTreeWidgetItem>> m_navigationWrapper; QScopedPointer<NavigationModeWrapper<QTreeWidget, QTreeWidgetItem>> m_masterNavigationWrapper;
int m_viewOrder = ViewOrder::OrderedByConfiguration; QScopedPointer<NavigationModeWrapper<QListWidget, QListWidgetItem>> m_slaveNavigationWrapper;
ViewOrder m_viewOrder = ViewOrder::OrderedByConfiguration;
ExploreMode m_exploreMode = ExploreMode::Combined;
bool m_externalFilesVisible = true; bool m_externalFilesVisible = true;

View File

@ -265,3 +265,20 @@ void TreeWidget::unmark(QTreeWidgetItem *p_item, int p_column)
p_item->setData(p_column, Qt::ForegroundRole, QVariant()); p_item->setData(p_column, Qt::ForegroundRole, QVariant());
p_item->setData(p_column, Qt::BackgroundRole, QVariant()); p_item->setData(p_column, Qt::BackgroundRole, QVariant());
} }
void TreeWidget::expandRecursively(QTreeWidgetItem *p_item)
{
if (!p_item) {
return;
}
p_item->setExpanded(true);
const int cnt = p_item->childCount();
if (cnt == 0) {
return;
}
for (int i = 0; i < cnt; ++i) {
expandRecursively(p_item->child(i));
}
}

View File

@ -42,6 +42,8 @@ namespace vnotex
// @p_func: return false to abort the iteration. // @p_func: return false to abort the iteration.
static void forEachItem(const QTreeWidget *p_widget, const std::function<bool(QTreeWidgetItem *p_item)> &p_func); static void forEachItem(const QTreeWidget *p_widget, const std::function<bool(QTreeWidgetItem *p_item)> &p_func);
static void expandRecursively(QTreeWidgetItem *p_item);
signals: signals:
// Emit when single item is selected and Drag&Drop to move internally. // Emit when single item is selected and Drag&Drop to move internally.
void itemMoved(QTreeWidgetItem *p_item); void itemMoved(QTreeWidgetItem *p_item);