diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 413c9fb1c..16cd879b9 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -9955,6 +9955,10 @@ This option is deprecated, use --set-key-file instead.
Limit search to selected group
+
+ Press Enter to search
+
+
SettingsClientModel
diff --git a/src/core/Config.h b/src/core/Config.h
index b4f3bdc04..5678bbc6e 100644
--- a/src/core/Config.h
+++ b/src/core/Config.h
@@ -98,6 +98,7 @@ public:
GUI_CompactMode,
GUI_CheckForUpdates,
GUI_CheckForUpdatesIncludeBetas,
+ SearchWaitForEnter,
GUI_ShowExpiredEntriesOnDatabaseUnlock,
GUI_ShowExpiredEntriesOnDatabaseUnlockOffsetDays,
GUI_FontSizeOffset,
diff --git a/src/gui/SearchWidget.cpp b/src/gui/SearchWidget.cpp
index a504518bc..5fce8a5aa 100644
--- a/src/gui/SearchWidget.cpp
+++ b/src/gui/SearchWidget.cpp
@@ -54,6 +54,7 @@ SearchWidget::SearchWidget(QWidget* parent)
connect(m_searchTimer, SIGNAL(timeout()), SLOT(startSearch()));
connect(m_clearSearchTimer, SIGNAL(timeout()), SLOT(clearSearch()));
connect(this, SIGNAL(escapePressed()), SLOT(clearSearch()));
+ connect(m_ui->searchEdit, &QLineEdit::returnPressed, this, &SearchWidget::onReturnPressed);
m_ui->searchEdit->setPlaceholderText(tr("Search (%1)…", "Search placeholder text, %1 is the keyboard shortcut")
.arg(QKeySequence(QKeySequence::Find).toString(QKeySequence::NativeText)));
@@ -69,6 +70,12 @@ SearchWidget::SearchWidget(QWidget* parent)
m_actionLimitGroup->setCheckable(true);
m_actionLimitGroup->setChecked(config()->get(Config::SearchLimitGroup).toBool());
+ m_actionWaitForEnter = m_searchMenu->addAction(
+ tr("Press Enter to search"), this, [](bool state) { config()->set(Config::SearchWaitForEnter, state); });
+ m_actionWaitForEnter->setObjectName("actionSearchWaitForEnter");
+ m_actionWaitForEnter->setCheckable(true);
+ m_actionWaitForEnter->setChecked(config()->get(Config::SearchWaitForEnter).toBool());
+
m_ui->searchIcon->setIcon(icons()->icon("system-search"));
m_ui->searchEdit->addAction(m_ui->searchIcon, QLineEdit::LeadingPosition);
@@ -153,12 +160,12 @@ void SearchWidget::connectSignals(SignalMultiplexer& mx)
mx.connect(SIGNAL(entrySelectionChanged()), this, SLOT(resetSearchClearTimer()));
mx.connect(SIGNAL(currentModeChanged(DatabaseWidget::Mode)), this, SLOT(resetSearchClearTimer()));
mx.connect(SIGNAL(databaseUnlocked()), this, SLOT(focusSearch()));
- mx.connect(m_ui->searchEdit, SIGNAL(returnPressed()), SLOT(switchToEntryEdit()));
+ mx.connect(this, SIGNAL(enterPressed()), SLOT(switchToEntryEdit()));
}
void SearchWidget::databaseChanged(DatabaseWidget* dbWidget)
{
- if (dbWidget != nullptr) {
+ if (dbWidget) {
// Set current search text from this database
m_ui->searchEdit->setText(dbWidget->getCurrentSearch());
// Enforce search policy
@@ -171,18 +178,15 @@ void SearchWidget::databaseChanged(DatabaseWidget* dbWidget)
void SearchWidget::startSearchTimer()
{
- if (!m_searchTimer->isActive()) {
+ if (m_actionWaitForEnter->isChecked()) {
m_searchTimer->stop();
+ } else {
+ m_searchTimer->start(500);
}
- m_searchTimer->start(100);
}
void SearchWidget::startSearch()
{
- if (!m_searchTimer->isActive()) {
- m_searchTimer->stop();
- }
-
m_ui->saveIcon->setVisible(true);
search(m_ui->searchEdit->text());
}
@@ -200,18 +204,18 @@ void SearchWidget::updateCaseSensitive()
emit caseSensitiveChanged(m_actionCaseSensitive->isChecked());
}
-void SearchWidget::setCaseSensitive(bool state)
-{
- m_actionCaseSensitive->setChecked(state);
- updateCaseSensitive();
-}
-
void SearchWidget::updateLimitGroup()
{
config()->set(Config::SearchLimitGroup, m_actionLimitGroup->isChecked());
emit limitGroupChanged(m_actionLimitGroup->isChecked());
}
+void SearchWidget::setCaseSensitive(bool state)
+{
+ m_actionCaseSensitive->setChecked(state);
+ updateCaseSensitive();
+}
+
void SearchWidget::setLimitGroup(bool state)
{
m_actionLimitGroup->setChecked(state);
@@ -244,3 +248,12 @@ void SearchWidget::showSearchMenu()
{
m_searchMenu->exec(m_ui->searchEdit->mapToGlobal(m_ui->searchEdit->rect().bottomLeft()));
}
+
+void SearchWidget::onReturnPressed()
+{
+ if (m_actionWaitForEnter->isChecked()) {
+ emit search(m_ui->searchEdit->text());
+ } else {
+ emit enterPressed();
+ }
+}
diff --git a/src/gui/SearchWidget.h b/src/gui/SearchWidget.h
index 8d2c63394..1d048d12b 100644
--- a/src/gui/SearchWidget.h
+++ b/src/gui/SearchWidget.h
@@ -68,6 +68,7 @@ public slots:
void clearSearch();
private slots:
+ void onReturnPressed();
void startSearchTimer();
void startSearch();
void updateCaseSensitive();
@@ -83,6 +84,7 @@ private:
QTimer* m_clearSearchTimer;
QAction* m_actionCaseSensitive;
QAction* m_actionLimitGroup;
+ QAction* m_actionWaitForEnter;
QMenu* m_searchMenu;
};
diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp
index f711817d5..9011d445c 100644
--- a/tests/gui/TestGui.cpp
+++ b/tests/gui/TestGui.cpp
@@ -1126,6 +1126,7 @@ void TestGui::testSearch()
auto* searchWidget = toolBar->findChild("SearchWidget");
QVERIFY(searchWidget->isEnabled());
auto* searchTextEdit = searchWidget->findChild("searchEdit");
+ auto* waitForEnterAction = searchWidget->findChild("actionSearchWaitForEnter");
auto* entryView = m_dbWidget->findChild("entryView");
QVERIFY(entryView->isVisible());
@@ -1137,6 +1138,50 @@ void TestGui::testSearch()
QVERIFY(helpButton->isVisible());
QVERIFY(!helpPanel->isVisible());
+ // Test "wait for enter" toggle
+ QVERIFY(waitForEnterAction->isVisible());
+ QVERIFY(waitForEnterAction->isCheckable());
+
+ // Test search with "wait for enter" disabled (default)
+ searchTextEdit->clear();
+ QTest::keyClicks(searchTextEdit, "ZZZ");
+ QTRY_COMPARE(searchTextEdit->text(), QString("ZZZ"));
+ QTRY_VERIFY(m_dbWidget->isSearchActive());
+ QTRY_COMPARE(entryView->model()->rowCount(), 0);
+
+ // Clear search
+ searchTextEdit->clear();
+ QTRY_VERIFY(!m_dbWidget->isSearchActive());
+
+ // Enable "wait for enter" mode
+ waitForEnterAction->trigger();
+ QVERIFY(waitForEnterAction->isChecked());
+
+ // Test search with "wait for enter" enabled
+ QTest::keyClicks(searchTextEdit, "ZZZ");
+ QTRY_VERIFY(!m_dbWidget->isSearchActive());
+
+ // Press Enter to execute search
+ QTest::keyClick(searchTextEdit, Qt::Key_Return);
+ QTRY_VERIFY(m_dbWidget->isSearchActive());
+ QTRY_COMPARE(entryView->model()->rowCount(), 0);
+ // Check that search remains active even after clearing
+ searchTextEdit->clear();
+ QTRY_VERIFY(m_dbWidget->isSearchActive());
+
+ // Disable "wait for enter" mode
+ waitForEnterAction->trigger();
+ QVERIFY(!waitForEnterAction->isChecked());
+
+ // Test search with "wait for enter" disabled again
+ QTest::keyClicks(searchTextEdit, "ZZZ");
+ QTRY_VERIFY(m_dbWidget->isSearchActive());
+ QTRY_COMPARE(entryView->model()->rowCount(), 0);
+
+ // Clear search
+ searchTextEdit->clear();
+ QTRY_VERIFY(!m_dbWidget->isSearchActive());
+
// Enter search
QTest::mouseClick(searchTextEdit, Qt::LeftButton);
QTRY_VERIFY(searchTextEdit->hasFocus());