18
#include "SearchWidget.h"
19
#include "ui_SearchHelpWidget.h"
20
#include "ui_SearchWidget.h"
27
#include "core/SignalMultiplexer.h"
29
#include "gui/widgets/PopupHelpWidget.h"
31
SearchWidget::SearchWidget(QWidget* parent)
33
, m_ui(new Ui::SearchWidget())
34
, m_searchTimer(new QTimer(this))
35
, m_clearSearchTimer(new QTimer(this))
38
setFocusProxy(m_ui->searchEdit);
40
m_helpWidget = new PopupHelpWidget(m_ui->searchEdit);
41
Ui::SearchHelpWidget helpUi;
42
helpUi.setupUi(m_helpWidget);
44
m_searchTimer->setSingleShot(true);
45
m_clearSearchTimer->setSingleShot(true);
47
new QShortcut(Qt::CTRL + Qt::Key_J, this, SLOT(toggleHelp()), nullptr, Qt::WidgetWithChildrenShortcut);
49
connect(m_ui->searchEdit, SIGNAL(textChanged(QString)), SLOT(startSearchTimer()));
50
connect(m_ui->helpIcon, SIGNAL(triggered()), SLOT(toggleHelp()));
51
connect(m_ui->searchIcon, SIGNAL(triggered()), SLOT(showSearchMenu()));
52
connect(m_ui->saveIcon, &QAction::triggered, this, [this] { emit saveSearch(m_ui->searchEdit->text()); });
53
connect(m_searchTimer, SIGNAL(timeout()), SLOT(startSearch()));
54
connect(m_clearSearchTimer, SIGNAL(timeout()), SLOT(clearSearch()));
55
connect(this, SIGNAL(escapePressed()), SLOT(clearSearch()));
57
m_ui->searchEdit->setPlaceholderText(tr("Search (%1)…", "Search placeholder text, %1 is the keyboard shortcut")
58
.arg(QKeySequence(QKeySequence::Find).toString(QKeySequence::NativeText)));
59
m_ui->searchEdit->installEventFilter(this);
61
m_searchMenu = new QMenu(this);
62
m_actionCaseSensitive = m_searchMenu->addAction(tr("Case sensitive"), this, SLOT(updateCaseSensitive()));
63
m_actionCaseSensitive->setObjectName("actionSearchCaseSensitive");
64
m_actionCaseSensitive->setCheckable(true);
66
m_actionLimitGroup = m_searchMenu->addAction(tr("Limit search to selected group"), this, SLOT(updateLimitGroup()));
67
m_actionLimitGroup->setObjectName("actionSearchLimitGroup");
68
m_actionLimitGroup->setCheckable(true);
69
m_actionLimitGroup->setChecked(config()->get(Config::SearchLimitGroup).toBool());
71
m_ui->searchIcon->setIcon(icons()->icon("system-search"));
72
m_ui->searchEdit->addAction(m_ui->searchIcon, QLineEdit::LeadingPosition);
74
m_ui->helpIcon->setIcon(icons()->icon("system-help"));
75
m_ui->searchEdit->addAction(m_ui->helpIcon, QLineEdit::TrailingPosition);
77
m_ui->saveIcon->setIcon(icons()->icon("document-save"));
78
m_ui->searchEdit->addAction(m_ui->saveIcon, QLineEdit::TrailingPosition);
79
m_ui->saveIcon->setVisible(false);
82
for (QToolButton* toolButton : m_ui->searchEdit->findChildren<QToolButton*>()) {
83
toolButton->setVisible(toolButton->defaultAction()->isVisible());
87
SearchWidget::~SearchWidget() = default;
89
bool SearchWidget::eventFilter(QObject* obj, QEvent* event)
91
if (event->type() == QEvent::KeyPress) {
92
auto keyEvent = static_cast<QKeyEvent*>(event);
93
if (keyEvent->key() == Qt::Key_Escape) {
96
} else if (keyEvent->matches(QKeySequence::Copy)) {
99
if (!m_ui->searchEdit->hasSelectedText()) {
103
} else if (keyEvent->matches(QKeySequence::MoveToNextLine)) {
104
if (m_ui->searchEdit->cursorPosition() == m_ui->searchEdit->text().length()) {
110
m_ui->searchEdit->setCursorPosition(m_ui->searchEdit->text().length());
114
} else if (event->type() == QEvent::FocusOut) {
115
if (config()->get(Config::Security_ClearSearch).toBool()) {
116
int timeout = config()->get(Config::Security_ClearSearchTimeout).toInt();
119
m_clearSearchTimer->start(timeout * 60000);
123
} else if (event->type() == QEvent::FocusIn) {
125
m_clearSearchTimer->stop();
128
return QWidget::eventFilter(obj, event);
131
void SearchWidget::connectSignals(SignalMultiplexer& mx)
134
mx.connect(this, SIGNAL(search(QString)), SLOT(search(QString)));
135
mx.connect(this, SIGNAL(saveSearch(QString)), SLOT(saveSearch(QString)));
136
mx.connect(this, SIGNAL(caseSensitiveChanged(bool)), SLOT(setSearchCaseSensitive(bool)));
137
mx.connect(this, SIGNAL(limitGroupChanged(bool)), SLOT(setSearchLimitGroup(bool)));
138
mx.connect(this, SIGNAL(copyPressed()), SLOT(copyPassword()));
139
mx.connect(this, SIGNAL(downPressed()), SLOT(focusOnEntries()));
140
mx.connect(SIGNAL(requestSearch(QString)), m_ui->searchEdit, SLOT(setText(QString)));
141
mx.connect(SIGNAL(clearSearch()), this, SLOT(clearSearch()));
142
mx.connect(SIGNAL(entrySelectionChanged()), this, SLOT(resetSearchClearTimer()));
143
mx.connect(SIGNAL(currentModeChanged(DatabaseWidget::Mode)), this, SLOT(resetSearchClearTimer()));
144
mx.connect(SIGNAL(databaseUnlocked()), this, SLOT(focusSearch()));
145
mx.connect(m_ui->searchEdit, SIGNAL(returnPressed()), SLOT(switchToEntryEdit()));
148
void SearchWidget::databaseChanged(DatabaseWidget* dbWidget)
150
if (dbWidget != nullptr) {
152
m_ui->searchEdit->setText(dbWidget->getCurrentSearch());
154
emit caseSensitiveChanged(m_actionCaseSensitive->isChecked());
155
emit limitGroupChanged(m_actionLimitGroup->isChecked());
161
void SearchWidget::startSearchTimer()
163
if (!m_searchTimer->isActive()) {
164
m_searchTimer->stop();
166
m_searchTimer->start(100);
169
void SearchWidget::startSearch()
171
if (!m_searchTimer->isActive()) {
172
m_searchTimer->stop();
175
m_ui->saveIcon->setVisible(true);
176
search(m_ui->searchEdit->text());
179
void SearchWidget::resetSearchClearTimer()
182
if (m_clearSearchTimer->isActive()) {
183
m_clearSearchTimer->start();
187
void SearchWidget::updateCaseSensitive()
189
emit caseSensitiveChanged(m_actionCaseSensitive->isChecked());
192
void SearchWidget::setCaseSensitive(bool state)
194
m_actionCaseSensitive->setChecked(state);
195
updateCaseSensitive();
198
void SearchWidget::updateLimitGroup()
200
config()->set(Config::SearchLimitGroup, m_actionLimitGroup->isChecked());
201
emit limitGroupChanged(m_actionLimitGroup->isChecked());
204
void SearchWidget::setLimitGroup(bool state)
206
m_actionLimitGroup->setChecked(state);
210
void SearchWidget::focusSearch()
212
m_ui->searchEdit->setFocus();
213
m_ui->searchEdit->selectAll();
216
void SearchWidget::clearSearch()
218
m_ui->searchEdit->clear();
219
m_ui->saveIcon->setVisible(false);
220
emit searchCanceled();
223
void SearchWidget::toggleHelp()
225
if (m_helpWidget->isVisible()) {
226
m_helpWidget->hide();
228
m_helpWidget->show();
232
void SearchWidget::showSearchMenu()
234
m_searchMenu->exec(m_ui->searchEdit->mapToGlobal(m_ui->searchEdit->rect().bottomLeft()));