mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-25 22:16:01 -05:00
Prevent crash when all entries are deleted from a group
* Fix #4093 - The first entry in the list is selected after deleting an entry * Prevents crashes due to dangling pointers held by the Entry Preview Widget when entries were deleted. * Improve GUI tests to ensure this new behavior occurs.
This commit is contained in:
parent
6cde2b83e8
commit
0d3eb047c7
@ -154,6 +154,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent)
|
|||||||
m_shareLabel->setVisible(false);
|
m_shareLabel->setVisible(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_previewView->setObjectName("previewWidget");
|
||||||
m_previewView->hide();
|
m_previewView->hide();
|
||||||
m_previewSplitter->addWidget(m_entryView);
|
m_previewSplitter->addWidget(m_entryView);
|
||||||
m_previewSplitter->addWidget(m_previewView);
|
m_previewSplitter->addWidget(m_previewView);
|
||||||
@ -552,6 +553,14 @@ void DatabaseWidget::deleteEntries(QList<Entry*> selectedEntries)
|
|||||||
}
|
}
|
||||||
|
|
||||||
refreshSearch();
|
refreshSearch();
|
||||||
|
|
||||||
|
m_entryView->setFirstEntryActive();
|
||||||
|
auto* currentEntry = currentSelectedEntry();
|
||||||
|
if (currentEntry) {
|
||||||
|
m_previewView->setEntry(currentEntry);
|
||||||
|
} else {
|
||||||
|
m_previewView->setGroup(groupView()->currentGroup());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DatabaseWidget::confirmDeleteEntries(QList<Entry*> entries, bool permanent)
|
bool DatabaseWidget::confirmDeleteEntries(QList<Entry*> entries, bool permanent)
|
||||||
|
@ -145,10 +145,12 @@ void EntryPreviewWidget::setDatabaseMode(DatabaseWidget::Mode mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == DatabaseWidget::Mode::ViewMode) {
|
if (mode == DatabaseWidget::Mode::ViewMode) {
|
||||||
if (m_ui->stackedWidget->currentWidget() == m_ui->pageGroup) {
|
if (m_currentGroup && m_ui->stackedWidget->currentWidget() == m_ui->pageGroup) {
|
||||||
setGroup(m_currentGroup);
|
setGroup(m_currentGroup);
|
||||||
} else {
|
} else if (m_currentEntry) {
|
||||||
setEntry(m_currentEntry);
|
setEntry(m_currentEntry);
|
||||||
|
} else {
|
||||||
|
hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,8 +77,8 @@ private:
|
|||||||
|
|
||||||
const QScopedPointer<Ui::EntryPreviewWidget> m_ui;
|
const QScopedPointer<Ui::EntryPreviewWidget> m_ui;
|
||||||
bool m_locked;
|
bool m_locked;
|
||||||
Entry* m_currentEntry;
|
QPointer<Entry> m_currentEntry;
|
||||||
Group* m_currentGroup;
|
QPointer<Group> m_currentGroup;
|
||||||
QTimer m_totpTimer;
|
QTimer m_totpTimer;
|
||||||
quint8 m_selectedTabEntry;
|
quint8 m_selectedTabEntry;
|
||||||
quint8 m_selectedTabGroup;
|
quint8 m_selectedTabGroup;
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include "gui/CloneDialog.h"
|
#include "gui/CloneDialog.h"
|
||||||
#include "gui/DatabaseTabWidget.h"
|
#include "gui/DatabaseTabWidget.h"
|
||||||
#include "gui/DatabaseWidget.h"
|
#include "gui/DatabaseWidget.h"
|
||||||
|
#include "gui/EntryPreviewWidget.h"
|
||||||
#include "gui/FileDialog.h"
|
#include "gui/FileDialog.h"
|
||||||
#include "gui/MessageBox.h"
|
#include "gui/MessageBox.h"
|
||||||
#include "gui/PasswordEdit.h"
|
#include "gui/PasswordEdit.h"
|
||||||
@ -967,6 +968,7 @@ void TestGui::testDeleteEntry()
|
|||||||
QWidget* entryDeleteWidget = toolBar->widgetForAction(entryDeleteAction);
|
QWidget* entryDeleteWidget = toolBar->widgetForAction(entryDeleteAction);
|
||||||
entryView->setFocus();
|
entryView->setFocus();
|
||||||
|
|
||||||
|
// Move one entry to the recycling bin
|
||||||
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::ViewMode);
|
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::ViewMode);
|
||||||
clickIndex(entryView->model()->index(1, 1), entryView, Qt::LeftButton);
|
clickIndex(entryView->model()->index(1, 1), entryView, Qt::LeftButton);
|
||||||
QVERIFY(entryDeleteWidget->isVisible());
|
QVERIFY(entryDeleteWidget->isVisible());
|
||||||
@ -979,6 +981,7 @@ void TestGui::testDeleteEntry()
|
|||||||
QCOMPARE(entryView->model()->rowCount(), 3);
|
QCOMPARE(entryView->model()->rowCount(), 3);
|
||||||
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 1);
|
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 1);
|
||||||
|
|
||||||
|
// Select multiple entries and move them to the recycling bin
|
||||||
clickIndex(entryView->model()->index(1, 1), entryView, Qt::LeftButton);
|
clickIndex(entryView->model()->index(1, 1), entryView, Qt::LeftButton);
|
||||||
clickIndex(entryView->model()->index(2, 1), entryView, Qt::LeftButton, Qt::ControlModifier);
|
clickIndex(entryView->model()->index(2, 1), entryView, Qt::LeftButton, Qt::ControlModifier);
|
||||||
QCOMPARE(entryView->selectionModel()->selectedRows().size(), 2);
|
QCOMPARE(entryView->selectionModel()->selectedRows().size(), 2);
|
||||||
@ -993,6 +996,7 @@ void TestGui::testDeleteEntry()
|
|||||||
QCOMPARE(entryView->model()->rowCount(), 1);
|
QCOMPARE(entryView->model()->rowCount(), 1);
|
||||||
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 3);
|
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 3);
|
||||||
|
|
||||||
|
// Go to the recycling bin
|
||||||
QCOMPARE(groupView->currentGroup(), m_db->rootGroup());
|
QCOMPARE(groupView->currentGroup(), m_db->rootGroup());
|
||||||
QModelIndex rootGroupIndex = groupView->model()->index(0, 0);
|
QModelIndex rootGroupIndex = groupView->model()->index(0, 0);
|
||||||
clickIndex(groupView->model()->index(groupView->model()->rowCount(rootGroupIndex) - 1, 0, rootGroupIndex),
|
clickIndex(groupView->model()->index(groupView->model()->rowCount(rootGroupIndex) - 1, 0, rootGroupIndex),
|
||||||
@ -1000,6 +1004,7 @@ void TestGui::testDeleteEntry()
|
|||||||
Qt::LeftButton);
|
Qt::LeftButton);
|
||||||
QCOMPARE(groupView->currentGroup()->name(), m_db->metadata()->recycleBin()->name());
|
QCOMPARE(groupView->currentGroup()->name(), m_db->metadata()->recycleBin()->name());
|
||||||
|
|
||||||
|
// Delete one entry from the bin
|
||||||
clickIndex(entryView->model()->index(0, 1), entryView, Qt::LeftButton);
|
clickIndex(entryView->model()->index(0, 1), entryView, Qt::LeftButton);
|
||||||
MessageBox::setNextAnswer(MessageBox::Cancel);
|
MessageBox::setNextAnswer(MessageBox::Cancel);
|
||||||
QTest::mouseClick(entryDeleteWidget, Qt::LeftButton);
|
QTest::mouseClick(entryDeleteWidget, Qt::LeftButton);
|
||||||
@ -1011,6 +1016,7 @@ void TestGui::testDeleteEntry()
|
|||||||
QCOMPARE(entryView->model()->rowCount(), 2);
|
QCOMPARE(entryView->model()->rowCount(), 2);
|
||||||
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 2);
|
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 2);
|
||||||
|
|
||||||
|
// Select the remaining entries and delete them
|
||||||
clickIndex(entryView->model()->index(0, 1), entryView, Qt::LeftButton);
|
clickIndex(entryView->model()->index(0, 1), entryView, Qt::LeftButton);
|
||||||
clickIndex(entryView->model()->index(1, 1), entryView, Qt::LeftButton, Qt::ControlModifier);
|
clickIndex(entryView->model()->index(1, 1), entryView, Qt::LeftButton, Qt::ControlModifier);
|
||||||
MessageBox::setNextAnswer(MessageBox::Delete);
|
MessageBox::setNextAnswer(MessageBox::Delete);
|
||||||
@ -1018,6 +1024,16 @@ void TestGui::testDeleteEntry()
|
|||||||
QCOMPARE(entryView->model()->rowCount(), 0);
|
QCOMPARE(entryView->model()->rowCount(), 0);
|
||||||
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 0);
|
QCOMPARE(m_db->metadata()->recycleBin()->entries().size(), 0);
|
||||||
|
|
||||||
|
// Ensure the entry preview widget shows the recycling group since all entries are deleted
|
||||||
|
auto* previewWidget = m_dbWidget->findChild<EntryPreviewWidget*>("previewWidget");
|
||||||
|
QVERIFY(previewWidget);
|
||||||
|
auto* groupTitleLabel = previewWidget->findChild<QLabel*>("groupTitleLabel");
|
||||||
|
QVERIFY(groupTitleLabel);
|
||||||
|
|
||||||
|
QTRY_VERIFY(groupTitleLabel->isVisible());
|
||||||
|
QVERIFY(groupTitleLabel->text().contains(m_db->metadata()->recycleBin()->name()));
|
||||||
|
|
||||||
|
// Go back to the root group
|
||||||
clickIndex(groupView->model()->index(0, 0), groupView, Qt::LeftButton);
|
clickIndex(groupView->model()->index(0, 0), groupView, Qt::LeftButton);
|
||||||
QCOMPARE(groupView->currentGroup(), m_db->rootGroup());
|
QCOMPARE(groupView->currentGroup(), m_db->rootGroup());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user