From 36df21d823173cb55b0f8e0afcfc19e4426b50a0 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Wed, 4 Jan 2017 20:46:52 -0500 Subject: [PATCH 1/5] Enhanced search ui keypress actions * Pressing down arrow will always focus on entry view * Pressing enter opens currently selected entry * Pressing CTRL+F focuses and selects search text * Rewrote test cases to cover the new functionality --- src/gui/SearchWidget.cpp | 21 +++++++++++---------- src/gui/SearchWidget.h | 2 ++ tests/gui/TestGui.cpp | 33 +++++++++++++++++++-------------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/gui/SearchWidget.cpp b/src/gui/SearchWidget.cpp index 5edf17cd..60adaf76 100644 --- a/src/gui/SearchWidget.cpp +++ b/src/gui/SearchWidget.cpp @@ -34,12 +34,11 @@ SearchWidget::SearchWidget(QWidget *parent) m_searchTimer->setSingleShot(true); connect(m_ui->searchEdit, SIGNAL(textChanged(QString)), SLOT(startSearchTimer())); - connect(m_ui->searchEdit, SIGNAL(returnPressed()), SLOT(startSearch())); connect(m_ui->searchIcon, SIGNAL(triggered(QAction*)), m_ui->searchEdit, SLOT(setFocus())); connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(startSearch())); connect(this, SIGNAL(escapePressed()), m_ui->searchEdit, SLOT(clear())); - new QShortcut(Qt::CTRL + Qt::Key_F, m_ui->searchEdit, SLOT(setFocus()), nullptr, Qt::ApplicationShortcut); + new QShortcut(Qt::CTRL + Qt::Key_F, this, SLOT(searchFocus()), nullptr, Qt::ApplicationShortcut); m_ui->searchEdit->installEventFilter(this); @@ -76,14 +75,9 @@ bool SearchWidget::eventFilter(QObject *obj, QEvent *event) } } else if (keyEvent->matches(QKeySequence::MoveToNextLine)) { - // If Down is pressed at EOL in the search edit, move - // the focus to the entry view. - QLineEdit* searchEdit = m_ui->searchEdit; - if (!searchEdit->hasSelectedText() && - searchEdit->cursorPosition() == searchEdit->text().length()) { - emit downPressed(); - return true; - } + // If Down is pressed move the focus to the entry view. + emit downPressed(); + return true; } } @@ -96,6 +90,7 @@ void SearchWidget::connectSignals(SignalMultiplexer& mx) mx.connect(this, SIGNAL(caseSensitiveChanged(bool)), SLOT(setSearchCaseSensitive(bool))); mx.connect(this, SIGNAL(copyPressed()), SLOT(copyPassword())); mx.connect(this, SIGNAL(downPressed()), SLOT(setFocus())); + mx.connect(m_ui->searchEdit, SIGNAL(returnPressed()), SLOT(switchToEntryEdit())); } void SearchWidget::databaseChanged(DatabaseWidget *dbWidget) @@ -138,3 +133,9 @@ void SearchWidget::setCaseSensitive(bool state) m_actionCaseSensitive->setChecked(state); updateCaseSensitive(); } + +void SearchWidget::searchFocus() +{ + m_ui->searchEdit->setFocus(); + m_ui->searchEdit->selectAll(); +} diff --git a/src/gui/SearchWidget.h b/src/gui/SearchWidget.h index 01f9e536..d2b94d97 100644 --- a/src/gui/SearchWidget.h +++ b/src/gui/SearchWidget.h @@ -48,6 +48,7 @@ signals: void escapePressed(); void copyPressed(); void downPressed(); + void enterPressed(); public slots: void databaseChanged(DatabaseWidget* dbWidget); @@ -56,6 +57,7 @@ private slots: void startSearchTimer(); void startSearch(); void updateCaseSensitive(); + void searchFocus(); private: const QScopedPointer m_ui; diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index babab8ab..45c1a271 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -413,19 +413,26 @@ void TestGui::testSearch() // Search for "someTHING" QTest::keyClicks(searchTextEdit, "THING"); QTRY_COMPARE(entryView->model()->rowCount(), 2); - // Press Down to focus on the entry view if at EOL + // Press Down to focus on the entry view QTest::keyClick(searchTextEdit, Qt::Key_Right, Qt::ControlModifier); QTRY_VERIFY(searchTextEdit->hasFocus()); QTest::keyClick(searchTextEdit, Qt::Key_Down); QTRY_VERIFY(entryView->hasFocus()); - // Test clipboard + // Restore focus and search text selection + QTest::keyClick(m_mainWindow, Qt::Key_F, Qt::ControlModifier); + QTRY_COMPARE(searchTextEdit->selectedText(), QString("someTHING")); + // Ensure Down focuses on entry view when search text is selected + QTest::keyClick(searchTextEdit, Qt::Key_Down); + QTRY_VERIFY(entryView->hasFocus()); + // Refocus back to search edit + QTest::mouseClick(searchTextEdit, Qt::LeftButton); + QTRY_VERIFY(searchTextEdit->hasFocus()); + // Test password copy QClipboard *clipboard = QApplication::clipboard(); - QTest::keyClick(entryView, Qt::Key_C, Qt::ControlModifier); + QTest::keyClick(searchTextEdit, Qt::Key_C, Qt::ControlModifier); QModelIndex searchedItem = entryView->model()->index(0, 1); Entry* searchedEntry = entryView->entryFromIndex(searchedItem); QTRY_COMPARE(searchedEntry->password(), clipboard->text()); - // Restore focus - QTest::mouseClick(searchTextEdit, Qt::LeftButton); // Test case sensitive search searchWidget->setCaseSensitive(true); @@ -445,16 +452,14 @@ void TestGui::testSearch() QCOMPARE(groupView->currentGroup(), m_db->rootGroup()); // Try to edit the first entry from the search view + // Refocus back to search edit + QTest::mouseClick(searchTextEdit, Qt::LeftButton); + QTRY_VERIFY(searchTextEdit->hasFocus()); + QVERIFY(m_dbWidget->isInSearchMode()); + QModelIndex item = entryView->model()->index(0, 1); Entry* entry = entryView->entryFromIndex(item); - QVERIFY(m_dbWidget->isInSearchMode()); - clickIndex(item, entryView, Qt::LeftButton); - QAction* entryEditAction = m_mainWindow->findChild("actionEntryEdit"); - QVERIFY(entryEditAction->isEnabled()); - QWidget* entryEditWidget = toolBar->widgetForAction(entryEditAction); - QVERIFY(entryEditWidget->isVisible()); - QVERIFY(entryEditWidget->isEnabled()); - QTest::mouseClick(entryEditWidget, Qt::LeftButton); + QTest::keyClick(searchTextEdit, Qt::Key_Return); QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::EditMode); // Perform the edit and save it @@ -465,7 +470,7 @@ void TestGui::testSearch() QDialogButtonBox* editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); - // Confirm the edit was made and we are back in view mode + // Confirm the edit was made and we are back in search mode QTRY_VERIFY(m_dbWidget->isInSearchMode()); QCOMPARE(entry->title(), origTitle.append("_edited")); From fd3fefd6f135878272abcb8e15c03fbaa784fbe4 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Fri, 13 Jan 2017 21:52:01 -0500 Subject: [PATCH 2/5] Use placeholder for search widget. --- src/gui/SearchWidget.ui | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/gui/SearchWidget.ui b/src/gui/SearchWidget.ui index 3959582c..102a13af 100644 --- a/src/gui/SearchWidget.ui +++ b/src/gui/SearchWidget.ui @@ -18,7 +18,7 @@ 0 - 0 + 6 0 @@ -38,17 +38,14 @@ - - - - Find: - - - - + + + Find: + + From 01464a78600cb730a8be4e4b89f1929bcd1cc60f Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 14 Jan 2017 20:27:34 -0500 Subject: [PATCH 3/5] Added clear text button, accurate down arrow behavior, and fixed sizing --- src/gui/SearchWidget.cpp | 18 ++++++++++----- src/gui/SearchWidget.ui | 50 +++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/gui/SearchWidget.cpp b/src/gui/SearchWidget.cpp index 60adaf76..023948d7 100644 --- a/src/gui/SearchWidget.cpp +++ b/src/gui/SearchWidget.cpp @@ -66,18 +66,24 @@ bool SearchWidget::eventFilter(QObject *obj, QEvent *event) return true; } else if (keyEvent->matches(QKeySequence::Copy)) { - // If Control+C is pressed in the search edit when no - // text is selected, copy the password of the current - // entry. + // If Control+C is pressed in the search edit when no text + // is selected, copy the password of the current entry if (!m_ui->searchEdit->hasSelectedText()) { emit copyPressed(); return true; } } else if (keyEvent->matches(QKeySequence::MoveToNextLine)) { - // If Down is pressed move the focus to the entry view. - emit downPressed(); - return true; + if (m_ui->searchEdit->cursorPosition() == m_ui->searchEdit->text().length()) { + // If down is pressed at EOL, move the focus to the entry view + emit downPressed(); + return true; + } + else { + // Otherwise move the cursor to EOL + m_ui->searchEdit->setCursorPosition(m_ui->searchEdit->text().length()); + return true; + } } } diff --git a/src/gui/SearchWidget.ui b/src/gui/SearchWidget.ui index 102a13af..281d5f85 100644 --- a/src/gui/SearchWidget.ui +++ b/src/gui/SearchWidget.ui @@ -10,40 +10,48 @@ 34 - + + + 0 + 0 + + + - 0 + 3 0 - 6 + 7 0 - - - - - - Qt::ClickFocus - - - Qt::ToolButtonIconOnly - - - true - - - - + + + + Qt::ClickFocus + + + Qt::ToolButtonIconOnly + + + true + + - + + + padding:3px + - Find: + Find + + + true From 39e0708b3bea597889e122a7679a375cb9ff794f Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 14 Jan 2017 21:41:18 -0500 Subject: [PATCH 4/5] Correcting missing icons when running release from build directory --- src/core/FilePath.cpp | 3 +++ src/gui/SearchWidget.ui | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/core/FilePath.cpp b/src/core/FilePath.cpp index 24c9e352..0506e3ab 100644 --- a/src/core/FilePath.cpp +++ b/src/core/FilePath.cpp @@ -211,6 +211,9 @@ FilePath::FilePath() else if (testSetDir(appDirPath + "/share")) { } #endif + // Last ditch test when running in the build directory (mainly for travis tests) + else if (testSetDir(QString(KEEPASSX_SOURCE_DIR) + "/share")) { + } if (m_dataPath.isEmpty()) { qWarning("FilePath::DataPath: can't find data dir"); diff --git a/src/gui/SearchWidget.ui b/src/gui/SearchWidget.ui index 281d5f85..a75642e1 100644 --- a/src/gui/SearchWidget.ui +++ b/src/gui/SearchWidget.ui @@ -34,6 +34,9 @@ Qt::ClickFocus + + Search + Qt::ToolButtonIconOnly From b6f754c29a7cf3a2365fea4487395a9f9741055c Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 14 Jan 2017 22:29:16 -0500 Subject: [PATCH 5/5] Changed built-in clear search button with custom one to fix pixelation --- src/gui/SearchWidget.cpp | 10 +++++++++- src/gui/SearchWidget.ui | 16 ++++++++++++++++ tests/gui/TestGui.cpp | 6 ++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/gui/SearchWidget.cpp b/src/gui/SearchWidget.cpp index 023948d7..4ac01b3f 100644 --- a/src/gui/SearchWidget.cpp +++ b/src/gui/SearchWidget.cpp @@ -34,7 +34,9 @@ SearchWidget::SearchWidget(QWidget *parent) m_searchTimer->setSingleShot(true); connect(m_ui->searchEdit, SIGNAL(textChanged(QString)), SLOT(startSearchTimer())); - connect(m_ui->searchIcon, SIGNAL(triggered(QAction*)), m_ui->searchEdit, SLOT(setFocus())); + connect(m_ui->searchIcon, SIGNAL(pressed()), m_ui->searchEdit, SLOT(setFocus())); + connect(m_ui->clearIcon, SIGNAL(pressed()), m_ui->searchEdit, SLOT(clear())); + connect(m_ui->clearIcon, SIGNAL(pressed()), m_ui->searchEdit, SLOT(setFocus())); connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(startSearch())); connect(this, SIGNAL(escapePressed()), m_ui->searchEdit, SLOT(clear())); @@ -50,6 +52,9 @@ SearchWidget::SearchWidget(QWidget *parent) m_ui->searchIcon->setIcon(filePath()->icon("actions", "system-search")); m_ui->searchIcon->setMenu(searchMenu); m_ui->searchIcon->setPopupMode(QToolButton::MenuButtonPopup); + + m_ui->clearIcon->setIcon(filePath()->icon("actions", "edit-clear-locationbar-rtl")); + m_ui->clearIcon->setEnabled(false); } SearchWidget::~SearchWidget() @@ -126,6 +131,9 @@ void SearchWidget::startSearch() m_searchTimer->stop(); } + bool hasText = m_ui->searchEdit->text().length() > 0; + m_ui->clearIcon->setEnabled(hasText); + search(m_ui->searchEdit->text()); } diff --git a/src/gui/SearchWidget.ui b/src/gui/SearchWidget.ui index a75642e1..46c2699f 100644 --- a/src/gui/SearchWidget.ui +++ b/src/gui/SearchWidget.ui @@ -54,6 +54,22 @@ Find + false + + + + + + + Qt::ClickFocus + + + Clear + + + Qt::ToolButtonIconOnly + + true diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 45c1a271..c23226a2 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -401,7 +401,13 @@ void TestGui::testSearch() QTRY_COMPARE(searchTextEdit->text(), QString("ZZZ")); QTRY_VERIFY(m_dbWidget->isInSearchMode()); QTRY_COMPARE(entryView->model()->rowCount(), 0); + // Press the search clear button + QToolButton* clearButton = searchWidget->findChild("clearIcon"); + QTest::mouseClick(clearButton, Qt::LeftButton); + QTRY_VERIFY(searchTextEdit->text().isEmpty()); + QTRY_VERIFY(searchTextEdit->hasFocus()); // Escape clears searchedit and retains focus + QTest::keyClicks(searchTextEdit, "ZZZ"); QTest::keyClick(searchTextEdit, Qt::Key_Escape); QTRY_VERIFY(searchTextEdit->text().isEmpty()); QTRY_VERIFY(searchTextEdit->hasFocus());