mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
UniversalEntry: add q to list all notebooks and a to search name of folder/note
This commit is contained in:
parent
4727d0aa98
commit
b46a8f4f39
73
src/iuniversalentry.h
Normal file
73
src/iuniversalentry.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#ifndef IUNIVERSALENTRY_H
|
||||||
|
#define IUNIVERSALENTRY_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
// Interface for one Universal Entry.
|
||||||
|
// An entry may be used for different keys, in which case we could use an ID to
|
||||||
|
// identify.
|
||||||
|
class IUniversalEntry : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Busy,
|
||||||
|
Success,
|
||||||
|
Fail,
|
||||||
|
Cancelled
|
||||||
|
};
|
||||||
|
|
||||||
|
IUniversalEntry(QObject *p_parent = nullptr)
|
||||||
|
: QObject(p_parent),
|
||||||
|
m_initialized(false),
|
||||||
|
m_widgetParent(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a description string for the entry.
|
||||||
|
virtual QString description(int p_id) const = 0;
|
||||||
|
|
||||||
|
// Return the widget to show to user.
|
||||||
|
virtual QWidget *widget(int p_id) = 0;
|
||||||
|
|
||||||
|
virtual void processCommand(int p_id, const QString &p_cmd) = 0;
|
||||||
|
|
||||||
|
// This UE is not used now. Free resources.
|
||||||
|
virtual void clear(int p_id) = 0;
|
||||||
|
|
||||||
|
// UE is hidden by the user.
|
||||||
|
virtual void entryHidden(int p_id) = 0;
|
||||||
|
|
||||||
|
// Select next item.
|
||||||
|
virtual void selectNextItem(int p_id, bool p_forward) = 0;
|
||||||
|
|
||||||
|
// Activate current item.
|
||||||
|
virtual void activate(int p_id) = 0;
|
||||||
|
|
||||||
|
// Ask the UE to stop asynchronously.
|
||||||
|
virtual void askToStop(int p_id) = 0;
|
||||||
|
|
||||||
|
void setWidgetParent(QWidget *p_parent)
|
||||||
|
{
|
||||||
|
m_widgetParent = p_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void widgetUpdated();
|
||||||
|
|
||||||
|
void stateUpdated(IUniversalEntry::State p_state);
|
||||||
|
|
||||||
|
void requestHideUniversalEntry();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void init() = 0;
|
||||||
|
|
||||||
|
bool m_initialized;
|
||||||
|
|
||||||
|
QWidget *m_widgetParent;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IUNIVERSALENTRY_H
|
@ -115,6 +115,10 @@ template_title_flash_dark_fg=@master_bg
|
|||||||
search_hit_item_fg=@selected_fg
|
search_hit_item_fg=@selected_fg
|
||||||
search_hit_item_bg=@master_dark_bg
|
search_hit_item_bg=@master_dark_bg
|
||||||
|
|
||||||
|
; Universal Entry CMD Edit border color
|
||||||
|
ue_cmd_busy_border=#3F51B5
|
||||||
|
ue_cmd_fail_border=@danger_bg
|
||||||
|
|
||||||
[widgets]
|
[widgets]
|
||||||
; Widget color attributes.
|
; Widget color attributes.
|
||||||
|
|
||||||
@ -351,3 +355,7 @@ headerview_checked_bg=@selected_bg
|
|||||||
progressbar_bg=@edit_bg
|
progressbar_bg=@edit_bg
|
||||||
progressbar_border_bg=@border_bg
|
progressbar_border_bg=@border_bg
|
||||||
progressbar_chunk_bg=@master_dark_bg
|
progressbar_chunk_bg=@master_dark_bg
|
||||||
|
|
||||||
|
universalentry_border_bg=@border_bg
|
||||||
|
|
||||||
|
doublerowitem_second_row_label_fg=#6C6C6C
|
||||||
|
@ -590,6 +590,15 @@ VTabIndicator QLabel[TabIndicatorLabel="true"] {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VDoubleRowItemWidget QLabel[FirstRowLabel="true"] {
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
VDoubleRowItemWidget QLabel[SecondRowLabel="true"] {
|
||||||
|
font-size: 8pt;
|
||||||
|
color: @doublerowitem_second_row_label_fg;
|
||||||
|
}
|
||||||
|
|
||||||
QLabel {
|
QLabel {
|
||||||
border: none;
|
border: none;
|
||||||
color: @label_fg;
|
color: @label_fg;
|
||||||
@ -1255,3 +1264,8 @@ QProgressBar::chunk {
|
|||||||
width: $20px;
|
width: $20px;
|
||||||
}
|
}
|
||||||
/* End QProgressBar */
|
/* End QProgressBar */
|
||||||
|
|
||||||
|
VUniversalEntry {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid @universalentry_border_bg;
|
||||||
|
}
|
||||||
|
@ -83,6 +83,10 @@ template_title_flash_dark_fg=#00897B
|
|||||||
search_hit_item_fg=@selected_fg
|
search_hit_item_fg=@selected_fg
|
||||||
search_hit_item_bg=#80CBC4
|
search_hit_item_bg=#80CBC4
|
||||||
|
|
||||||
|
; Universal Entry CMD Edit border color
|
||||||
|
ue_cmd_busy_border=#3F51B5
|
||||||
|
ue_cmd_fail_border=@danger_bg
|
||||||
|
|
||||||
[widgets]
|
[widgets]
|
||||||
; Widget color attributes.
|
; Widget color attributes.
|
||||||
|
|
||||||
|
@ -109,6 +109,10 @@ template_title_flash_dark_fg=@master_bg
|
|||||||
search_hit_item_fg=@selected_fg
|
search_hit_item_fg=@selected_fg
|
||||||
search_hit_item_bg=#CCE7E4
|
search_hit_item_bg=#CCE7E4
|
||||||
|
|
||||||
|
; Universal Entry CMD Edit border color
|
||||||
|
ue_cmd_busy_border=#3F51B5
|
||||||
|
ue_cmd_fail_border=@danger_bg
|
||||||
|
|
||||||
[widgets]
|
[widgets]
|
||||||
; Widget color attributes.
|
; Widget color attributes.
|
||||||
|
|
||||||
@ -344,3 +348,7 @@ headerview_checked_bg=@selected_bg
|
|||||||
progressbar_bg=@edit_bg
|
progressbar_bg=@edit_bg
|
||||||
progressbar_border_bg=@border_bg
|
progressbar_border_bg=@border_bg
|
||||||
progressbar_chunk_bg=@master_light_bg
|
progressbar_chunk_bg=@master_light_bg
|
||||||
|
|
||||||
|
universalentry_border_bg=@border_bg
|
||||||
|
|
||||||
|
doublerowitem_second_row_label_fg=#6C6C6C
|
||||||
|
@ -590,6 +590,15 @@ VTabIndicator QLabel[TabIndicatorLabel="true"] {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VDoubleRowItemWidget QLabel[FirstRowLabel="true"] {
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
VDoubleRowItemWidget QLabel[SecondRowLabel="true"] {
|
||||||
|
font-size: 8pt;
|
||||||
|
color: @doublerowitem_second_row_label_fg;
|
||||||
|
}
|
||||||
|
|
||||||
QLabel {
|
QLabel {
|
||||||
border: none;
|
border: none;
|
||||||
color: @label_fg;
|
color: @label_fg;
|
||||||
@ -1254,3 +1263,8 @@ QProgressBar::chunk {
|
|||||||
width: $20px;
|
width: $20px;
|
||||||
}
|
}
|
||||||
/* End QProgressBar */
|
/* End QProgressBar */
|
||||||
|
|
||||||
|
VUniversalEntry {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid @universalentry_border_bg;
|
||||||
|
}
|
||||||
|
11
src/src.pro
11
src/src.pro
@ -118,7 +118,10 @@ SOURCES += main.cpp\
|
|||||||
vsearch.cpp \
|
vsearch.cpp \
|
||||||
vsearchresulttree.cpp \
|
vsearchresulttree.cpp \
|
||||||
vsearchengine.cpp \
|
vsearchengine.cpp \
|
||||||
vuniversalentry.cpp
|
vuniversalentry.cpp \
|
||||||
|
vlistwidgetdoublerows.cpp \
|
||||||
|
vdoublerowitemwidget.cpp \
|
||||||
|
vsearchue.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -226,7 +229,11 @@ HEADERS += vmainwindow.h \
|
|||||||
isearchengine.h \
|
isearchengine.h \
|
||||||
vsearchconfig.h \
|
vsearchconfig.h \
|
||||||
vsearchengine.h \
|
vsearchengine.h \
|
||||||
vuniversalentry.h
|
vuniversalentry.h \
|
||||||
|
iuniversalentry.h \
|
||||||
|
vlistwidgetdoublerows.h \
|
||||||
|
vdoublerowitemwidget.h \
|
||||||
|
vsearchue.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc \
|
vnote.qrc \
|
||||||
|
37
src/vdoublerowitemwidget.cpp
Normal file
37
src/vdoublerowitemwidget.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "vdoublerowitemwidget.h"
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
VDoubleRowItemWidget::VDoubleRowItemWidget(QWidget *p_parent)
|
||||||
|
: QWidget(p_parent)
|
||||||
|
{
|
||||||
|
m_firstLabel = new QLabel(this);
|
||||||
|
m_firstLabel->setProperty("FirstRowLabel", true);
|
||||||
|
|
||||||
|
m_secondLabel = new QLabel(this);
|
||||||
|
m_secondLabel->setProperty("SecondRowLabel", true);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout();
|
||||||
|
layout->addWidget(m_firstLabel);
|
||||||
|
layout->addWidget(m_secondLabel);
|
||||||
|
layout->addStretch();
|
||||||
|
layout->setContentsMargins(3, 0, 0, 0);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VDoubleRowItemWidget::setText(const QString &p_firstText,
|
||||||
|
const QString &p_secondText)
|
||||||
|
{
|
||||||
|
m_firstLabel->setText(p_firstText);
|
||||||
|
|
||||||
|
if (!p_secondText.isEmpty()) {
|
||||||
|
m_secondLabel->setText(p_secondText);
|
||||||
|
m_secondLabel->show();
|
||||||
|
} else {
|
||||||
|
m_secondLabel->hide();
|
||||||
|
}
|
||||||
|
}
|
21
src/vdoublerowitemwidget.h
Normal file
21
src/vdoublerowitemwidget.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef VDOUBLEROWITEMWIDGET_H
|
||||||
|
#define VDOUBLEROWITEMWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
|
class VDoubleRowItemWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VDoubleRowItemWidget(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
void setText(const QString &p_firstText, const QString &p_secondText);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *m_firstLabel;
|
||||||
|
QLabel *m_secondLabel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VDOUBLEROWITEMWIDGET_H
|
@ -9,9 +9,10 @@
|
|||||||
#include "utils/vimnavigationforwidget.h"
|
#include "utils/vimnavigationforwidget.h"
|
||||||
#include "vstyleditemdelegate.h"
|
#include "vstyleditemdelegate.h"
|
||||||
|
|
||||||
VListWidget::VListWidget(QWidget *parent)
|
VListWidget::VListWidget(QWidget *p_parent)
|
||||||
: QListWidget(parent),
|
: QListWidget(p_parent),
|
||||||
ISimpleSearch()
|
ISimpleSearch(),
|
||||||
|
m_fitContent(false)
|
||||||
{
|
{
|
||||||
m_searchInput = new VSimpleSearchInput(this, this);
|
m_searchInput = new VSimpleSearchInput(this, this);
|
||||||
connect(m_searchInput, &VSimpleSearchInput::triggered,
|
connect(m_searchInput, &VSimpleSearchInput::triggered,
|
||||||
@ -142,8 +143,19 @@ int VListWidget::totalNumberOfItems()
|
|||||||
|
|
||||||
void VListWidget::selectNextItem(bool p_forward)
|
void VListWidget::selectNextItem(bool p_forward)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p_forward);
|
if (count() == 0) {
|
||||||
Q_ASSERT(false);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cur = currentRow();
|
||||||
|
cur = cur + (p_forward ? 1 : -1);
|
||||||
|
if (cur < 0) {
|
||||||
|
cur = 0;
|
||||||
|
} else if (cur >= count()) {
|
||||||
|
cur = count() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentRow(cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VListWidget::sortListWidget(QListWidget *p_list, const QVector<int> &p_sortedIdx)
|
void VListWidget::sortListWidget(QListWidget *p_list, const QVector<int> &p_sortedIdx)
|
||||||
@ -161,3 +173,34 @@ void VListWidget::sortListWidget(QListWidget *p_list, const QVector<int> &p_sort
|
|||||||
p_list->insertItem(i, it);
|
p_list->insertItem(i, it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSize VListWidget::sizeHint() const
|
||||||
|
{
|
||||||
|
if (count() == 0 || !m_fitContent) {
|
||||||
|
return QListWidget::sizeHint();
|
||||||
|
} else {
|
||||||
|
// Adjust size to content.
|
||||||
|
int cnt = count();
|
||||||
|
int hei = 0;
|
||||||
|
int wid = sizeHintForColumn(0) + 10;
|
||||||
|
for (int i = 0; i < cnt; ++i) {
|
||||||
|
hei += sizeHintForRow(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
hei += 2 * cnt;
|
||||||
|
|
||||||
|
// Scrollbar.
|
||||||
|
QScrollBar *verBar = verticalScrollBar();
|
||||||
|
QScrollBar *horBar = horizontalScrollBar();
|
||||||
|
if (verBar && (verBar->minimum() != verBar->maximum())) {
|
||||||
|
wid += verBar->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (horBar && (horBar->minimum() != horBar->maximum())) {
|
||||||
|
hei += horBar->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QSize(wid, hei);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@ class VStyledItemDelegate;
|
|||||||
class VListWidget : public QListWidget, public ISimpleSearch
|
class VListWidget : public QListWidget, public ISimpleSearch
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit VListWidget(QWidget *parent = Q_NULLPTR);
|
explicit VListWidget(QWidget *p_parent = Q_NULLPTR);
|
||||||
|
|
||||||
// Clear list widget as well as other data.
|
// Clear list widget as well as other data.
|
||||||
// clear() is not virtual to override.
|
// clear() is not virtual to override.
|
||||||
void clearAll();
|
virtual void clearAll();
|
||||||
|
|
||||||
// Implement ISimpleSearch.
|
// Implement ISimpleSearch.
|
||||||
virtual QList<void *> searchItems(const QString &p_text,
|
virtual QList<void *> searchItems(const QString &p_text,
|
||||||
@ -32,9 +32,13 @@ public:
|
|||||||
|
|
||||||
virtual void selectNextItem(bool p_forward) Q_DECL_OVERRIDE;
|
virtual void selectNextItem(bool p_forward) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
// Sort @p_list according to @p_sortedIdx.
|
// Sort @p_list according to @p_sortedIdx.
|
||||||
static void sortListWidget(QListWidget *p_list, const QVector<int> &p_sortedIdx);
|
static void sortListWidget(QListWidget *p_list, const QVector<int> &p_sortedIdx);
|
||||||
|
|
||||||
|
void setFitContent(bool p_enabled);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleSearchModeTriggered(bool p_inSearchMode, bool p_focus);
|
void handleSearchModeTriggered(bool p_inSearchMode, bool p_focus);
|
||||||
|
|
||||||
@ -50,6 +54,13 @@ private:
|
|||||||
VSimpleSearchInput *m_searchInput;
|
VSimpleSearchInput *m_searchInput;
|
||||||
|
|
||||||
VStyledItemDelegate *m_delegate;
|
VStyledItemDelegate *m_delegate;
|
||||||
|
|
||||||
|
// Whether fit the size to content.
|
||||||
|
bool m_fitContent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void VListWidget::setFitContent(bool p_enabled)
|
||||||
|
{
|
||||||
|
m_fitContent = p_enabled;
|
||||||
|
}
|
||||||
#endif // VLISTWIDGET_H
|
#endif // VLISTWIDGET_H
|
||||||
|
55
src/vlistwidgetdoublerows.cpp
Normal file
55
src/vlistwidgetdoublerows.cpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#include "vlistwidgetdoublerows.h"
|
||||||
|
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
#include "vdoublerowitemwidget.h"
|
||||||
|
|
||||||
|
VListWidgetDoubleRows::VListWidgetDoubleRows(QWidget *p_parent)
|
||||||
|
: VListWidget(p_parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QListWidgetItem *VListWidgetDoubleRows::addItem(const QIcon &p_icon,
|
||||||
|
const QString &p_firstRow,
|
||||||
|
const QString &p_secondRow)
|
||||||
|
{
|
||||||
|
VDoubleRowItemWidget *itemWidget = new VDoubleRowItemWidget(this);
|
||||||
|
itemWidget->setText(p_firstRow, p_secondRow);
|
||||||
|
QSize sz = itemWidget->sizeHint();
|
||||||
|
QSize iconSz = iconSize();
|
||||||
|
if (!iconSz.isValid()) {
|
||||||
|
iconSz = QSize(sz.height(), sz.height());
|
||||||
|
setIconSize(iconSz);
|
||||||
|
}
|
||||||
|
|
||||||
|
sz.setHeight(sz.height() * 1.25);
|
||||||
|
|
||||||
|
QListWidgetItem *item = new QListWidgetItem();
|
||||||
|
if (!p_icon.isNull()) {
|
||||||
|
item->setIcon(p_icon);
|
||||||
|
sz.setWidth(sz.width() + iconSz.width());
|
||||||
|
sz.setHeight(qMax(sz.height(), iconSz.height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
item->setSizeHint(sz);
|
||||||
|
|
||||||
|
VListWidget::addItem(item);
|
||||||
|
VListWidget::setItemWidget(item, itemWidget);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VListWidgetDoubleRows::clearAll()
|
||||||
|
{
|
||||||
|
// Delete the item widget for each item.
|
||||||
|
int cnt = count();
|
||||||
|
for (int i = 0; i < cnt; ++i) {
|
||||||
|
QWidget *wid = itemWidget(item(i));
|
||||||
|
removeItemWidget(item(i));
|
||||||
|
delete wid;
|
||||||
|
}
|
||||||
|
|
||||||
|
VListWidget::clearAll();
|
||||||
|
|
||||||
|
setIconSize(QSize());
|
||||||
|
}
|
24
src/vlistwidgetdoublerows.h
Normal file
24
src/vlistwidgetdoublerows.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef VLISTWIDGETDOUBLEROWS_H
|
||||||
|
#define VLISTWIDGETDOUBLEROWS_H
|
||||||
|
|
||||||
|
#include "vlistwidget.h"
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
class QListWidgetItem;
|
||||||
|
|
||||||
|
|
||||||
|
class VListWidgetDoubleRows : public VListWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VListWidgetDoubleRows(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
QListWidgetItem *addItem(const QIcon &p_icon,
|
||||||
|
const QString &p_firstRow,
|
||||||
|
const QString &p_secondRow);
|
||||||
|
|
||||||
|
void clearAll() Q_DECL_OVERRIDE;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VLISTWIDGETDOUBLEROWS_H
|
@ -40,6 +40,7 @@
|
|||||||
#include "dialog/vexportdialog.h"
|
#include "dialog/vexportdialog.h"
|
||||||
#include "vsearcher.h"
|
#include "vsearcher.h"
|
||||||
#include "vuniversalentry.h"
|
#include "vuniversalentry.h"
|
||||||
|
#include "vsearchue.h"
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
@ -3164,15 +3165,7 @@ VNotebook *VMainWindow::getCurrentNotebook() const
|
|||||||
void VMainWindow::activateUniversalEntry()
|
void VMainWindow::activateUniversalEntry()
|
||||||
{
|
{
|
||||||
if (!m_ue) {
|
if (!m_ue) {
|
||||||
m_ue = new VUniversalEntry(this);
|
initUniversalEntry();
|
||||||
m_ue->hide();
|
|
||||||
m_ue->setWindowFlags(Qt::Popup
|
|
||||||
| Qt::FramelessWindowHint
|
|
||||||
| Qt::NoDropShadowWindowHint);
|
|
||||||
connect(m_ue, &VUniversalEntry::exited,
|
|
||||||
this, [this]() {
|
|
||||||
m_captain->setCaptainModeEnabled(true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_captain->setCaptainModeEnabled(false);
|
m_captain->setCaptainModeEnabled(false);
|
||||||
@ -3191,3 +3184,21 @@ void VMainWindow::activateUniversalEntry()
|
|||||||
m_ue->show();
|
m_ue->show();
|
||||||
m_ue->raise();
|
m_ue->raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMainWindow::initUniversalEntry()
|
||||||
|
{
|
||||||
|
m_ue = new VUniversalEntry(this);
|
||||||
|
m_ue->hide();
|
||||||
|
m_ue->setWindowFlags(Qt::Popup
|
||||||
|
| Qt::FramelessWindowHint
|
||||||
|
| Qt::NoDropShadowWindowHint);
|
||||||
|
connect(m_ue, &VUniversalEntry::exited,
|
||||||
|
this, [this]() {
|
||||||
|
m_captain->setCaptainModeEnabled(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register entries.
|
||||||
|
VSearchUE *searchUE = new VSearchUE(this);
|
||||||
|
m_ue->registerEntry('q', searchUE, VSearchUE::Name_Notebook_AllNotebook);
|
||||||
|
m_ue->registerEntry('a', searchUE, VSearchUE::Name_FolderNote_AllNotebook);
|
||||||
|
}
|
||||||
|
@ -282,6 +282,8 @@ private:
|
|||||||
|
|
||||||
void updateEditReadAct(const VEditTab *p_tab);
|
void updateEditReadAct(const VEditTab *p_tab);
|
||||||
|
|
||||||
|
void initUniversalEntry();
|
||||||
|
|
||||||
// Captain mode functions.
|
// Captain mode functions.
|
||||||
|
|
||||||
// Popup the attachment list if it is enabled.
|
// Popup the attachment list if it is enabled.
|
||||||
|
@ -382,6 +382,7 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
|
|
||||||
case Qt::Key_Enter:
|
case Qt::Key_Enter:
|
||||||
// Fall through.
|
// Fall through.
|
||||||
|
V_FALLTHROUGH;
|
||||||
case Qt::Key_Return:
|
case Qt::Key_Return:
|
||||||
{
|
{
|
||||||
if (handleKeyReturn(p_event)) {
|
if (handleKeyReturn(p_event)) {
|
||||||
|
@ -45,3 +45,8 @@ const QString &VMetaWordLineEdit::getEvaluatedText() const
|
|||||||
{
|
{
|
||||||
return m_evaluatedText;
|
return m_evaluatedText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString VMetaWordLineEdit::evaluateText(const QString &p_text) const
|
||||||
|
{
|
||||||
|
return g_mwMgr->evaluate(p_text);
|
||||||
|
}
|
||||||
|
@ -16,6 +16,8 @@ public:
|
|||||||
// Return the evaluated text.
|
// Return the evaluated text.
|
||||||
const QString &getEvaluatedText() const;
|
const QString &getEvaluatedText() const;
|
||||||
|
|
||||||
|
QString evaluateText(const QString &p_text) const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleTextChanged(const QString &p_text);
|
void handleTextChanged(const QString &p_text);
|
||||||
|
|
||||||
|
384
src/vsearchue.cpp
Normal file
384
src/vsearchue.cpp
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
#include "vsearchue.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "vlistwidgetdoublerows.h"
|
||||||
|
#include "vnotebook.h"
|
||||||
|
#include "vnote.h"
|
||||||
|
#include "vsearch.h"
|
||||||
|
#include "utils/viconutils.h"
|
||||||
|
#include "vmainwindow.h"
|
||||||
|
#include "vnotebookselector.h"
|
||||||
|
#include "vnotefile.h"
|
||||||
|
|
||||||
|
extern VNote *g_vnote;
|
||||||
|
|
||||||
|
extern VMainWindow *g_mainWin;
|
||||||
|
|
||||||
|
VSearchUE::VSearchUE(QObject *p_parent)
|
||||||
|
: IUniversalEntry(p_parent),
|
||||||
|
m_search(NULL),
|
||||||
|
m_inSearch(false),
|
||||||
|
m_listWidget(NULL),
|
||||||
|
m_id(ID::Name_Notebook_AllNotebook)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VSearchUE::description(int p_id) const
|
||||||
|
{
|
||||||
|
switch (p_id) {
|
||||||
|
case ID::Name_Notebook_AllNotebook:
|
||||||
|
return tr("List and search all notebooks");
|
||||||
|
|
||||||
|
case ID::Name_FolderNote_AllNotebook:
|
||||||
|
return tr("Search the name of folders/notes in all notebooks");
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return tr("Invalid ID %1").arg(p_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::init()
|
||||||
|
{
|
||||||
|
if (m_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(m_widgetParent);
|
||||||
|
|
||||||
|
m_initialized = true;
|
||||||
|
|
||||||
|
m_search = new VSearch(this);
|
||||||
|
connect(m_search, &VSearch::resultItemAdded,
|
||||||
|
this, &VSearchUE::handleSearchItemAdded);
|
||||||
|
connect(m_search, &VSearch::finished,
|
||||||
|
this, &VSearchUE::handleSearchFinished);
|
||||||
|
|
||||||
|
m_noteIcon = VIconUtils::treeViewIcon(":/resources/icons/note_item.svg");
|
||||||
|
m_folderIcon = VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg");
|
||||||
|
m_notebookIcon = VIconUtils::treeViewIcon(":/resources/icons/notebook_item.svg");
|
||||||
|
|
||||||
|
m_listWidget = new VListWidgetDoubleRows(m_widgetParent);
|
||||||
|
m_listWidget->setFitContent(true);
|
||||||
|
m_listWidget->hide();
|
||||||
|
connect(m_listWidget, &VListWidgetDoubleRows::itemActivated,
|
||||||
|
this, &VSearchUE::activateItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *VSearchUE::widget(int p_id)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
|
||||||
|
switch (p_id) {
|
||||||
|
case ID::Name_Notebook_AllNotebook:
|
||||||
|
V_FALLTHROUGH;
|
||||||
|
case ID::Name_FolderNote_AllNotebook:
|
||||||
|
return m_listWidget;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::processCommand(int p_id, const QString &p_cmd)
|
||||||
|
{
|
||||||
|
qDebug() << "processCommand" << p_id << p_cmd;
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
clear(-1);
|
||||||
|
|
||||||
|
m_inSearch = true;
|
||||||
|
m_id = p_id;
|
||||||
|
emit stateUpdated(State::Busy);
|
||||||
|
switch (p_id) {
|
||||||
|
case ID::Name_Notebook_AllNotebook:
|
||||||
|
searchNameOfAllNotebooks(p_cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ID::Name_FolderNote_AllNotebook:
|
||||||
|
searchNameOfFolderNoteInAllNotebooks(p_cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
widget(p_id)->updateGeometry();
|
||||||
|
emit widgetUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::searchNameOfAllNotebooks(const QString &p_cmd)
|
||||||
|
{
|
||||||
|
const QVector<VNotebook *> ¬ebooks = g_vnote->getNotebooks();
|
||||||
|
if (p_cmd.isEmpty()) {
|
||||||
|
// List all the notebooks.
|
||||||
|
for (auto const & nb : notebooks) {
|
||||||
|
QSharedPointer<VSearchResultItem> item(new VSearchResultItem(VSearchResultItem::Notebook,
|
||||||
|
VSearchResultItem::LineNumber,
|
||||||
|
nb->getName(),
|
||||||
|
nb->getPath()));
|
||||||
|
handleSearchItemAdded(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_inSearch = false;
|
||||||
|
emit stateUpdated(State::Success);
|
||||||
|
} else {
|
||||||
|
// Do a fuzzy search against the name of the notebooks.
|
||||||
|
VSearchConfig::Option opt = VSearchConfig::Fuzzy;
|
||||||
|
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::AllNotebooks,
|
||||||
|
VSearchConfig::Name,
|
||||||
|
VSearchConfig::Notebook,
|
||||||
|
VSearchConfig::Internal,
|
||||||
|
opt,
|
||||||
|
p_cmd,
|
||||||
|
QString()));
|
||||||
|
m_search->setConfig(config);
|
||||||
|
|
||||||
|
QSharedPointer<VSearchResult> result = m_search->search(notebooks);
|
||||||
|
handleSearchFinished(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd)
|
||||||
|
{
|
||||||
|
const QVector<VNotebook *> ¬ebooks = g_vnote->getNotebooks();
|
||||||
|
if (p_cmd.isEmpty()) {
|
||||||
|
m_inSearch = false;
|
||||||
|
emit stateUpdated(State::Success);
|
||||||
|
} else {
|
||||||
|
VSearchConfig::Option opt = VSearchConfig::NoneOption;
|
||||||
|
QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::AllNotebooks,
|
||||||
|
VSearchConfig::Name,
|
||||||
|
VSearchConfig::Folder | VSearchConfig::Note,
|
||||||
|
VSearchConfig::Internal,
|
||||||
|
opt,
|
||||||
|
p_cmd,
|
||||||
|
QString()));
|
||||||
|
m_search->setConfig(config);
|
||||||
|
QSharedPointer<VSearchResult> result = m_search->search(notebooks);
|
||||||
|
handleSearchFinished(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::clear(int p_id)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_id);
|
||||||
|
stopSearch();
|
||||||
|
|
||||||
|
m_data.clear();
|
||||||
|
m_listWidget->clearAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::entryHidden(int p_id)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::handleSearchItemAdded(const QSharedPointer<VSearchResultItem> &p_item)
|
||||||
|
{
|
||||||
|
switch (m_id) {
|
||||||
|
case ID::Name_Notebook_AllNotebook:
|
||||||
|
V_FALLTHROUGH;
|
||||||
|
case ID::Name_FolderNote_AllNotebook:
|
||||||
|
appendItemToList(p_item);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::appendItemToList(const QSharedPointer<VSearchResultItem> &p_item)
|
||||||
|
{
|
||||||
|
static int itemAdded = 0;
|
||||||
|
m_data.append(p_item);
|
||||||
|
|
||||||
|
QString first, second;
|
||||||
|
if (p_item->m_text.isEmpty()) {
|
||||||
|
first = p_item->m_path;
|
||||||
|
} else {
|
||||||
|
first = p_item->m_text;
|
||||||
|
second = p_item->m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon *icon = NULL;
|
||||||
|
switch (p_item->m_type) {
|
||||||
|
case VSearchResultItem::Note:
|
||||||
|
icon = &m_noteIcon;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchResultItem::Folder:
|
||||||
|
icon = &m_folderIcon;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchResultItem::Notebook:
|
||||||
|
icon = &m_notebookIcon;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QListWidgetItem *item = m_listWidget->addItem(*icon, first, second);
|
||||||
|
item->setData(Qt::UserRole, m_data.size() - 1);
|
||||||
|
item->setToolTip(p_item->m_path);
|
||||||
|
|
||||||
|
if (m_listWidget->currentRow() == -1) {
|
||||||
|
m_listWidget->setCurrentRow(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++itemAdded >= 10) {
|
||||||
|
itemAdded = 0;
|
||||||
|
m_listWidget->updateGeometry();
|
||||||
|
emit widgetUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::handleSearchFinished(const QSharedPointer<VSearchResult> &p_result)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_inSearch);
|
||||||
|
Q_ASSERT(p_result->m_state != VSearchState::Idle);
|
||||||
|
|
||||||
|
qDebug() << "handleSearchFinished" << (int)p_result->m_state;
|
||||||
|
|
||||||
|
IUniversalEntry::State state = State::Idle;
|
||||||
|
|
||||||
|
switch (p_result->m_state) {
|
||||||
|
case VSearchState::Busy:
|
||||||
|
qDebug() << "search is ongoing";
|
||||||
|
state = State::Busy;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case VSearchState::Success:
|
||||||
|
qDebug() << "search succeeded";
|
||||||
|
state = State::Success;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchState::Fail:
|
||||||
|
qDebug() << "search failed";
|
||||||
|
state = State::Fail;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchState::Cancelled:
|
||||||
|
qDebug() << "search cancelled";
|
||||||
|
state = State::Cancelled;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_search->clear();
|
||||||
|
m_inSearch = false;
|
||||||
|
|
||||||
|
widget(m_id)->updateGeometry();
|
||||||
|
emit widgetUpdated();
|
||||||
|
|
||||||
|
emit stateUpdated(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::stopSearch()
|
||||||
|
{
|
||||||
|
if (m_inSearch) {
|
||||||
|
m_search->stop();
|
||||||
|
|
||||||
|
while (m_inSearch) {
|
||||||
|
VUtils::sleepWait(100);
|
||||||
|
qDebug() << "sleep wait for search to stop";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QSharedPointer<VSearchResultItem> &VSearchUE::itemResultData(const QListWidgetItem *p_item) const
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_item);
|
||||||
|
int idx = p_item->data(Qt::UserRole).toInt();
|
||||||
|
Q_ASSERT(idx >= 0 && idx < m_data.size());
|
||||||
|
return m_data[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::activateItem(const QListWidgetItem *p_item)
|
||||||
|
{
|
||||||
|
if (!p_item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit requestHideUniversalEntry();
|
||||||
|
|
||||||
|
const QSharedPointer<VSearchResultItem> &resItem = itemResultData(p_item);
|
||||||
|
switch (resItem->m_type) {
|
||||||
|
case VSearchResultItem::Note:
|
||||||
|
{
|
||||||
|
QStringList files(resItem->m_path);
|
||||||
|
g_mainWin->openFiles(files);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VSearchResultItem::Folder:
|
||||||
|
{
|
||||||
|
VDirectory *dir = g_vnote->getInternalDirectory(resItem->m_path);
|
||||||
|
if (dir) {
|
||||||
|
g_mainWin->locateDirectory(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VSearchResultItem::Notebook:
|
||||||
|
{
|
||||||
|
VNotebook *nb = g_vnote->getNotebook(resItem->m_path);
|
||||||
|
if (nb) {
|
||||||
|
g_mainWin->getNotebookSelector()->locateNotebook(nb);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::selectNextItem(int p_id, bool p_forward)
|
||||||
|
{
|
||||||
|
switch (p_id) {
|
||||||
|
case ID::Name_Notebook_AllNotebook:
|
||||||
|
V_FALLTHROUGH;
|
||||||
|
case ID::Name_FolderNote_AllNotebook:
|
||||||
|
{
|
||||||
|
// Could not use postEvent method here which will induce infinite recursion.
|
||||||
|
m_listWidget->selectNextItem(p_forward);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::activate(int p_id)
|
||||||
|
{
|
||||||
|
switch (p_id) {
|
||||||
|
case ID::Name_Notebook_AllNotebook:
|
||||||
|
V_FALLTHROUGH;
|
||||||
|
case ID::Name_FolderNote_AllNotebook:
|
||||||
|
{
|
||||||
|
activateItem(m_listWidget->currentItem());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchUE::askToStop(int p_id)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_id);
|
||||||
|
m_search->stop();
|
||||||
|
}
|
85
src/vsearchue.h
Normal file
85
src/vsearchue.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#ifndef VSEARCHUE_H
|
||||||
|
#define VSEARCHUE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "iuniversalentry.h"
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
#include "vsearchconfig.h"
|
||||||
|
|
||||||
|
class VListWidgetDoubleRows;
|
||||||
|
class QListWidgetItem;
|
||||||
|
|
||||||
|
|
||||||
|
// Universal Entry to list and search all the notebooks.
|
||||||
|
class VSearchUE : public IUniversalEntry
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum ID
|
||||||
|
{
|
||||||
|
// List and search the name of all notebooks.
|
||||||
|
Name_Notebook_AllNotebook = 0,
|
||||||
|
|
||||||
|
// Search the name of the folder/note in all the notebooks.
|
||||||
|
Name_FolderNote_AllNotebook
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit VSearchUE(QObject *p_parent = nullptr);
|
||||||
|
|
||||||
|
QString description(int p_id) const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
QWidget *widget(int p_id) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void processCommand(int p_id, const QString &p_cmd) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void clear(int p_id) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void entryHidden(int p_id) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void selectNextItem(int p_id, bool p_forward) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void activate(int p_id) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void askToStop(int p_id) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void init() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleSearchItemAdded(const QSharedPointer<VSearchResultItem> &p_item);
|
||||||
|
|
||||||
|
void handleSearchFinished(const QSharedPointer<VSearchResult> &p_result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void searchNameOfAllNotebooks(const QString &p_cmd);
|
||||||
|
|
||||||
|
void searchNameOfFolderNoteInAllNotebooks(const QString &p_cmd);
|
||||||
|
|
||||||
|
// Stop the search synchronously.
|
||||||
|
void stopSearch();
|
||||||
|
|
||||||
|
void appendItemToList(const QSharedPointer<VSearchResultItem> &p_item);
|
||||||
|
|
||||||
|
void activateItem(const QListWidgetItem *p_item);
|
||||||
|
|
||||||
|
const QSharedPointer<VSearchResultItem> &itemResultData(const QListWidgetItem *p_item) const;
|
||||||
|
|
||||||
|
VSearch *m_search;
|
||||||
|
|
||||||
|
bool m_inSearch;
|
||||||
|
|
||||||
|
// Current instance ID.
|
||||||
|
int m_id;
|
||||||
|
|
||||||
|
QVector<QSharedPointer<VSearchResultItem> > m_data;
|
||||||
|
|
||||||
|
QIcon m_noteIcon;
|
||||||
|
QIcon m_folderIcon;
|
||||||
|
QIcon m_notebookIcon;
|
||||||
|
|
||||||
|
VListWidgetDoubleRows *m_listWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VSEARCHUE_H
|
@ -5,31 +5,119 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QHideEvent>
|
#include <QHideEvent>
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QStyleOption>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QAtomicInt>
|
||||||
|
|
||||||
#include "vlineedit.h"
|
#include "vmetawordlineedit.h"
|
||||||
#include "utils/vutils.h"
|
#include "utils/vutils.h"
|
||||||
|
#include "vlistwidget.h"
|
||||||
|
#include "vpalette.h"
|
||||||
|
|
||||||
#define MINIMUM_WIDTH 200
|
#define MINIMUM_WIDTH 200
|
||||||
|
|
||||||
|
#define CMD_EDIT_INTERVAL 500
|
||||||
|
|
||||||
|
extern VPalette *g_palette;
|
||||||
|
|
||||||
|
VUniversalEntryContainer::VUniversalEntryContainer(QWidget *p_parent)
|
||||||
|
: QWidget(p_parent),
|
||||||
|
m_widget(NULL)
|
||||||
|
{
|
||||||
|
m_layout = new QVBoxLayout();
|
||||||
|
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
setLayout(m_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntryContainer::clear()
|
||||||
|
{
|
||||||
|
if (m_widget) {
|
||||||
|
m_layout->removeWidget(m_widget);
|
||||||
|
m_widget->hide();
|
||||||
|
m_widget = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustSizeByWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntryContainer::setWidget(QWidget *p_widget)
|
||||||
|
{
|
||||||
|
if (m_widget != p_widget) {
|
||||||
|
clear();
|
||||||
|
m_widget = p_widget;
|
||||||
|
m_layout->addWidget(m_widget);
|
||||||
|
m_widget->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustSizeByWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntryContainer::adjustSizeByWidget()
|
||||||
|
{
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize VUniversalEntryContainer::sizeHint() const
|
||||||
|
{
|
||||||
|
if (m_widget) {
|
||||||
|
return m_widget->sizeHint();
|
||||||
|
} else {
|
||||||
|
return QWidget::sizeHint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
VUniversalEntry::VUniversalEntry(QWidget *p_parent)
|
VUniversalEntry::VUniversalEntry(QWidget *p_parent)
|
||||||
: QWidget(p_parent),
|
: QWidget(p_parent),
|
||||||
m_availableRect(0, 0, MINIMUM_WIDTH, MINIMUM_WIDTH)
|
m_availableRect(0, 0, MINIMUM_WIDTH, MINIMUM_WIDTH),
|
||||||
|
m_lastEntry(NULL),
|
||||||
|
m_inQueue(0),
|
||||||
|
m_pendingCommand(false)
|
||||||
{
|
{
|
||||||
m_minimumWidth = MINIMUM_WIDTH * VUtils::calculateScaleFactor() + 0.5;
|
m_minimumWidth = MINIMUM_WIDTH * VUtils::calculateScaleFactor() + 0.5;
|
||||||
|
|
||||||
|
m_cmdTimer = new QTimer(this);
|
||||||
|
m_cmdTimer->setSingleShot(true);
|
||||||
|
m_cmdTimer->setInterval(CMD_EDIT_INTERVAL);
|
||||||
|
connect(m_cmdTimer, &QTimer::timeout,
|
||||||
|
this, [this]() {
|
||||||
|
processCommand();
|
||||||
|
});
|
||||||
|
|
||||||
setupUI();
|
setupUI();
|
||||||
|
|
||||||
|
m_infoWidget = new VListWidget(this);
|
||||||
|
m_infoWidget->setFitContent(true);
|
||||||
|
m_container->setWidget(m_infoWidget);
|
||||||
|
|
||||||
|
m_cmdStyleSheet = m_cmdEdit->styleSheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VUniversalEntry::setupUI()
|
void VUniversalEntry::setupUI()
|
||||||
{
|
{
|
||||||
m_cmdEdit = new VLineEdit(this);
|
m_cmdEdit = new VMetaWordLineEdit(this);
|
||||||
m_cmdEdit->setPlaceholderText(tr("Welcome to Universal Entry"));
|
m_cmdEdit->setPlaceholderText(tr("Welcome to Universal Entry"));
|
||||||
|
connect(m_cmdEdit, &VMetaWordLineEdit::textEdited,
|
||||||
|
this, [this]() {
|
||||||
|
m_cmdTimer->stop();
|
||||||
|
m_cmdTimer->start();
|
||||||
|
});
|
||||||
|
|
||||||
m_layout = new QVBoxLayout();
|
m_container = new VUniversalEntryContainer(this);
|
||||||
m_layout->addWidget(m_cmdEdit);
|
|
||||||
|
|
||||||
m_layout->setContentsMargins(0, 0, 0, 0);
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout->addWidget(m_cmdEdit);
|
||||||
|
mainLayout->addWidget(m_container);
|
||||||
|
|
||||||
setLayout(m_layout);
|
mainLayout->setContentsMargins(1, 1, 1, 1);
|
||||||
|
mainLayout->setSpacing(0);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
setMinimumWidth(m_minimumWidth);
|
setMinimumWidth(m_minimumWidth);
|
||||||
}
|
}
|
||||||
@ -37,6 +125,10 @@ void VUniversalEntry::setupUI()
|
|||||||
void VUniversalEntry::hideEvent(QHideEvent *p_event)
|
void VUniversalEntry::hideEvent(QHideEvent *p_event)
|
||||||
{
|
{
|
||||||
QWidget::hideEvent(p_event);
|
QWidget::hideEvent(p_event);
|
||||||
|
if (m_lastEntry) {
|
||||||
|
m_lastEntry->m_entry->entryHidden(m_lastEntry->m_id);
|
||||||
|
}
|
||||||
|
|
||||||
emit exited();
|
emit exited();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +137,6 @@ void VUniversalEntry::showEvent(QShowEvent *p_event)
|
|||||||
QWidget::showEvent(p_event);
|
QWidget::showEvent(p_event);
|
||||||
|
|
||||||
m_cmdEdit->setFocus();
|
m_cmdEdit->setFocus();
|
||||||
m_cmdEdit->selectAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VUniversalEntry::setAvailableRect(const QRect &p_rect)
|
void VUniversalEntry::setAvailableRect(const QRect &p_rect)
|
||||||
@ -55,4 +146,193 @@ void VUniversalEntry::setAvailableRect(const QRect &p_rect)
|
|||||||
if (m_availableRect.width() < m_minimumWidth) {
|
if (m_availableRect.width() < m_minimumWidth) {
|
||||||
m_availableRect.setWidth(m_minimumWidth);
|
m_availableRect.setWidth(m_minimumWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMaximumSize(m_availableRect.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntry::registerEntry(QChar p_key, IUniversalEntry *p_entry, int p_id)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!m_entries.contains(p_key));
|
||||||
|
|
||||||
|
p_entry->setParent(this);
|
||||||
|
p_entry->setWidgetParent(this);
|
||||||
|
connect(p_entry, &IUniversalEntry::widgetUpdated,
|
||||||
|
this, [this]() {
|
||||||
|
m_container->adjustSizeByWidget();
|
||||||
|
adjustSize();
|
||||||
|
});
|
||||||
|
connect(p_entry, &IUniversalEntry::stateUpdated,
|
||||||
|
this, &VUniversalEntry::updateState);
|
||||||
|
connect(p_entry, &IUniversalEntry::requestHideUniversalEntry,
|
||||||
|
this, &VUniversalEntry::hide);
|
||||||
|
|
||||||
|
m_entries.insert(p_key, Entry(p_entry, p_id));
|
||||||
|
m_infoWidget->addItem(QString("%1: %2").arg(p_key)
|
||||||
|
.arg(p_entry->description(p_id)));
|
||||||
|
m_infoWidget->updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntry::processCommand()
|
||||||
|
{
|
||||||
|
if (!m_inQueue.testAndSetRelaxed(0, 1)) {
|
||||||
|
// There is already a job in queue.
|
||||||
|
qDebug() << "already a job in queue, pend a new job and ask to stop";
|
||||||
|
m_pendingCommand = true;
|
||||||
|
if (m_lastEntry) {
|
||||||
|
m_lastEntry->m_entry->askToStop(m_lastEntry->m_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
redo:
|
||||||
|
QString cmd = m_cmdEdit->getEvaluatedText();
|
||||||
|
processCommand(cmd);
|
||||||
|
if (m_pendingCommand && cmd != m_cmdEdit->getEvaluatedText()) {
|
||||||
|
// Handle pending job.
|
||||||
|
qDebug() << "handle pending job" << cmd;
|
||||||
|
m_pendingCommand = false;
|
||||||
|
goto redo;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_inQueue.store(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntry::processCommand(const QString &p_cmd)
|
||||||
|
{
|
||||||
|
if (p_cmd.isEmpty()) {
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = m_entries.find(p_cmd[0]);
|
||||||
|
if (it == m_entries.end()) {
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Entry &entry = it.value();
|
||||||
|
if (m_lastEntry && m_lastEntry != &entry) {
|
||||||
|
m_lastEntry->m_entry->clear(m_lastEntry->m_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lastEntry = &entry;
|
||||||
|
m_container->setWidget(entry.m_entry->widget(entry.m_id));
|
||||||
|
adjustSize();
|
||||||
|
entry.m_entry->processCommand(entry.m_id, p_cmd.mid(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntry::clear()
|
||||||
|
{
|
||||||
|
if (m_lastEntry) {
|
||||||
|
m_lastEntry->m_entry->clear(m_lastEntry->m_id);
|
||||||
|
m_lastEntry = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_container->setWidget(m_infoWidget);
|
||||||
|
adjustSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntry::keyPressEvent(QKeyEvent *p_event)
|
||||||
|
{
|
||||||
|
int modifiers = p_event->modifiers();
|
||||||
|
bool forward = true;
|
||||||
|
switch (p_event->key()) {
|
||||||
|
case Qt::Key_BracketLeft:
|
||||||
|
if (VUtils::isControlModifierForVim(modifiers)) {
|
||||||
|
// Hide.
|
||||||
|
hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Up/Down Ctrl+K/J to navigate to next item.
|
||||||
|
case Qt::Key_Up:
|
||||||
|
forward = false;
|
||||||
|
V_FALLTHROUGH;
|
||||||
|
case Qt::Key_Down:
|
||||||
|
if (m_lastEntry) {
|
||||||
|
m_lastEntry->m_entry->selectNextItem(m_lastEntry->m_id, forward);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qt::Key_K:
|
||||||
|
forward = false;
|
||||||
|
V_FALLTHROUGH;
|
||||||
|
case Qt::Key_J:
|
||||||
|
if (m_lastEntry && VUtils::isControlModifierForVim(modifiers)) {
|
||||||
|
m_lastEntry->m_entry->selectNextItem(m_lastEntry->m_id, forward);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qt::Key_Enter:
|
||||||
|
// Fall through.
|
||||||
|
V_FALLTHROUGH;
|
||||||
|
case Qt::Key_Return:
|
||||||
|
{
|
||||||
|
if (m_lastEntry) {
|
||||||
|
m_lastEntry->m_entry->activate(m_lastEntry->m_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Qt::Key_E:
|
||||||
|
if (VUtils::isControlModifierForVim(modifiers)) {
|
||||||
|
// Ctrl+E to eliminate input except the command key.
|
||||||
|
QString cmd = m_cmdEdit->getEvaluatedText();
|
||||||
|
if (!cmd.isEmpty()) {
|
||||||
|
m_cmdEdit->setText(cmd.left(1));
|
||||||
|
m_cmdTimer->stop();
|
||||||
|
processCommand();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::keyPressEvent(p_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntry::paintEvent(QPaintEvent *p_event)
|
||||||
|
{
|
||||||
|
QStyleOption opt;
|
||||||
|
opt.init(this);
|
||||||
|
QPainter p(this);
|
||||||
|
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||||
|
|
||||||
|
QWidget::paintEvent(p_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VUniversalEntry::updateState(IUniversalEntry::State p_state)
|
||||||
|
{
|
||||||
|
QString fg;
|
||||||
|
switch (p_state) {
|
||||||
|
case IUniversalEntry::Busy:
|
||||||
|
fg = g_palette->color("ue_cmd_busy_border");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IUniversalEntry::Fail:
|
||||||
|
fg = g_palette->color("ue_cmd_fail_border");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fg.isEmpty()) {
|
||||||
|
m_cmdEdit->setStyleSheet(m_cmdStyleSheet);
|
||||||
|
} else {
|
||||||
|
m_cmdEdit->setStyleSheet(QString("border-color: %1;").arg(fg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,41 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QRect>
|
#include <QRect>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QAtomicInt>
|
||||||
|
|
||||||
class VLineEdit;
|
#include "iuniversalentry.h"
|
||||||
|
|
||||||
|
class VMetaWordLineEdit;
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
class QHideEvent;
|
class QHideEvent;
|
||||||
class QShowEvent;
|
class QShowEvent;
|
||||||
|
class QPaintEvent;
|
||||||
|
class QKeyEvent;
|
||||||
|
class QTimer;
|
||||||
|
class VListWidget;
|
||||||
|
|
||||||
|
class VUniversalEntryContainer : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
VUniversalEntryContainer(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void setWidget(QWidget *p_widget);
|
||||||
|
|
||||||
|
void adjustSizeByWidget();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget *m_widget;
|
||||||
|
|
||||||
|
QVBoxLayout *m_layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class VUniversalEntry : public QWidget
|
class VUniversalEntry : public QWidget
|
||||||
{
|
{
|
||||||
@ -18,6 +48,11 @@ public:
|
|||||||
// Set the availabel width and height.
|
// Set the availabel width and height.
|
||||||
void setAvailableRect(const QRect &p_rect);
|
void setAvailableRect(const QRect &p_rect);
|
||||||
|
|
||||||
|
// Register an entry at @p_key.
|
||||||
|
// Different entries may use the same @p_entry, in which case they can use
|
||||||
|
// @p_id to distinguish.
|
||||||
|
void registerEntry(QChar p_key, IUniversalEntry *p_entry, int p_id = 0);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// Exit Universal Entry.
|
// Exit Universal Entry.
|
||||||
void exited();
|
void exited();
|
||||||
@ -27,17 +62,62 @@ protected:
|
|||||||
|
|
||||||
void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
|
void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
Entry()
|
||||||
|
: m_entry(NULL), m_id(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry(IUniversalEntry *p_entry, int p_id)
|
||||||
|
: m_entry(p_entry), m_id(p_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IUniversalEntry *m_entry;
|
||||||
|
int m_id;
|
||||||
|
};
|
||||||
|
|
||||||
void setupUI();
|
void setupUI();
|
||||||
|
|
||||||
VLineEdit *m_cmdEdit;
|
void clear();
|
||||||
|
|
||||||
QVBoxLayout *m_layout;
|
void processCommand();
|
||||||
|
|
||||||
|
void processCommand(const QString &p_cmd);
|
||||||
|
|
||||||
|
void updateState(IUniversalEntry::State p_state);
|
||||||
|
|
||||||
|
VMetaWordLineEdit *m_cmdEdit;
|
||||||
|
|
||||||
|
VUniversalEntryContainer *m_container;
|
||||||
|
|
||||||
// Rect availabel for the UE to use.
|
// Rect availabel for the UE to use.
|
||||||
QRect m_availableRect;
|
QRect m_availableRect;
|
||||||
|
|
||||||
int m_minimumWidth;
|
int m_minimumWidth;
|
||||||
|
|
||||||
|
QHash<QChar, Entry> m_entries;
|
||||||
|
|
||||||
|
// Widget to list all entries.
|
||||||
|
VListWidget *m_infoWidget;
|
||||||
|
|
||||||
|
QTimer *m_cmdTimer;
|
||||||
|
|
||||||
|
// Last used Entry.
|
||||||
|
const Entry *m_lastEntry;
|
||||||
|
|
||||||
|
// The CMD edit's original style sheet.
|
||||||
|
QString m_cmdStyleSheet;
|
||||||
|
|
||||||
|
QAtomicInt m_inQueue;
|
||||||
|
|
||||||
|
bool m_pendingCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VUNIVERSALENTRY_H
|
#endif // VUNIVERSALENTRY_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user