Add auto-save delay per database (#9100)

Add a new propery autosaveDelay in Metadata of the db.
The property is saved in customData to not affect database structure as this setting is unique to keepasxc.
The propery sets delay to wait since last modification before saving.

Co-authored-by: jNullj <jNullj@users.noreply.github.com>
This commit is contained in:
Jonathan White 2024-04-27 23:50:40 -04:00
parent 775efc65ed
commit bab48b42f7
No known key found for this signature in database
GPG key ID: 440FC65F2E0C6E01
10 changed files with 294 additions and 6 deletions

View file

@ -1469,6 +1469,10 @@ void TestGui::testDatabaseSettings()
auto* dbSettingsDialog = m_dbWidget->findChild<QWidget*>("databaseSettingsDialog");
auto* transformRoundsSpinBox = dbSettingsDialog->findChild<QSpinBox*>("transformRoundsSpinBox");
auto advancedToggle = dbSettingsDialog->findChild<QCheckBox*>("advancedSettingsToggle");
auto* autosaveDelayCheckBox = dbSettingsDialog->findChild<QCheckBox*>("autosaveDelayCheckBox");
auto* autosaveDelaySpinBox = dbSettingsDialog->findChild<QSpinBox*>("autosaveDelaySpinBox");
auto* dbSettingsButtonBox = dbSettingsDialog->findChild<QDialogButtonBox*>("buttonBox");
int autosaveDelayTestValue = 2;
advancedToggle->setChecked(true);
QApplication::processEvents();
@ -1478,7 +1482,136 @@ void TestGui::testDatabaseSettings()
QTest::keyClick(transformRoundsSpinBox, Qt::Key_Enter);
QTRY_COMPARE(m_db->kdf()->rounds(), 123456);
// test disable and default values for maximum history items and size
triggerAction("actionDatabaseSettings");
auto* historyMaxItemsCheckBox = dbSettingsDialog->findChild<QCheckBox*>("historyMaxItemsCheckBox");
auto* historyMaxItemsSpinBox = dbSettingsDialog->findChild<QSpinBox*>("historyMaxItemsSpinBox");
auto* historyMaxSizeCheckBox = dbSettingsDialog->findChild<QCheckBox*>("historyMaxSizeCheckBox");
auto* historyMaxSizeSpinBox = dbSettingsDialog->findChild<QSpinBox*>("historyMaxSizeSpinBox");
// test defaults
QCOMPARE(historyMaxItemsSpinBox->value(), Metadata::DefaultHistoryMaxItems);
QCOMPARE(historyMaxSizeSpinBox->value(), qRound(Metadata::DefaultHistoryMaxSize / qreal(1024 * 1024)));
// disable and test setting as well
historyMaxItemsCheckBox->setChecked(false);
historyMaxSizeCheckBox->setChecked(false);
QTest::mouseClick(dbSettingsButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
QTRY_COMPARE(m_db->metadata()->historyMaxItems(), -1);
QTRY_COMPARE(m_db->metadata()->historyMaxSize(), -1);
// then open to check the saved disabled state in gui
triggerAction("actionDatabaseSettings");
QCOMPARE(historyMaxItemsCheckBox->isChecked(), false);
QCOMPARE(historyMaxSizeCheckBox->isChecked(), false);
QTest::mouseClick(dbSettingsButtonBox->button(QDialogButtonBox::Cancel), Qt::LeftButton);
// Test loading default values and setting autosaveDelay
triggerAction("actionDatabaseSettings");
QVERIFY(autosaveDelayCheckBox->isChecked() == false);
autosaveDelayCheckBox->toggle();
autosaveDelaySpinBox->setValue(autosaveDelayTestValue);
QTest::mouseClick(dbSettingsButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
QTRY_COMPARE(m_db->metadata()->autosaveDelayMin(), autosaveDelayTestValue);
checkSaveDatabase();
// Test loading autosaveDelay non-default values
triggerAction("actionDatabaseSettings");
QTRY_COMPARE(autosaveDelayCheckBox->isChecked(), true);
QTRY_COMPARE(autosaveDelaySpinBox->value(), autosaveDelayTestValue);
QTest::mouseClick(dbSettingsButtonBox->button(QDialogButtonBox::Cancel), Qt::LeftButton);
// test autosave delay
// 1 init
config()->set(Config::AutoSaveAfterEveryChange, true);
QSignalSpy writeDbSignalSpy(m_db.data(), &Database::databaseSaved);
// 2 create new entries
// 2.a) Click the new entry button and set the title
auto* entryNewAction = m_mainWindow->findChild<QAction*>("actionEntryNew");
QVERIFY(entryNewAction->isEnabled());
auto* toolBar = m_mainWindow->findChild<QToolBar*>("toolBar");
QVERIFY(toolBar);
QWidget* entryNewWidget = toolBar->widgetForAction(entryNewAction);
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
auto* editEntryWidget = m_dbWidget->findChild<EditEntryWidget*>("editEntryWidget");
QVERIFY(editEntryWidget);
auto* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit");
QVERIFY(titleEdit);
QTest::keyClicks(titleEdit, "Test autosaveDelay 1");
// 2.b) Save changes
editEntryWidget->setCurrentPage(0);
auto* editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
// 2.c) Make sure file was not modified yet
Tools::wait(150); // due to modify timer
QTRY_COMPARE(writeDbSignalSpy.count(), 0);
// 2.d) Create second entry to test delay timer reset
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QTest::keyClicks(titleEdit, "Test autosaveDelay 2");
// 2.e) Save changes
editEntryWidget->setCurrentPage(0);
editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
// 3 Double check both true negative and true positive
// 3.a) Test unmodified prior to delay timeout
Tools::wait(150); // due to modify timer
QTRY_COMPARE(writeDbSignalSpy.count(), 0);
// 3.b) Test modification time after expected
m_dbWidget->triggerAutosaveTimer();
QTRY_COMPARE(writeDbSignalSpy.count(), 1);
// 4 Test no delay when disabled autosave or autosaveDelay
// 4.a) create new entry
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QTest::keyClicks(titleEdit, "Test autosaveDelay 3");
// 4.b) Save changes
editEntryWidget->setCurrentPage(0);
editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
// 4.c) Start timer
Tools::wait(150); // due to modify timer
// 4.d) Disable autosave
config()->set(Config::AutoSaveAfterEveryChange, false);
// 4.e) Make sure changes are not saved
m_dbWidget->triggerAutosaveTimer();
QTRY_COMPARE(writeDbSignalSpy.count(), 1);
// 4.f) Repeat for autosaveDelay
config()->set(Config::AutoSaveAfterEveryChange, true);
QTest::mouseClick(entryNewWidget, Qt::LeftButton);
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
QTest::keyClicks(titleEdit, "Test autosaveDelay 4");
editEntryWidget->setCurrentPage(0);
editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
Tools::wait(150); // due to modify timer
m_db->metadata()->setAutosaveDelayMin(0);
// 4.g) Make sure changes are not saved
m_dbWidget->triggerAutosaveTimer();
QTRY_COMPARE(writeDbSignalSpy.count(), 1);
// 5 Cleanup
config()->set(Config::AutoSaveAfterEveryChange, false);
}
void TestGui::testDatabaseLocking()