mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
TagExplorer: add explorer for tags
This commit is contained in:
parent
f94169053e
commit
13c2d143bb
11
src/resources/icons/tag.svg
Normal file
11
src/resources/icons/tag.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?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" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#000000" d="M464,32H304L48,320l160,160l256-288V32z M448,184L208.125,456L72.062,320L311.587,48H448V184z"/>
|
||||||
|
<path fill="#000000" d="M368,160c17.645,0,32-14.355,32-32s-14.355-32-32-32s-32,14.355-32,32S350.355,160,368,160z M368,112
|
||||||
|
c8.836,0,16,7.163,16,16s-7.164,16-16,16s-16-7.163-16-16S359.164,112,368,112z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 810 B |
12
src/resources/icons/tag_explorer.svg
Normal file
12
src/resources/icons/tag_explorer.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?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" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#000000" d="M448,64V32H288L32,320l160,160l23.471-23.904L240,480l240-272V64H448z M192,457.371L54.39,320L294.621,48H432v16v16
|
||||||
|
v105.377l-216.555,247.99l-11.34,11.363L192,457.371z M464,201.377L240,457.371l-13.182-12.65L448,192V80h16V201.377z"/>
|
||||||
|
<path fill="#000000" d="M352,160c17.645,0,32-14.355,32-32s-14.355-32-32-32s-32,14.355-32,32S334.355,160,352,160z M352,112
|
||||||
|
c8.836,0,16,7.163,16,16s-7.164,16-16,16s-16-7.163-16-16S343.164,112,352,112z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 947 B |
@ -139,7 +139,8 @@ SOURCES += main.cpp\
|
|||||||
utils/vprocessutils.cpp \
|
utils/vprocessutils.cpp \
|
||||||
vtagpanel.cpp \
|
vtagpanel.cpp \
|
||||||
valltagspanel.cpp \
|
valltagspanel.cpp \
|
||||||
vtaglabel.cpp
|
vtaglabel.cpp \
|
||||||
|
vtagexplorer.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -272,7 +273,8 @@ HEADERS += vmainwindow.h \
|
|||||||
utils/vprocessutils.h \
|
utils/vprocessutils.h \
|
||||||
vtagpanel.h \
|
vtagpanel.h \
|
||||||
valltagspanel.h \
|
valltagspanel.h \
|
||||||
vtaglabel.h
|
vtaglabel.h \
|
||||||
|
vtagexplorer.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc \
|
vnote.qrc \
|
||||||
|
@ -194,6 +194,9 @@ public:
|
|||||||
const QByteArray getNotebookSplitterState() const;
|
const QByteArray getNotebookSplitterState() const;
|
||||||
void setNotebookSplitterState(const QByteArray &p_state);
|
void setNotebookSplitterState(const QByteArray &p_state);
|
||||||
|
|
||||||
|
const QByteArray getTagExplorerSplitterState() const;
|
||||||
|
void setTagExplorerSplitterState(const QByteArray &p_state);
|
||||||
|
|
||||||
bool getFindCaseSensitive() const;
|
bool getFindCaseSensitive() const;
|
||||||
void setFindCaseSensitive(bool p_enabled);
|
void setFindCaseSensitive(bool p_enabled);
|
||||||
|
|
||||||
@ -1304,6 +1307,19 @@ inline void VConfigManager::setNotebookSplitterState(const QByteArray &p_state)
|
|||||||
p_state);
|
p_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const QByteArray VConfigManager::getTagExplorerSplitterState() const
|
||||||
|
{
|
||||||
|
return getConfigFromSessionSettings("geometry",
|
||||||
|
"tag_explorer_splitter_state").toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VConfigManager::setTagExplorerSplitterState(const QByteArray &p_state)
|
||||||
|
{
|
||||||
|
setConfigToSessionSettings("geometry",
|
||||||
|
"tag_explorer_splitter_state",
|
||||||
|
p_state);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool VConfigManager::getFindCaseSensitive() const
|
inline bool VConfigManager::getFindCaseSensitive() const
|
||||||
{
|
{
|
||||||
return m_findCaseSensitive;
|
return m_findCaseSensitive;
|
||||||
|
@ -460,7 +460,7 @@ void VHistoryList::openItem(const QListWidgetItem *p_item) const
|
|||||||
g_mainWin->openFiles(files);
|
g_mainWin->openFiles(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VHistoryList::locateCurrentItem()
|
void VHistoryList::locateCurrentItem() const
|
||||||
{
|
{
|
||||||
auto item = m_itemList->currentItem();
|
auto item = m_itemList->currentItem();
|
||||||
if (!item) {
|
if (!item) {
|
||||||
|
@ -48,7 +48,7 @@ private slots:
|
|||||||
|
|
||||||
void unpinSelectedItems();
|
void unpinSelectedItems();
|
||||||
|
|
||||||
void locateCurrentItem();
|
void locateCurrentItem() const;
|
||||||
|
|
||||||
// Add selected files to Cart.
|
// Add selected files to Cart.
|
||||||
void addFileToCart() const;
|
void addFileToCart() const;
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "vhistorylist.h"
|
#include "vhistorylist.h"
|
||||||
#include "vexplorer.h"
|
#include "vexplorer.h"
|
||||||
#include "vlistue.h"
|
#include "vlistue.h"
|
||||||
|
#include "vtagexplorer.h"
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
@ -291,6 +292,13 @@ void VMainWindow::setupNaviBox()
|
|||||||
m_naviBox->addItem(m_explorer,
|
m_naviBox->addItem(m_explorer,
|
||||||
":/resources/icons/explorer.svg",
|
":/resources/icons/explorer.svg",
|
||||||
tr("Explorer"));
|
tr("Explorer"));
|
||||||
|
|
||||||
|
m_tagExplorer = new VTagExplorer();
|
||||||
|
m_naviBox->addItem(m_tagExplorer,
|
||||||
|
":/resources/icons/tag_explorer.svg",
|
||||||
|
tr("Tags"));
|
||||||
|
connect(m_notebookSelector, &VNotebookSelector::curNotebookChanged,
|
||||||
|
m_tagExplorer, &VTagExplorer::setNotebook);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::setupNotebookPanel()
|
void VMainWindow::setupNotebookPanel()
|
||||||
@ -2177,17 +2185,18 @@ void VMainWindow::saveStateAndGeometry()
|
|||||||
g_config->setSearchDockChecked(m_searchDock->isVisible());
|
g_config->setSearchDockChecked(m_searchDock->isVisible());
|
||||||
g_config->setNotebookSplitterState(m_nbSplitter->saveState());
|
g_config->setNotebookSplitterState(m_nbSplitter->saveState());
|
||||||
g_config->setMainSplitterState(m_mainSplitter->saveState());
|
g_config->setMainSplitterState(m_mainSplitter->saveState());
|
||||||
|
m_tagExplorer->saveStateAndGeometry();
|
||||||
g_config->setNaviBoxCurrentIndex(m_naviBox->currentIndex());
|
g_config->setNaviBoxCurrentIndex(m_naviBox->currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::restoreStateAndGeometry()
|
void VMainWindow::restoreStateAndGeometry()
|
||||||
{
|
{
|
||||||
const QByteArray &geometry = g_config->getMainWindowGeometry();
|
const QByteArray geometry = g_config->getMainWindowGeometry();
|
||||||
if (!geometry.isEmpty()) {
|
if (!geometry.isEmpty()) {
|
||||||
restoreGeometry(geometry);
|
restoreGeometry(geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray &state = g_config->getMainWindowState();
|
const QByteArray state = g_config->getMainWindowState();
|
||||||
if (!state.isEmpty()) {
|
if (!state.isEmpty()) {
|
||||||
restoreState(state);
|
restoreState(state);
|
||||||
}
|
}
|
||||||
@ -2195,12 +2204,12 @@ void VMainWindow::restoreStateAndGeometry()
|
|||||||
m_toolDock->setVisible(g_config->getToolsDockChecked());
|
m_toolDock->setVisible(g_config->getToolsDockChecked());
|
||||||
m_searchDock->setVisible(g_config->getSearchDockChecked());
|
m_searchDock->setVisible(g_config->getSearchDockChecked());
|
||||||
|
|
||||||
const QByteArray &splitterState = g_config->getMainSplitterState();
|
const QByteArray splitterState = g_config->getMainSplitterState();
|
||||||
if (!splitterState.isEmpty()) {
|
if (!splitterState.isEmpty()) {
|
||||||
m_mainSplitter->restoreState(splitterState);
|
m_mainSplitter->restoreState(splitterState);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray &nbSplitterState = g_config->getNotebookSplitterState();
|
const QByteArray nbSplitterState = g_config->getNotebookSplitterState();
|
||||||
if (!nbSplitterState.isEmpty()) {
|
if (!nbSplitterState.isEmpty()) {
|
||||||
m_nbSplitter->restoreState(nbSplitterState);
|
m_nbSplitter->restoreState(nbSplitterState);
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ class QPrinter;
|
|||||||
class VUniversalEntry;
|
class VUniversalEntry;
|
||||||
class VHistoryList;
|
class VHistoryList;
|
||||||
class VExplorer;
|
class VExplorer;
|
||||||
|
class VTagExplorer;
|
||||||
|
|
||||||
enum class PanelViewState
|
enum class PanelViewState
|
||||||
{
|
{
|
||||||
@ -462,6 +463,8 @@ private:
|
|||||||
|
|
||||||
VExplorer *m_explorer;
|
VExplorer *m_explorer;
|
||||||
|
|
||||||
|
VTagExplorer *m_tagExplorer;
|
||||||
|
|
||||||
// Interval of the shared memory timer in ms.
|
// Interval of the shared memory timer in ms.
|
||||||
static const int c_sharedMemTimerInterval;
|
static const int c_sharedMemTimerInterval;
|
||||||
};
|
};
|
||||||
|
@ -259,5 +259,7 @@
|
|||||||
<file>resources/themes/v_detorte/v_detorte_codeblock.css</file>
|
<file>resources/themes/v_detorte/v_detorte_codeblock.css</file>
|
||||||
<file>resources/themes/v_detorte/v_detorte_mermaid.css</file>
|
<file>resources/themes/v_detorte/v_detorte_mermaid.css</file>
|
||||||
<file>resources/icons/tags.svg</file>
|
<file>resources/icons/tags.svg</file>
|
||||||
|
<file>resources/icons/tag_explorer.svg</file>
|
||||||
|
<file>resources/icons/tag.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -442,3 +442,18 @@ bool VNotebook::addTag(const QString &p_tag)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNotebook::removeTag(const QString &p_tag)
|
||||||
|
{
|
||||||
|
if (p_tag.isEmpty() || m_tags.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nr = m_tags.removeAll(p_tag);
|
||||||
|
if (nr > 0) {
|
||||||
|
if (!writeConfigNotebook()) {
|
||||||
|
qWarning() << "fail to update config of notebook" << m_name
|
||||||
|
<< "in directory" << m_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -60,6 +60,8 @@ public:
|
|||||||
|
|
||||||
bool addTag(const QString &p_tag);
|
bool addTag(const QString &p_tag);
|
||||||
|
|
||||||
|
void removeTag(const QString &p_tag);
|
||||||
|
|
||||||
bool hasTag(const QString &p_tag) const;
|
bool hasTag(const QString &p_tag) const;
|
||||||
|
|
||||||
static VNotebook *createNotebook(const QString &p_name,
|
static VNotebook *createNotebook(const QString &p_name,
|
||||||
|
497
src/vtagexplorer.cpp
Normal file
497
src/vtagexplorer.cpp
Normal file
@ -0,0 +1,497 @@
|
|||||||
|
#include "vtagexplorer.h"
|
||||||
|
|
||||||
|
#include <QtWidgets>
|
||||||
|
|
||||||
|
#include "utils/viconutils.h"
|
||||||
|
#include "vmainwindow.h"
|
||||||
|
#include "vlistwidget.h"
|
||||||
|
#include "vnotebook.h"
|
||||||
|
#include "vconfigmanager.h"
|
||||||
|
#include "vsearch.h"
|
||||||
|
#include "vnote.h"
|
||||||
|
#include "vcart.h"
|
||||||
|
#include "vhistorylist.h"
|
||||||
|
#include "vnotefile.h"
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
|
||||||
|
extern VMainWindow *g_mainWin;
|
||||||
|
|
||||||
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
|
extern VNote *g_vnote;
|
||||||
|
|
||||||
|
#define MAX_DISPLAY_LENGTH 10
|
||||||
|
|
||||||
|
VTagExplorer::VTagExplorer(QWidget *p_parent)
|
||||||
|
: QWidget(p_parent),
|
||||||
|
m_uiInitialized(false),
|
||||||
|
m_notebook(NULL),
|
||||||
|
m_notebookChanged(true),
|
||||||
|
m_search(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::setupUI()
|
||||||
|
{
|
||||||
|
if (m_uiInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_uiInitialized = true;
|
||||||
|
|
||||||
|
m_notebookLabel = new QLabel(tr("Tags"), this);
|
||||||
|
m_notebookLabel->setProperty("TitleLabel", true);
|
||||||
|
|
||||||
|
m_tagList = new VListWidget(this);
|
||||||
|
m_tagList->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||||
|
connect(m_tagList, &QListWidget::itemActivated,
|
||||||
|
this, [this](const QListWidgetItem *p_item) {
|
||||||
|
QString tag;
|
||||||
|
if (p_item) {
|
||||||
|
tag = p_item->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = activateTag(tag);
|
||||||
|
if (ret && !tag.isEmpty() && m_fileList->count() == 0) {
|
||||||
|
promptToRemoveEmptyTag(tag);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_tagLabel = new QLabel(tr("Notes"), this);
|
||||||
|
m_tagLabel->setProperty("TitleLabel", true);
|
||||||
|
|
||||||
|
m_fileList = new VListWidget(this);
|
||||||
|
m_fileList->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||||
|
m_fileList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
m_fileList->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
connect(m_fileList, &QListWidget::itemActivated,
|
||||||
|
this, &VTagExplorer::openFileItem);
|
||||||
|
connect(m_fileList, &QListWidget::customContextMenuRequested,
|
||||||
|
this, &VTagExplorer::handleFileListContextMenuRequested);
|
||||||
|
|
||||||
|
QWidget *fileWidget = new QWidget(this);
|
||||||
|
QVBoxLayout *fileLayout = new QVBoxLayout();
|
||||||
|
fileLayout->addWidget(m_tagLabel);
|
||||||
|
fileLayout->addWidget(m_fileList);
|
||||||
|
fileLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
fileWidget->setLayout(fileLayout);
|
||||||
|
|
||||||
|
m_splitter = new QSplitter(this);
|
||||||
|
m_splitter->setOrientation(Qt::Vertical);
|
||||||
|
m_splitter->setObjectName("TagExplorerSplitter");
|
||||||
|
m_splitter->addWidget(m_tagList);
|
||||||
|
m_splitter->addWidget(fileWidget);
|
||||||
|
m_splitter->setStretchFactor(0, 0);
|
||||||
|
m_splitter->setStretchFactor(1, 1);
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout->addWidget(m_notebookLabel);
|
||||||
|
mainLayout->addWidget(m_splitter);
|
||||||
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
restoreStateAndGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::showEvent(QShowEvent *p_event)
|
||||||
|
{
|
||||||
|
setupUI();
|
||||||
|
QWidget::showEvent(p_event);
|
||||||
|
|
||||||
|
updateContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::focusInEvent(QFocusEvent *p_event)
|
||||||
|
{
|
||||||
|
setupUI();
|
||||||
|
QWidget::focusInEvent(p_event);
|
||||||
|
m_tagList->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::setNotebook(VNotebook *p_notebook)
|
||||||
|
{
|
||||||
|
if (p_notebook == m_notebook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupUI();
|
||||||
|
|
||||||
|
m_notebook = p_notebook;
|
||||||
|
m_notebookChanged = true;
|
||||||
|
|
||||||
|
if (!isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::updateContent()
|
||||||
|
{
|
||||||
|
if (m_notebook) {
|
||||||
|
updateNotebookLabel();
|
||||||
|
const QStringList &tags = m_notebook->getTags();
|
||||||
|
if (m_notebookChanged || tagListObsolete(tags)) {
|
||||||
|
updateTagList(tags);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_notebookChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::clear()
|
||||||
|
{
|
||||||
|
setupUI();
|
||||||
|
|
||||||
|
m_fileList->clearAll();
|
||||||
|
m_tagList->clearAll();
|
||||||
|
updateTagLabel("");
|
||||||
|
updateNotebookLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::updateNotebookLabel()
|
||||||
|
{
|
||||||
|
QString text = tr("Tags");
|
||||||
|
QString tooltip;
|
||||||
|
if (m_notebook) {
|
||||||
|
QString name = m_notebook->getName();
|
||||||
|
tooltip = name;
|
||||||
|
|
||||||
|
if (name.size() > MAX_DISPLAY_LENGTH) {
|
||||||
|
name = name.left(MAX_DISPLAY_LENGTH) + QStringLiteral("...");
|
||||||
|
}
|
||||||
|
|
||||||
|
text = tr("Tags (%1)").arg(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_notebookLabel->setText(text);
|
||||||
|
m_notebookLabel->setToolTip(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VTagExplorer::tagListObsolete(const QStringList &p_tags) const
|
||||||
|
{
|
||||||
|
if (m_tagList->count() != p_tags.size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < p_tags.size(); ++i) {
|
||||||
|
if (p_tags[i] != m_tagList->item(i)->text()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::updateTagLabel(const QString &p_tag)
|
||||||
|
{
|
||||||
|
QString text = tr("Notes");
|
||||||
|
QString tooltip;
|
||||||
|
if (!p_tag.isEmpty()) {
|
||||||
|
QString name = p_tag;
|
||||||
|
tooltip = name;
|
||||||
|
|
||||||
|
if (name.size() > MAX_DISPLAY_LENGTH) {
|
||||||
|
name = name.left(MAX_DISPLAY_LENGTH) + QStringLiteral("...");
|
||||||
|
}
|
||||||
|
|
||||||
|
text = tr("Notes (%1)").arg(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_tagLabel->setText(text);
|
||||||
|
m_tagLabel->setToolTip(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VTagExplorer::activateTag(const QString &p_tag)
|
||||||
|
{
|
||||||
|
updateTagLabel(p_tag);
|
||||||
|
|
||||||
|
m_fileList->clearAll();
|
||||||
|
|
||||||
|
if (p_tag.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search this tag within current notebook.
|
||||||
|
g_mainWin->showStatusMessage(tr("Searching for tag \"%1\"").arg(p_tag));
|
||||||
|
|
||||||
|
QVector<VNotebook *> notebooks;
|
||||||
|
notebooks.append(m_notebook);
|
||||||
|
getVSearch()->clear();
|
||||||
|
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::CurrentNotebook,
|
||||||
|
VSearchConfig::Tag,
|
||||||
|
VSearchConfig::Note,
|
||||||
|
VSearchConfig::Internal,
|
||||||
|
VSearchConfig::NoneOption,
|
||||||
|
p_tag,
|
||||||
|
QString()));
|
||||||
|
getVSearch()->setConfig(config);
|
||||||
|
QSharedPointer<VSearchResult> result = getVSearch()->search(notebooks);
|
||||||
|
|
||||||
|
bool ret = result->m_state == VSearchState::Success;
|
||||||
|
handleSearchFinished(result);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::updateTagList(const QStringList &p_tags)
|
||||||
|
{
|
||||||
|
// Clear.
|
||||||
|
m_tagList->clearAll();
|
||||||
|
activateTag("");
|
||||||
|
|
||||||
|
for (auto const & tag : p_tags) {
|
||||||
|
addTagItem(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_tagList->count() > 0) {
|
||||||
|
m_tagList->setCurrentRow(0, QItemSelectionModel::ClearAndSelect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::addTagItem(const QString &p_tag)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = new QListWidgetItem(VIconUtils::treeViewIcon(":/resources/icons/tag.svg"),
|
||||||
|
p_tag);
|
||||||
|
item->setToolTip(p_tag);
|
||||||
|
|
||||||
|
m_tagList->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::saveStateAndGeometry()
|
||||||
|
{
|
||||||
|
if (!m_uiInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_config->setTagExplorerSplitterState(m_splitter->saveState());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::restoreStateAndGeometry()
|
||||||
|
{
|
||||||
|
const QByteArray state = g_config->getTagExplorerSplitterState();
|
||||||
|
if (!state.isEmpty()) {
|
||||||
|
m_splitter->restoreState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::initVSearch()
|
||||||
|
{
|
||||||
|
m_search = new VSearch(this);
|
||||||
|
connect(m_search, &VSearch::resultItemAdded,
|
||||||
|
this, &VTagExplorer::handleSearchItemAdded);
|
||||||
|
connect(m_search, &VSearch::resultItemsAdded,
|
||||||
|
this, &VTagExplorer::handleSearchItemsAdded);
|
||||||
|
connect(m_search, &VSearch::finished,
|
||||||
|
this, &VTagExplorer::handleSearchFinished);
|
||||||
|
|
||||||
|
m_noteIcon = VIconUtils::treeViewIcon(":/resources/icons/note_item.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::handleSearchItemAdded(const QSharedPointer<VSearchResultItem> &p_item)
|
||||||
|
{
|
||||||
|
appendItemToFileList(p_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::appendItemToFileList(const QSharedPointer<VSearchResultItem> &p_item)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_item->m_type == VSearchResultItem::Note);
|
||||||
|
|
||||||
|
QListWidgetItem *item = new QListWidgetItem(m_noteIcon,
|
||||||
|
p_item->m_text.isEmpty() ? p_item->m_path : p_item->m_text);
|
||||||
|
item->setData(Qt::UserRole, p_item->m_path);
|
||||||
|
item->setToolTip(p_item->m_path);
|
||||||
|
m_fileList->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::handleSearchItemsAdded(const QList<QSharedPointer<VSearchResultItem> > &p_items)
|
||||||
|
{
|
||||||
|
for (auto const & it : p_items) {
|
||||||
|
appendItemToFileList(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::handleSearchFinished(const QSharedPointer<VSearchResult> &p_result)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_result->m_state != VSearchState::Idle);
|
||||||
|
QString msg;
|
||||||
|
switch (p_result->m_state) {
|
||||||
|
case VSearchState::Busy:
|
||||||
|
// Only synchronized search.
|
||||||
|
Q_ASSERT(false);
|
||||||
|
msg = tr("Invalid busy state when searching for tag");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchState::Success:
|
||||||
|
qDebug() << "search succeeded";
|
||||||
|
msg = tr("Search for tag succeeded");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchState::Fail:
|
||||||
|
qDebug() << "search failed";
|
||||||
|
msg = tr("Search for tag failed");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchState::Cancelled:
|
||||||
|
qDebug() << "search cancelled";
|
||||||
|
msg = tr("Search for tag calcelled");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_search->clear();
|
||||||
|
|
||||||
|
if (!msg.isEmpty()) {
|
||||||
|
g_mainWin->showStatusMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::openFileItem(QListWidgetItem *p_item) const
|
||||||
|
{
|
||||||
|
if (!p_item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList files;
|
||||||
|
files << getFilePath(p_item);
|
||||||
|
g_mainWin->openFiles(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::openSelectedFileItems() const
|
||||||
|
{
|
||||||
|
QStringList files;
|
||||||
|
QList<QListWidgetItem *> selectedItems = m_fileList->selectedItems();
|
||||||
|
for (auto it : selectedItems) {
|
||||||
|
files << getFilePath(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!files.isEmpty()) {
|
||||||
|
g_mainWin->openFiles(files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VTagExplorer::getFilePath(const QListWidgetItem *p_item) const
|
||||||
|
{
|
||||||
|
return p_item->data(Qt::UserRole).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::handleFileListContextMenuRequested(QPoint p_pos)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = m_fileList->itemAt(p_pos);
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu menu(this);
|
||||||
|
menu.setToolTipsVisible(true);
|
||||||
|
|
||||||
|
QAction *openAct = new QAction(tr("&Open"), &menu);
|
||||||
|
openAct->setToolTip(tr("Open selected notes"));
|
||||||
|
connect(openAct, &QAction::triggered,
|
||||||
|
this, &VTagExplorer::openSelectedFileItems);
|
||||||
|
menu.addAction(openAct);
|
||||||
|
|
||||||
|
QList<QListWidgetItem *> selectedItems = m_fileList->selectedItems();
|
||||||
|
if (selectedItems.size() == 1) {
|
||||||
|
QAction *locateAct = new QAction(VIconUtils::menuIcon(":/resources/icons/locate_note.svg"),
|
||||||
|
tr("&Locate To Folder"),
|
||||||
|
&menu);
|
||||||
|
locateAct->setToolTip(tr("Locate the folder of current note"));
|
||||||
|
connect(locateAct, &QAction::triggered,
|
||||||
|
this, &VTagExplorer::locateCurrentFileItem);
|
||||||
|
menu.addAction(locateAct);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.addSeparator();
|
||||||
|
|
||||||
|
QAction *addToCartAct = new QAction(VIconUtils::menuIcon(":/resources/icons/cart.svg"),
|
||||||
|
tr("Add To Cart"),
|
||||||
|
&menu);
|
||||||
|
addToCartAct->setToolTip(tr("Add selected notes to Cart for further processing"));
|
||||||
|
connect(addToCartAct, &QAction::triggered,
|
||||||
|
this, &VTagExplorer::addFileToCart);
|
||||||
|
menu.addAction(addToCartAct);
|
||||||
|
|
||||||
|
QAction *pinToHistoryAct = new QAction(VIconUtils::menuIcon(":/resources/icons/pin.svg"),
|
||||||
|
tr("Pin To History"),
|
||||||
|
&menu);
|
||||||
|
pinToHistoryAct->setToolTip(tr("Pin selected notes to History"));
|
||||||
|
connect(pinToHistoryAct, &QAction::triggered,
|
||||||
|
this, &VTagExplorer::pinFileToHistory);
|
||||||
|
menu.addAction(pinToHistoryAct);
|
||||||
|
|
||||||
|
menu.exec(m_fileList->mapToGlobal(p_pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::locateCurrentFileItem() const
|
||||||
|
{
|
||||||
|
auto item = m_fileList->currentItem();
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFile *file = g_vnote->getInternalFile(getFilePath(item));
|
||||||
|
if (file) {
|
||||||
|
g_mainWin->locateFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::addFileToCart() const
|
||||||
|
{
|
||||||
|
QList<QListWidgetItem *> items = m_fileList->selectedItems();
|
||||||
|
VCart *cart = g_mainWin->getCart();
|
||||||
|
|
||||||
|
for (int i = 0; i < items.size(); ++i) {
|
||||||
|
cart->addFile(getFilePath(items[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mainWin->showStatusMessage(tr("%1 %2 added to Cart")
|
||||||
|
.arg(items.size())
|
||||||
|
.arg(items.size() > 1 ? tr("notes") : tr("note")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::pinFileToHistory() const
|
||||||
|
{
|
||||||
|
QList<QListWidgetItem *> items = m_fileList->selectedItems();
|
||||||
|
|
||||||
|
QStringList files;
|
||||||
|
for (int i = 0; i < items.size(); ++i) {
|
||||||
|
files << getFilePath(items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mainWin->getHistoryList()->pinFiles(files);
|
||||||
|
|
||||||
|
g_mainWin->showStatusMessage(tr("%1 %2 pinned to History")
|
||||||
|
.arg(items.size())
|
||||||
|
.arg(items.size() > 1 ? tr("notes") : tr("note")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTagExplorer::promptToRemoveEmptyTag(const QString &p_tag)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!p_tag.isEmpty());
|
||||||
|
|
||||||
|
int ret = VUtils::showMessage(QMessageBox::Warning,
|
||||||
|
tr("Warning"),
|
||||||
|
tr("Empty tag detected! Do you want to remove it?"),
|
||||||
|
tr("The tag <span style=\"%1\">%2</span> seems not to "
|
||||||
|
"be assigned to any note currently.")
|
||||||
|
.arg(g_config->c_dataTextStyle)
|
||||||
|
.arg(p_tag),
|
||||||
|
QMessageBox::Ok | QMessageBox::Cancel,
|
||||||
|
QMessageBox::Cancel,
|
||||||
|
this,
|
||||||
|
MessageBoxType::Danger);
|
||||||
|
|
||||||
|
if (ret == QMessageBox::Cancel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the tag from m_notebook.
|
||||||
|
m_notebook->removeTag(p_tag);
|
||||||
|
updateContent();
|
||||||
|
}
|
113
src/vtagexplorer.h
Normal file
113
src/vtagexplorer.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#ifndef VTAGEXPLORER_H
|
||||||
|
#define VTAGEXPLORER_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
#include "vsearchconfig.h"
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
class VListWidget;
|
||||||
|
class QListWidgetItem;
|
||||||
|
class QSplitter;
|
||||||
|
class VNotebook;
|
||||||
|
class VSearch;
|
||||||
|
|
||||||
|
class VTagExplorer : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VTagExplorer(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void setNotebook(VNotebook *p_notebook);
|
||||||
|
|
||||||
|
void saveStateAndGeometry();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void focusInEvent(QFocusEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleSearchItemAdded(const QSharedPointer<VSearchResultItem> &p_item);
|
||||||
|
|
||||||
|
void handleSearchItemsAdded(const QList<QSharedPointer<VSearchResultItem> > &p_items);
|
||||||
|
|
||||||
|
void handleSearchFinished(const QSharedPointer<VSearchResult> &p_result);
|
||||||
|
|
||||||
|
void openFileItem(QListWidgetItem *p_item) const;
|
||||||
|
|
||||||
|
void openSelectedFileItems() const;
|
||||||
|
|
||||||
|
void locateCurrentFileItem() const;
|
||||||
|
|
||||||
|
void addFileToCart() const;
|
||||||
|
|
||||||
|
void pinFileToHistory() const;
|
||||||
|
|
||||||
|
void handleFileListContextMenuRequested(QPoint p_pos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUI();
|
||||||
|
|
||||||
|
void updateNotebookLabel();
|
||||||
|
|
||||||
|
void updateTagLabel(const QString &p_tag);
|
||||||
|
|
||||||
|
bool tagListObsolete(const QStringList &p_tags) const;
|
||||||
|
|
||||||
|
void updateTagList(const QStringList &p_tags);
|
||||||
|
|
||||||
|
void updateContent();
|
||||||
|
|
||||||
|
// Return ture if succeeded.
|
||||||
|
bool activateTag(const QString &p_tag);
|
||||||
|
|
||||||
|
void addTagItem(const QString &p_tag);
|
||||||
|
|
||||||
|
void restoreStateAndGeometry();
|
||||||
|
|
||||||
|
VSearch *getVSearch() const;
|
||||||
|
|
||||||
|
void initVSearch();
|
||||||
|
|
||||||
|
void appendItemToFileList(const QSharedPointer<VSearchResultItem> &p_item);
|
||||||
|
|
||||||
|
QString getFilePath(const QListWidgetItem *p_item) const;
|
||||||
|
|
||||||
|
void promptToRemoveEmptyTag(const QString &p_tag);
|
||||||
|
|
||||||
|
bool m_uiInitialized;
|
||||||
|
|
||||||
|
QLabel *m_notebookLabel;
|
||||||
|
|
||||||
|
QLabel *m_tagLabel;
|
||||||
|
|
||||||
|
VListWidget *m_tagList;
|
||||||
|
|
||||||
|
VListWidget *m_fileList;
|
||||||
|
|
||||||
|
QSplitter *m_splitter;
|
||||||
|
|
||||||
|
VNotebook *m_notebook;
|
||||||
|
|
||||||
|
bool m_notebookChanged;
|
||||||
|
|
||||||
|
QIcon m_noteIcon;
|
||||||
|
|
||||||
|
VSearch *m_search;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline VSearch *VTagExplorer::getVSearch() const
|
||||||
|
{
|
||||||
|
if (m_search) {
|
||||||
|
return m_search;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_cast<VTagExplorer *>(this)->initVSearch();
|
||||||
|
return m_search;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VTAGEXPLORER_H
|
Loading…
x
Reference in New Issue
Block a user