mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-08-07 22:12:59 -04:00
Add "press enter to search" option (#12263)
* Also increase auto-search timeout to 500 ms to improve user experience, especially with large databases. The previous value of 100ms guaranteed a search was performed after every character entered, even when typing relatively fast. --------- Co-authored-by: Jonathan White <support@dmapps.us>
This commit is contained in:
parent
76b2f377df
commit
7ec0f1f5a8
5 changed files with 79 additions and 14 deletions
|
@ -9955,6 +9955,10 @@ This option is deprecated, use --set-key-file instead.</source>
|
|||
<source>Limit search to selected group</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Press Enter to search</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsClientModel</name>
|
||||
|
|
|
@ -98,6 +98,7 @@ public:
|
|||
GUI_CompactMode,
|
||||
GUI_CheckForUpdates,
|
||||
GUI_CheckForUpdatesIncludeBetas,
|
||||
SearchWaitForEnter,
|
||||
GUI_ShowExpiredEntriesOnDatabaseUnlock,
|
||||
GUI_ShowExpiredEntriesOnDatabaseUnlockOffsetDays,
|
||||
GUI_FontSizeOffset,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -1126,6 +1126,7 @@ void TestGui::testSearch()
|
|||
auto* searchWidget = toolBar->findChild<SearchWidget*>("SearchWidget");
|
||||
QVERIFY(searchWidget->isEnabled());
|
||||
auto* searchTextEdit = searchWidget->findChild<QLineEdit*>("searchEdit");
|
||||
auto* waitForEnterAction = searchWidget->findChild<QAction*>("actionSearchWaitForEnter");
|
||||
|
||||
auto* entryView = m_dbWidget->findChild<EntryView*>("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());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue