mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
295 lines
7.7 KiB
C++
295 lines
7.7 KiB
C++
#include "vtagpanel.h"
|
|
|
|
#include <QtWidgets>
|
|
|
|
#include "vbuttonwithwidget.h"
|
|
#include "utils/viconutils.h"
|
|
#include "vnotefile.h"
|
|
#include "valltagspanel.h"
|
|
#include "vtaglabel.h"
|
|
#include "vlineedit.h"
|
|
#include "vmainwindow.h"
|
|
#include "vnote.h"
|
|
#include "vconfigmanager.h"
|
|
|
|
extern VPalette *g_palette;
|
|
|
|
extern VMainWindow *g_mainWin;
|
|
|
|
extern VNote *g_vnote;
|
|
|
|
extern VConfigManager *g_config;
|
|
|
|
VTagPanel::VTagPanel(QWidget *parent)
|
|
: QWidget(parent),
|
|
m_file(NULL),
|
|
m_notebookOfCompleter(NULL)
|
|
{
|
|
setupUI();
|
|
}
|
|
|
|
void VTagPanel::setupUI()
|
|
{
|
|
const int maxNum = g_config->getMaxNumOfTagLabels();
|
|
for (int i = 0; i < maxNum; ++i) {
|
|
VTagLabel *label = new VTagLabel(this);
|
|
connect(label, &VTagLabel::removalRequested,
|
|
this, [this](const QString &p_text) {
|
|
removeTag(p_text);
|
|
updateTags();
|
|
});
|
|
|
|
m_labels.append(label);
|
|
}
|
|
|
|
m_tagsPanel = new VAllTagsPanel(this);
|
|
connect(m_tagsPanel, &VAllTagsPanel::tagRemoved,
|
|
this, [this](const QString &p_text) {
|
|
removeTag(p_text);
|
|
|
|
if (m_file->getTags().size() <= g_config->getMaxNumOfTagLabels()) {
|
|
// Hide the more panel.
|
|
m_btn->hidePopupWidget();
|
|
m_btn->hide();
|
|
}
|
|
});
|
|
|
|
m_btn = new VButtonWithWidget(VIconUtils::icon(":/resources/icons/tags.svg",
|
|
g_palette->color("tab_indicator_tag_label_bg")),
|
|
"",
|
|
m_tagsPanel,
|
|
this);
|
|
m_btn->setToolTip(tr("View and edit tags of current note"));
|
|
m_btn->setProperty("StatusBtn", true);
|
|
m_btn->setFocusPolicy(Qt::NoFocus);
|
|
connect(m_btn, &VButtonWithWidget::popupWidgetAboutToShow,
|
|
this, &VTagPanel::updateAllTagsPanel);
|
|
|
|
m_tagEdit = new VLineEdit(this);
|
|
m_tagEdit->setToolTip(tr("Press Enter to add a tag"));
|
|
m_tagEdit->setPlaceholderText(tr("Add a tag"));
|
|
m_tagEdit->setProperty("EmbeddedEdit", true);
|
|
m_tagEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
|
|
connect(m_tagEdit, &QLineEdit::returnPressed,
|
|
this, [this]() {
|
|
Q_ASSERT(m_file);
|
|
QString text = m_tagEdit->text();
|
|
if (addTag(text)) {
|
|
if (m_file->getNotebook()->addTag(text)) {
|
|
updateCompleter();
|
|
}
|
|
|
|
updateTags();
|
|
|
|
g_mainWin->showStatusMessage(tr("Tag \"%1\" added").arg(text));
|
|
}
|
|
|
|
// Clear after a wait since it may be triggered by the completion.
|
|
// The activated() of completion will add text to the edit.
|
|
QTimer::singleShot(100, m_tagEdit, SLOT(clear()));
|
|
});
|
|
|
|
QValidator *validator = new QRegExpValidator(QRegExp("[^,]+"), m_tagEdit);
|
|
m_tagEdit->setValidator(validator);
|
|
|
|
// Completer.
|
|
m_tagsModel = new QStringListModel(this);
|
|
QCompleter *completer = new QCompleter(m_tagsModel, this);
|
|
completer->setCaseSensitivity(Qt::CaseSensitive);
|
|
completer->popup()->setItemDelegate(new QStyledItemDelegate(this));
|
|
m_tagEdit->setCompleter(completer);
|
|
m_tagEdit->installEventFilter(this);
|
|
|
|
QHBoxLayout *mainLayout = new QHBoxLayout();
|
|
for (auto label : m_labels) {
|
|
mainLayout->addWidget(label);
|
|
label->hide();
|
|
}
|
|
|
|
mainLayout->addWidget(m_btn);
|
|
mainLayout->addWidget(m_tagEdit);
|
|
|
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
setLayout(mainLayout);
|
|
}
|
|
|
|
void VTagPanel::clearLabels()
|
|
{
|
|
for (auto label : m_labels) {
|
|
label->clear();
|
|
label->hide();
|
|
}
|
|
|
|
m_tagsPanel->clear();
|
|
}
|
|
|
|
void VTagPanel::updateTags(VNoteFile *p_file)
|
|
{
|
|
if (m_file == p_file) {
|
|
return;
|
|
}
|
|
|
|
m_file = p_file;
|
|
|
|
updateTags();
|
|
}
|
|
|
|
void VTagPanel::updateTags()
|
|
{
|
|
clearLabels();
|
|
|
|
if (!m_file) {
|
|
m_btn->setVisible(false);
|
|
return;
|
|
}
|
|
|
|
const QStringList &tags = m_file->getTags();
|
|
int idx = 0;
|
|
for (; idx < tags.size() && idx < m_labels.size(); ++idx) {
|
|
m_labels[idx]->setText(tags[idx]);
|
|
m_labels[idx]->show();
|
|
}
|
|
|
|
m_btn->setVisible(idx < tags.size());
|
|
}
|
|
|
|
void VTagPanel::updateAllTagsPanel()
|
|
{
|
|
Q_ASSERT(m_file);
|
|
m_tagsPanel->clear();
|
|
|
|
const QStringList &tags = m_file->getTags();
|
|
for (int idx = g_config->getMaxNumOfTagLabels(); idx < tags.size(); ++idx) {
|
|
m_tagsPanel->addTag(tags[idx]);
|
|
}
|
|
}
|
|
|
|
void VTagPanel::removeTag(const QString &p_text)
|
|
{
|
|
if (!m_file) {
|
|
return;
|
|
}
|
|
|
|
m_file->removeTag(p_text);
|
|
g_mainWin->showStatusMessage(tr("Tag \"%1\" removed").arg(p_text));
|
|
}
|
|
|
|
bool VTagPanel::addTag(const QString &p_text)
|
|
{
|
|
if (!m_file) {
|
|
return false;
|
|
}
|
|
|
|
bool ret = m_file->addTag(p_text);
|
|
return ret;
|
|
}
|
|
|
|
bool VTagPanel::eventFilter(QObject *p_obj, QEvent *p_event)
|
|
{
|
|
Q_ASSERT(p_obj == m_tagEdit);
|
|
|
|
if (p_event->type() == QEvent::FocusIn) {
|
|
QFocusEvent *eve = static_cast<QFocusEvent *>(p_event);
|
|
if (eve->gotFocus()) {
|
|
// Just check completer.
|
|
updateCompleter(m_file);
|
|
}
|
|
}
|
|
|
|
return QWidget::eventFilter(p_obj, p_event);
|
|
}
|
|
|
|
void VTagPanel::updateCompleter(const VNoteFile *p_file)
|
|
{
|
|
const VNotebook *nb = p_file ? p_file->getNotebook() : NULL;
|
|
if (nb == m_notebookOfCompleter) {
|
|
// No need to update.
|
|
return;
|
|
}
|
|
|
|
m_notebookOfCompleter = nb;
|
|
updateCompleter();
|
|
}
|
|
|
|
void VTagPanel::updateCompleter()
|
|
{
|
|
m_tagsModel->setStringList(m_notebookOfCompleter ? m_notebookOfCompleter->getTags()
|
|
: QStringList());
|
|
}
|
|
|
|
void VTagPanel::showNavigation()
|
|
{
|
|
if (!isVisible() || !m_file) {
|
|
return;
|
|
}
|
|
|
|
// View all tags.
|
|
if (isAllTagsPanelAvailable()) {
|
|
QChar key('a');
|
|
m_keyMap[key] = m_btn;
|
|
|
|
QString str = QString(m_majorKey) + key;
|
|
QLabel *label = new QLabel(str, this);
|
|
label->setStyleSheet(g_vnote->getNavigationLabelStyle(str, true));
|
|
label->move(m_btn->geometry().topLeft());
|
|
label->show();
|
|
m_naviLabels.append(label);
|
|
}
|
|
|
|
// Add tag edit.
|
|
{
|
|
QChar key('b');
|
|
m_keyMap[key] = m_tagEdit;
|
|
|
|
QString str = QString(m_majorKey) + key;
|
|
QLabel *label = new QLabel(str, this);
|
|
label->setStyleSheet(g_vnote->getNavigationLabelStyle(str, true));
|
|
label->move(m_tagEdit->geometry().topLeft());
|
|
label->show();
|
|
m_naviLabels.append(label);
|
|
}
|
|
}
|
|
|
|
bool VTagPanel::handleKeyNavigation(int p_key, bool &p_succeed)
|
|
{
|
|
bool ret = false;
|
|
p_succeed = false;
|
|
QChar keyChar = VUtils::keyToChar(p_key);
|
|
if (m_isSecondKey && !keyChar.isNull()) {
|
|
m_isSecondKey = false;
|
|
p_succeed = true;
|
|
auto it = m_keyMap.find(keyChar);
|
|
if (it != m_keyMap.end()) {
|
|
ret = true;
|
|
|
|
if (*it == m_btn) {
|
|
// Show all tags panel.
|
|
// To avoid focus in VCaptain after hiding the menu.
|
|
g_mainWin->focusEditArea();
|
|
// Use timer to hide the label first.
|
|
QTimer::singleShot(50, m_btn, SLOT(showPopupWidget()));
|
|
} else {
|
|
m_tagEdit->setFocus();
|
|
}
|
|
}
|
|
} else if (keyChar == m_majorKey) {
|
|
// Major key pressed.
|
|
// Need second key if m_keyMap is not empty.
|
|
if (m_keyMap.isEmpty()) {
|
|
p_succeed = true;
|
|
} else {
|
|
m_isSecondKey = true;
|
|
}
|
|
|
|
ret = true;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool VTagPanel::isAllTagsPanelAvailable() const
|
|
{
|
|
return m_btn->isVisible();
|
|
}
|