From 2836364e1a83c074b64b966bece288a41a40663b Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 19 Oct 2024 00:09:32 -0400 Subject: [PATCH] Fix assert hit when viewing entry history * Fixes #11371 * Adds test for showing entry history * Improved page switching capabilities for entry edit widget --- src/gui/DatabaseWidget.cpp | 3 +- src/gui/EditWidget.cpp | 15 ++++++++-- src/gui/EditWidget.h | 3 +- src/gui/entry/EditEntryWidget.cpp | 47 +++++++++++++++++++++++++++-- src/gui/entry/EditEntryWidget.h | 15 ++++++++++ tests/gui/TestGui.cpp | 50 +++++++++++++++++++++---------- 6 files changed, 110 insertions(+), 23 deletions(-) diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 76a15a376..6d648b689 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -179,6 +179,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) m_previewSplitter->setSizes({1, 1}); m_editEntryWidget->setObjectName("editEntryWidget"); + m_historyEditEntryWidget->setObjectName("editEntryHistoryWidget"); m_editGroupWidget->setObjectName("editGroupWidget"); m_reportsDialog->setObjectName("reportsDialog"); m_databaseSettingDialog->setObjectName("databaseSettingsDialog"); @@ -273,7 +274,7 @@ DatabaseWidget::Mode DatabaseWidget::currentMode() const mode = Mode::ReportsMode; } else if (widget == m_databaseSettingDialog) { mode = Mode::DatabaseSettingsMode; - } else if (widget == m_editEntryWidget) { + } else if (widget == m_editEntryWidget || widget == m_historyEditEntryWidget) { mode = Mode::EditEntryMode; } else if (widget == m_editGroupWidget) { mode = Mode::EditGroupMode; diff --git a/src/gui/EditWidget.cpp b/src/gui/EditWidget.cpp index e7e3555f2..9eb63810e 100644 --- a/src/gui/EditWidget.cpp +++ b/src/gui/EditWidget.cpp @@ -73,16 +73,25 @@ void EditWidget::addPage(const QString& labelText, const QIcon& icon, QWidget* w m_ui->categoryList->addCategory(labelText, icon); } -bool EditWidget::hasPage(QWidget* widget) +bool EditWidget::hasPage(const QWidget* widget) const { + return pageIndex(widget) >= 0; +} + +int EditWidget::pageIndex(const QWidget* widget) const +{ + if (!widget) { + return -1; + } + for (int i = 0; i < m_ui->stackedWidget->count(); i++) { auto* scrollArea = qobject_cast(m_ui->stackedWidget->widget(i)); if (scrollArea && scrollArea->widget() == widget) { - return true; + return i; } } - return false; + return -1; } void EditWidget::setPageHidden(QWidget* widget, bool hidden) diff --git a/src/gui/EditWidget.h b/src/gui/EditWidget.h index c4997abae..b1aaa9a95 100644 --- a/src/gui/EditWidget.h +++ b/src/gui/EditWidget.h @@ -42,7 +42,8 @@ public: ~EditWidget(); void addPage(const QString& labelText, const QIcon& icon, QWidget* widget); - bool hasPage(QWidget* widget); + bool hasPage(const QWidget* widget) const; + int pageIndex(const QWidget* widget) const; void setPageHidden(QWidget* widget, bool hidden); void setCurrentPage(int index); void setHeadline(const QString& text); diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 13cf7ae11..fc6404902 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -140,6 +140,47 @@ EditEntryWidget::~EditEntryWidget() { } +bool EditEntryWidget::switchToPage(Page page) +{ + auto index = pageIndex(widgetForPage(page)); + if (index >= 0) { + setCurrentPage(index); + return true; + } + return false; +} + +QWidget* EditEntryWidget::widgetForPage(Page page) const +{ + switch (page) { + case Page::Main: + return m_mainWidget; + case Page::Advanced: + return m_advancedWidget; + case Page::Icon: + return m_iconsWidget; + case Page::AutoType: + return m_autoTypeWidget; + case Page::Browser: +#ifdef WITH_XC_BROWSER + return m_browserWidget; +#else + return nullptr; +#endif + case Page::SSHAgent: +#ifdef WITH_XC_SSHAGENT + return m_sshAgentWidget; +#else + return nullptr; +#endif + case Page::Properties: + return m_editWidgetProperties; + case Page::History: + return m_historyWidget; + } + return nullptr; +} + void EditEntryWidget::setupMain() { m_mainUi->setupUi(m_mainWidget); @@ -847,7 +888,7 @@ void EditEntryWidget::loadEntry(Entry* entry, setForms(entry); setReadOnly(m_history); - setCurrentPage(0); + switchToPage(Page::Main); setPageHidden(m_historyWidget, m_history || m_entry->historyItems().count() < 1); #ifdef WITH_XC_SSHAGENT setPageHidden(m_sshAgentWidget, !sshAgent()->isEnabled()); @@ -1092,7 +1133,7 @@ bool EditEntryWidget::commitEntry() MessageBox::Yes | MessageBox::No, MessageBox::Yes); if (res == MessageBox::Yes) { - setCurrentPage(3); + switchToPage(Page::AutoType); return false; } } @@ -1107,7 +1148,7 @@ bool EditEntryWidget::commitEntry() MessageBox::Yes | MessageBox::No, MessageBox::Yes); if (res == MessageBox::Yes) { - setCurrentPage(3); + switchToPage(Page::AutoType); return false; } } diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index fddf64eda..45913e55a 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -77,6 +77,19 @@ public: Entry* currentEntry() const; void clear(); + enum class Page + { + Main, + Advanced, + Icon, + AutoType, + Browser, + SSHAgent, + Properties, + History + }; + bool switchToPage(Page page); + signals: void editFinished(bool accepted); void historyEntryActivated(Entry* entry); @@ -162,6 +175,8 @@ private: void displayAttribute(QModelIndex index, bool showProtected); + QWidget* widgetForPage(Page page) const; + QPointer m_entry; QSharedPointer m_db; diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index dc10dd0b8..7f100cc5c 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -471,8 +471,28 @@ void TestGui::testEditEntry() QCOMPARE(entry->historyItems().size(), ++editCount); QVERIFY(!applyButton->isEnabled()); + // Test viewing entry history + auto historyView = editEntryWidget->findChild("historyView"); + auto showButton = editEntryWidget->findChild("showButton"); + QVERIFY(historyView); + editEntryWidget->switchToPage(EditEntryWidget::Page::History); + QApplication::processEvents(); + QVERIFY(historyView->isVisible()); + QVERIFY(!showButton->isEnabled()); + // Select the second row in the history view + historyView->setCurrentIndex(historyView->model()->index(1, 0)); + QVERIFY(showButton->isEnabled()); + QTest::mouseClick(showButton, Qt::LeftButton); + // Verify that the entry history widget is shown + auto entryHistoryWidget = m_dbWidget->findChild("editEntryHistoryWidget"); + QVERIFY(entryHistoryWidget); + QVERIFY(entryHistoryWidget->isVisible()); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); + QTest::keyClick(entryHistoryWidget, Qt::Key_Escape); + QVERIFY(historyView->isVisible()); + // Test the "known bad" checkbox - editEntryWidget->setCurrentPage(1); + editEntryWidget->switchToPage(EditEntryWidget::Page::Advanced); auto excludeReportsCheckBox = editEntryWidget->findChild("excludeReportsCheckBox"); QVERIFY(excludeReportsCheckBox); QCOMPARE(excludeReportsCheckBox->isChecked(), false); @@ -495,7 +515,7 @@ void TestGui::testEditEntry() QCOMPARE(tags->tags().last(), QString("tag 2_is!awesome")); // Test entry colors (simulate choosing a color) - editEntryWidget->setCurrentPage(1); + editEntryWidget->switchToPage(EditEntryWidget::Page::Advanced); auto fgColor = QString("#FF0000"); auto bgColor = QString("#0000FF"); // Set foreground color @@ -512,7 +532,7 @@ void TestGui::testEditEntry() QCOMPARE(entry->historyItems().size(), ++editCount); // Test protected attributes - editEntryWidget->setCurrentPage(1); + editEntryWidget->switchToPage(EditEntryWidget::Page::Advanced); auto* attrTextEdit = editEntryWidget->findChild("attributesEdit"); QTest::mouseClick(editEntryWidget->findChild("addAttributeButton"), Qt::LeftButton); QString attrText = "TEST TEXT"; @@ -522,7 +542,7 @@ void TestGui::testEditEntry() QVERIFY(attrTextEdit->toPlainText().contains("PROTECTED")); QTest::mouseClick(editEntryWidget->findChild("revealAttributeButton"), Qt::LeftButton); QCOMPARE(attrTextEdit->toPlainText(), attrText); - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); // Save the edit (press OK) QTest::mouseClick(okButton, Qt::LeftButton); @@ -901,7 +921,7 @@ void TestGui::testTotp() QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); - editEntryWidget->setCurrentPage(1); + editEntryWidget->switchToPage(EditEntryWidget::Page::Advanced); auto* attrTextEdit = editEntryWidget->findChild("attributesEdit"); QTest::mouseClick(editEntryWidget->findChild("revealAttributeButton"), Qt::LeftButton); QCOMPARE(attrTextEdit->toPlainText(), expectedFinalSeed); @@ -1623,7 +1643,7 @@ void TestGui::testDatabaseSettings() QTest::keyClicks(titleEdit, "Test autosaveDelay 1"); // 2.b) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); auto* editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); @@ -1637,7 +1657,7 @@ void TestGui::testDatabaseSettings() QTest::keyClicks(titleEdit, "Test autosaveDelay 2"); // 2.e) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); @@ -1657,7 +1677,7 @@ void TestGui::testDatabaseSettings() QTest::keyClicks(titleEdit, "Test autosaveDelay 3"); // 4.b) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); @@ -1676,7 +1696,7 @@ void TestGui::testDatabaseSettings() QTest::mouseClick(entryNewWidget, Qt::LeftButton); QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditEntryMode); QTest::keyClicks(titleEdit, "Test autosaveDelay 4"); - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); Tools::wait(150); // due to modify timer @@ -1922,7 +1942,7 @@ void TestGui::testAutoType() QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); // 1.b) Uncheck Auto-Type checkbox - editEntryWidget->setCurrentPage(3); + editEntryWidget->switchToPage(EditEntryWidget::Page::AutoType); auto* enableAutoTypeButton = editEntryWidget->findChild("enableButton"); QVERIFY(enableAutoTypeButton); QVERIFY(enableAutoTypeButton->isVisible()); @@ -1932,7 +1952,7 @@ void TestGui::testAutoType() QVERIFY(!enableAutoTypeButton->isChecked()); // 1.c) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); auto* editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); @@ -1946,13 +1966,13 @@ void TestGui::testAutoType() QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); // 2.b) Confirm AutoType is enabled and default - editEntryWidget->setCurrentPage(3); + editEntryWidget->switchToPage(EditEntryWidget::Page::AutoType); QVERIFY(enableAutoTypeButton->isChecked()); auto* inheritSequenceButton = editEntryWidget->findChild("inheritSequenceButton"); QVERIFY(inheritSequenceButton->isChecked()); // 2.c) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); // 3. Create an entry with custom Auto-Type sequence @@ -1965,7 +1985,7 @@ void TestGui::testAutoType() QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); // 3.b) Confirm AutoType is enabled and set custom sequence - editEntryWidget->setCurrentPage(3); + editEntryWidget->switchToPage(EditEntryWidget::Page::AutoType); QVERIFY(enableAutoTypeButton->isChecked()); auto* customSequenceButton = editEntryWidget->findChild("customSequenceButton"); QTest::mouseClick(customSequenceButton, Qt::LeftButton); @@ -1978,7 +1998,7 @@ void TestGui::testAutoType() QTest::keyClicks(sequenceEdit, "{USERNAME}{TAB}{TAB}{PASSWORD}{ENTER}"); // 3.c) Save changes - editEntryWidget->setCurrentPage(0); + editEntryWidget->switchToPage(EditEntryWidget::Page::Main); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); QApplication::processEvents();