Outline: support increase/decrease the expanded level

Add config [global]/outline_expanded_level (6 by default).
This commit is contained in:
Le Tan 2018-07-04 19:07:43 +08:00
parent 4f4652dc3a
commit 5ebc7b8243
8 changed files with 224 additions and 52 deletions

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#000000" d="M213.7,256L213.7,256L213.7,256L380.9,81.9c4.2-4.3,4.1-11.4-0.2-15.8l-29.9-30.6c-4.3-4.4-11.3-4.5-15.5-0.2L131.1,247.9
c-2.2,2.2-3.2,5.2-3,8.1c-0.1,3,0.9,5.9,3,8.1l204.2,212.7c4.2,4.3,11.2,4.2,15.5-0.2l29.9-30.6c4.3-4.4,4.4-11.5,0.2-15.8
L213.7,256z"/>
</svg>

After

Width:  |  Height:  |  Size: 768 B

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#000000" d="M298.3,256L298.3,256L298.3,256L131.1,81.9c-4.2-4.3-4.1-11.4,0.2-15.8l29.9-30.6c4.3-4.4,11.3-4.5,15.5-0.2l204.2,212.7
c2.2,2.2,3.2,5.2,3,8.1c0.1,3-0.9,5.9-3,8.1L176.7,476.8c-4.2,4.3-11.2,4.2-15.5-0.2L131.3,446c-4.3-4.4-4.4-11.5-0.2-15.8
L298.3,256z"/>
</svg>

After

Width:  |  Height:  |  Size: 767 B

View File

@ -229,6 +229,10 @@ history_size=50
; 6 - modified time reverse ; 6 - modified time reverse
note_list_view_order=0 note_list_view_order=0
; Level of the heading the outline should be expanded to
; 1 - 6
outline_expanded_level=6
[export] [export]
; Path of the wkhtmltopdf tool ; Path of the wkhtmltopdf tool
wkhtmltopdf=wkhtmltopdf wkhtmltopdf=wkhtmltopdf

View File

@ -300,6 +300,9 @@ void VConfigManager::initialize()
if (m_historySize < 0) { if (m_historySize < 0) {
m_historySize = 0; m_historySize = 0;
} }
m_outlineExpandedLevel = getConfigFromSettings("global",
"outline_expanded_level").toInt();
} }
void VConfigManager::initSettings() void VConfigManager::initSettings()

View File

@ -519,6 +519,9 @@ public:
int getNoteListViewOrder() const; int getNoteListViewOrder() const;
void setNoteListViewOrder(int p_order); void setNoteListViewOrder(int p_order);
int getOutlineExpandedLevel() const;
void setOutlineExpandedLevel(int p_level);
private: private:
// Look up a config from user and default settings. // Look up a config from user and default settings.
QVariant getConfigFromSettings(const QString &section, const QString &key) const; QVariant getConfigFromSettings(const QString &section, const QString &key) const;
@ -935,6 +938,9 @@ private:
// Whether user has reset the configurations. // Whether user has reset the configurations.
bool m_hasReset; bool m_hasReset;
// Expanded level of outline.
int m_outlineExpandedLevel;
// The name of the config file in each directory. // The name of the config file in each directory.
static const QString c_dirConfigFile; static const QString c_dirConfigFile;
@ -2433,4 +2439,19 @@ inline QString VConfigManager::fetchDirConfigFilePath(const QString &p_path)
{ {
return QDir(p_path).filePath(c_dirConfigFile); return QDir(p_path).filePath(c_dirConfigFile);
} }
inline int VConfigManager::getOutlineExpandedLevel() const
{
return m_outlineExpandedLevel;
}
inline void VConfigManager::setOutlineExpandedLevel(int p_level)
{
if (m_outlineExpandedLevel == p_level) {
return;
}
m_outlineExpandedLevel = p_level;
setConfigToSettings("global", "outline_expanded_level", m_outlineExpandedLevel);
}
#endif // VCONFIGMANAGER_H #endif // VCONFIGMANAGER_H

View File

@ -263,5 +263,7 @@
<file>resources/icons/tag.svg</file> <file>resources/icons/tag.svg</file>
<file>resources/view_image.js</file> <file>resources/view_image.js</file>
<file>resources/view_image.css</file> <file>resources/view_image.css</file>
<file>resources/icons/decrease_outline_level.svg</file>
<file>resources/icons/increase_outline_level.svg</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -1,27 +1,111 @@
#include <QVector>
#include <QString>
#include <QKeyEvent>
#include <QLabel>
#include <QCoreApplication>
#include "voutline.h" #include "voutline.h"
#include <QtWidgets>
#include <QCoreApplication>
#include "utils/vutils.h" #include "utils/vutils.h"
#include "vnote.h" #include "vnote.h"
#include "vfile.h" #include "vfile.h"
#include "vtreewidget.h"
#include "utils/viconutils.h"
#include "vconfigmanager.h"
#include "vmainwindow.h"
extern VNote *g_vnote; extern VNote *g_vnote;
extern VConfigManager *g_config;
extern VMainWindow *g_mainWin;
#define STATIC_EXPANDED_LEVEL 6
VOutline::VOutline(QWidget *parent) VOutline::VOutline(QWidget *parent)
: VTreeWidget(parent), : QWidget(parent),
VNavigationMode(), VNavigationMode(),
m_muted(false) m_muted(false)
{ {
setColumnCount(1); setupUI();
setHeaderHidden(true);
setSelectionMode(QAbstractItemView::SingleSelection);
m_expandTimer = new QTimer(this);
m_expandTimer->setSingleShot(true);
m_expandTimer->setInterval(1000);
connect(m_expandTimer, &QTimer::timeout,
this, [this]() {
// Auto adjust items after current header change.
int level = g_config->getOutlineExpandedLevel();
if (level == STATIC_EXPANDED_LEVEL) {
return;
}
expandTree(level);
QTreeWidgetItem *curItem = m_tree->currentItem();
if (curItem) {
m_tree->scrollToItem(curItem);
}
});
}
void VOutline::setupUI()
{
m_deLevelBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/decrease_outline_level.svg"),
"",
this);
m_deLevelBtn->setToolTip(tr("Decrease Expanded Level"));
m_deLevelBtn->setProperty("FlatBtn", true);
m_deLevelBtn->setEnabled(false);
connect(m_deLevelBtn, &QPushButton::clicked,
this, [this]() {
int level = g_config->getOutlineExpandedLevel() - 1;
if (level <= 0) {
level = 1;
} else {
g_config->setOutlineExpandedLevel(level);
expandTree(level);
}
g_mainWin->showStatusMessage(tr("Set Outline Expanded Level to %1").arg(level));
});
m_inLevelBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/increase_outline_level.svg"),
"",
this);
m_inLevelBtn->setToolTip(tr("Increase Expanded Level"));
m_inLevelBtn->setProperty("FlatBtn", true);
m_inLevelBtn->setEnabled(false);
connect(m_inLevelBtn, &QPushButton::clicked,
this, [this]() {
int level = g_config->getOutlineExpandedLevel() + 1;
if (level >= 7) {
level = 6;
} else {
g_config->setOutlineExpandedLevel(level);
expandTree(level);
}
g_mainWin->showStatusMessage(tr("Set Outline Expanded Level to %1").arg(level));
});
QHBoxLayout *btnLayout = new QHBoxLayout();
btnLayout->addStretch();
btnLayout->addWidget(m_deLevelBtn);
btnLayout->addWidget(m_inLevelBtn);
btnLayout->setContentsMargins(0, 0, 0, 0);
m_tree = new VTreeWidget(this);
m_tree->setColumnCount(1);
m_tree->setHeaderHidden(true);
m_tree->setSelectionMode(QAbstractItemView::SingleSelection);
// TODO: jump to the header when user click the same item twice. // TODO: jump to the header when user click the same item twice.
connect(this, &VOutline::currentItemChanged, connect(m_tree, &QTreeWidget::currentItemChanged,
this, &VOutline::handleCurrentItemChanged); this, &VOutline::handleCurrentItemChanged);
QVBoxLayout *layout = new QVBoxLayout();
layout->addLayout(btnLayout);
layout->addWidget(m_tree);
layout->setContentsMargins(3, 0, 3, 0);
setLayout(layout);
} }
void VOutline::updateOutline(const VTableOfContent &p_outline) void VOutline::updateOutline(const VTableOfContent &p_outline)
@ -35,9 +119,11 @@ void VOutline::updateOutline(const VTableOfContent &p_outline)
m_outline = p_outline; m_outline = p_outline;
updateTreeFromOutline(this, m_outline); updateTreeFromOutline(m_tree, m_outline);
expandTree(); updateButtonsState();
expandTree(g_config->getOutlineExpandedLevel());
} }
void VOutline::updateTreeFromOutline(QTreeWidget *p_treeWidget, void VOutline::updateTreeFromOutline(QTreeWidget *p_treeWidget,
@ -94,13 +180,42 @@ void VOutline::fillItem(QTreeWidgetItem *p_item, const VTableOfContentItem &p_he
} }
} }
void VOutline::expandTree() void VOutline::expandTree(int p_expandedLevel)
{ {
if (topLevelItemCount() == 0) { int topCount = m_tree->topLevelItemCount();
if (topCount == 0) {
return; return;
} }
expandAll(); m_tree->collapseAll();
// Get the base level.
const VTableOfContentItem *header = getHeaderFromItem(m_tree->topLevelItem(0), m_outline);
if (!header) {
return;
}
int baseLevel = header->m_level;
int levelToBeExpanded = p_expandedLevel - baseLevel;
for (int i = 0; i < topCount; ++i) {
expandTreeOne(m_tree->topLevelItem(i), levelToBeExpanded);
}
}
void VOutline::expandTreeOne(QTreeWidgetItem *p_item, int p_levelToBeExpanded)
{
if (p_levelToBeExpanded <= 0) {
return;
}
// Expand this item.
p_item->setExpanded(true);
int nrChild = p_item->childCount();
for (int i = 0; i < nrChild; ++i) {
expandTreeOne(p_item->child(i), p_levelToBeExpanded - 1);
}
} }
void VOutline::handleCurrentItemChanged(QTreeWidgetItem *p_curItem, void VOutline::handleCurrentItemChanged(QTreeWidgetItem *p_curItem,
@ -131,8 +246,10 @@ void VOutline::updateCurrentHeader(const VHeaderPointer &p_header)
// Item change should not emit the signal. // Item change should not emit the signal.
m_muted = true; m_muted = true;
m_currentHeader = p_header; m_currentHeader = p_header;
selectHeader(this, m_outline, m_currentHeader); selectHeader(m_tree, m_outline, m_currentHeader);
m_muted = false; m_muted = false;
m_expandTimer->start();
} }
void VOutline::selectHeader(QTreeWidget *p_treeWidget, void VOutline::selectHeader(QTreeWidget *p_treeWidget,
@ -184,59 +301,35 @@ bool VOutline::selectHeaderOne(QTreeWidget *p_treeWidget,
void VOutline::keyPressEvent(QKeyEvent *event) void VOutline::keyPressEvent(QKeyEvent *event)
{ {
int key = event->key(); switch (event->key()) {
int modifiers = event->modifiers();
switch (key) {
case Qt::Key_Return: case Qt::Key_Return:
V_FALLTHROUGH;
case Qt::Key_Enter:
{ {
QTreeWidgetItem *item = currentItem(); QTreeWidgetItem *item = m_tree->currentItem();
if (item) { if (item) {
item->setExpanded(!item->isExpanded()); item->setExpanded(!item->isExpanded());
} }
break;
}
case Qt::Key_J:
{
if (modifiers == Qt::ControlModifier) {
event->accept();
QKeyEvent *downEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down,
Qt::NoModifier);
QCoreApplication::postEvent(this, downEvent);
return; return;
} }
break;
}
case Qt::Key_K:
{
if (modifiers == Qt::ControlModifier) {
event->accept();
QKeyEvent *upEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up,
Qt::NoModifier);
QCoreApplication::postEvent(this, upEvent);
return;
}
break;
}
default: default:
break; break;
} }
VTreeWidget::keyPressEvent(event); QWidget::keyPressEvent(event);
} }
void VOutline::showNavigation() void VOutline::showNavigation()
{ {
VNavigationMode::showNavigation(this); VNavigationMode::showNavigation(m_tree);
} }
bool VOutline::handleKeyNavigation(int p_key, bool &p_succeed) bool VOutline::handleKeyNavigation(int p_key, bool &p_succeed)
{ {
static bool secondKey = false; static bool secondKey = false;
return VNavigationMode::handleKeyNavigation(this, return VNavigationMode::handleKeyNavigation(m_tree,
secondKey, secondKey,
p_key, p_key,
p_succeed); p_succeed);
@ -248,3 +341,17 @@ const VTableOfContentItem *VOutline::getHeaderFromItem(QTreeWidgetItem *p_item,
int index = p_item->data(0, Qt::UserRole).toInt(); int index = p_item->data(0, Qt::UserRole).toInt();
return p_outline.getItem(index); return p_outline.getItem(index);
} }
void VOutline::focusInEvent(QFocusEvent *p_event)
{
QWidget::focusInEvent(p_event);
m_tree->setFocus();
}
void VOutline::updateButtonsState()
{
bool empty = m_outline.isEmpty();
m_deLevelBtn->setEnabled(!empty);
m_inLevelBtn->setEnabled(!empty);
}

View File

@ -1,19 +1,22 @@
#ifndef VOUTLINE_H #ifndef VOUTLINE_H
#define VOUTLINE_H #define VOUTLINE_H
#include <QWidget>
#include <QVector> #include <QVector>
#include <QMap> #include <QMap>
#include <QChar> #include <QChar>
#include "vtreewidget.h"
#include "vtableofcontent.h" #include "vtableofcontent.h"
#include "vnavigationmode.h" #include "vnavigationmode.h"
class QLabel; class QLabel;
class VTreeWidget;
class QPushButton;
class QTimer;
// Display table of content as a tree and enable user to click an item to // Display table of content as a tree and enable user to click an item to
// jump to that header. // jump to that header.
class VOutline : public VTreeWidget, public VNavigationMode class VOutline : public QWidget, public VNavigationMode
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -52,12 +55,22 @@ public slots:
protected: protected:
void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
void focusInEvent(QFocusEvent *p_event) Q_DECL_OVERRIDE;
private slots: private slots:
// Handle current item change even of the tree. // Handle current item change even of the tree.
// Do not response if m_muted is true. // Do not response if m_muted is true.
void handleCurrentItemChanged(QTreeWidgetItem *p_curItem, QTreeWidgetItem *p_preItem); void handleCurrentItemChanged(QTreeWidgetItem *p_curItem, QTreeWidgetItem *p_preItem);
private: private:
void setupUI();
void expandTree(int p_expandedLevel = 6);
void expandTreeOne(QTreeWidgetItem *p_item, int p_levelToBeExpanded);
void updateButtonsState();
// @index: the index in @headers. // @index: the index in @headers.
static void updateTreeByLevel(QTreeWidget *p_treeWidget, static void updateTreeByLevel(QTreeWidget *p_treeWidget,
const QVector<VTableOfContentItem> &p_headers, const QVector<VTableOfContentItem> &p_headers,
@ -69,8 +82,6 @@ private:
// Fill the info of @p_item. // Fill the info of @p_item.
static void fillItem(QTreeWidgetItem *p_item, const VTableOfContentItem &p_header); static void fillItem(QTreeWidgetItem *p_item, const VTableOfContentItem &p_header);
void expandTree();
static bool selectHeaderOne(QTreeWidget *p_treeWidget, static bool selectHeaderOne(QTreeWidget *p_treeWidget,
QTreeWidgetItem *p_item, QTreeWidgetItem *p_item,
const VTableOfContent &p_outline, const VTableOfContent &p_outline,
@ -82,6 +93,12 @@ private:
// When true, won't emit outlineItemActivated(). // When true, won't emit outlineItemActivated().
bool m_muted; bool m_muted;
QTimer *m_expandTimer;
QPushButton *m_deLevelBtn;
QPushButton *m_inLevelBtn;
VTreeWidget *m_tree;
}; };
#endif // VOUTLINE_H #endif // VOUTLINE_H