From d7f408e4553c8d0e36de519b418b15d61132b487 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sun, 14 Jan 2018 18:04:33 -0500 Subject: [PATCH 1/4] Correct saving files to DropBox/Drive/OneDrive * Replaces QSaveFile with QTemporaryFile * Added backup before save config setting * This method may cause data loss (see comments) --- src/core/Config.cpp | 1 + src/core/Database.cpp | 46 +++++++++++++++++++++++--------- src/core/Database.h | 2 +- src/gui/DatabaseTabWidget.cpp | 4 ++- src/gui/SettingsWidget.cpp | 2 ++ src/gui/SettingsWidgetGeneral.ui | 7 +++++ 6 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/core/Config.cpp b/src/core/Config.cpp index fafb3cfd..3f49bafe 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -114,6 +114,7 @@ void Config::init(const QString& fileName) m_defaults.insert("AutoSaveAfterEveryChange", false); m_defaults.insert("AutoReloadOnChange", true); m_defaults.insert("AutoSaveOnExit", false); + m_defaults.insert("BackupBeforeSave", false); m_defaults.insert("SearchLimitGroup", false); m_defaults.insert("MinimizeOnCopy", false); m_defaults.insert("UseGroupIconOnEntryCreation", false); diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 75b91a5c..c65c566f 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -19,7 +19,7 @@ #include "Database.h" #include -#include +#include #include #include #include @@ -470,30 +470,52 @@ Database* Database::unlockFromStdin(QString databaseFilename, QString keyFilenam return Database::openDatabaseFile(databaseFilename, compositeKey); } -QString Database::saveToFile(QString filePath) +/** + * Save the database to a file. + * + * This function uses QTemporaryFile instead of QSaveFile due to a bug + * in Qt (https://bugreports.qt.io/browse/QTBUG-57299) that may prevent + * the QSaveFile from renaming itself when using DropBox, Drive, or OneDrive. + * + * The risk in using QTemporaryFile is that the rename function is not atomic + * and may result in loss of data if there is a crash or power loss at the + * wrong moment. + * + * @param filePath Absolute path of the file to save + * @param keepOld Rename the original database file instead of deleting + * @return error string, if any + */ +QString Database::saveToFile(QString filePath, bool keepOld) { KeePass2Writer writer; - QSaveFile saveFile(filePath); - if (saveFile.open(QIODevice::WriteOnly)) { - + QTemporaryFile saveFile; + if (saveFile.open()) { // write the database to the file setEmitModified(false); writer.writeDatabase(&saveFile, this); setEmitModified(true); if (writer.hasError()) { + // the writer failed return writer.errorString(); } - if (saveFile.commit()) { - // successfully saved database file - return QString(); - } else { - return saveFile.errorString(); + saveFile.close(); // flush to disk + + if (keepOld) { + QFile::remove(filePath + ".old"); + QFile::rename(filePath, filePath + ".old"); + } + + QFile::remove(filePath); + if (saveFile.rename(filePath)) { + // successfully saved database file + saveFile.setAutoRemove(false); + return {}; } - } else { - return saveFile.errorString(); } + + return saveFile.errorString(); } QSharedPointer Database::kdf() const diff --git a/src/core/Database.h b/src/core/Database.h index 3bf43f62..31d19087 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -111,7 +111,7 @@ public: void emptyRecycleBin(); void setEmitModified(bool value); void merge(const Database* other); - QString saveToFile(QString filePath); + QString saveToFile(QString filePath, bool keepOld = false); /** * Returns a unique id that is only valid as long as the Database exists. diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index c00a67d0..06ff84ed 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -28,6 +28,7 @@ #include "core/Database.h" #include "core/Group.h" #include "core/Metadata.h" +#include "core/AsyncTask.h" #include "format/CsvExporter.h" #include "gui/Clipboard.h" #include "gui/DatabaseWidget.h" @@ -322,7 +323,8 @@ bool DatabaseTabWidget::saveDatabase(Database* db, QString filePath) } dbStruct.dbWidget->blockAutoReload(true); - QString errorMessage = db->saveToFile(filePath); + // TODO: Make this async, but lock out the database widget to prevent re-entrance + QString errorMessage = db->saveToFile(filePath, config()->get("BackupBeforeSave").toBool()); dbStruct.dbWidget->blockAutoReload(false); if (errorMessage.isEmpty()) { diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index 7d3f65f8..12c97088 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -117,6 +117,7 @@ void SettingsWidget::loadSettings() config()->get("OpenPreviousDatabasesOnStartup").toBool()); m_generalUi->autoSaveAfterEveryChangeCheckBox->setChecked(config()->get("AutoSaveAfterEveryChange").toBool()); m_generalUi->autoSaveOnExitCheckBox->setChecked(config()->get("AutoSaveOnExit").toBool()); + m_generalUi->backupBeforeSaveCheckBox->setChecked(config()->get("BackupBeforeSave").toBool()); m_generalUi->autoReloadOnChangeCheckBox->setChecked(config()->get("AutoReloadOnChange").toBool()); m_generalUi->minimizeOnCopyCheckBox->setChecked(config()->get("MinimizeOnCopy").toBool()); m_generalUi->useGroupIconOnEntryCreationCheckBox->setChecked(config()->get("UseGroupIconOnEntryCreation").toBool()); @@ -193,6 +194,7 @@ void SettingsWidget::saveSettings() config()->set("AutoSaveAfterEveryChange", m_generalUi->autoSaveAfterEveryChangeCheckBox->isChecked()); config()->set("AutoSaveOnExit", m_generalUi->autoSaveOnExitCheckBox->isChecked()); + config()->set("BackupBeforeSave", m_generalUi->backupBeforeSaveCheckBox->isChecked()); config()->set("AutoReloadOnChange", m_generalUi->autoReloadOnChangeCheckBox->isChecked()); config()->set("MinimizeOnCopy", m_generalUi->minimizeOnCopyCheckBox->isChecked()); config()->set("UseGroupIconOnEntryCreation", diff --git a/src/gui/SettingsWidgetGeneral.ui b/src/gui/SettingsWidgetGeneral.ui index 87af235d..a80c8c2f 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -84,6 +84,13 @@ + + + + Backup database file before saving + + + From 3db9a86a4c89151dd0eb0f8929e0a0a8b9ff6af8 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Wed, 17 Jan 2018 20:13:13 -0500 Subject: [PATCH 2/4] After 3 failed saves, offer to disable safe saves * User is prompted to disable safe saves after three failed attempts * Completely retooled basic settings to group settings logically * Added setting for "atomic saves" --- src/core/Config.cpp | 1 + src/core/Database.cpp | 107 ++++-- src/core/Database.h | 5 +- src/gui/DatabaseTabWidget.cpp | 21 +- src/gui/DatabaseTabWidget.h | 1 + src/gui/SettingsWidget.cpp | 2 + src/gui/SettingsWidgetGeneral.ui | 538 ++++++++++++++++--------------- 7 files changed, 384 insertions(+), 291 deletions(-) diff --git a/src/core/Config.cpp b/src/core/Config.cpp index 3f49bafe..328dfaed 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -115,6 +115,7 @@ void Config::init(const QString& fileName) m_defaults.insert("AutoReloadOnChange", true); m_defaults.insert("AutoSaveOnExit", false); m_defaults.insert("BackupBeforeSave", false); + m_defaults.insert("UseAtomicSaves", true); m_defaults.insert("SearchLimitGroup", false); m_defaults.insert("MinimizeOnCopy", false); m_defaults.insert("UseGroupIconOnEntryCreation", false); diff --git a/src/core/Database.cpp b/src/core/Database.cpp index c65c566f..9a1fe0b3 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -19,6 +19,7 @@ #include "Database.h" #include +#include #include #include #include @@ -482,40 +483,92 @@ Database* Database::unlockFromStdin(QString databaseFilename, QString keyFilenam * wrong moment. * * @param filePath Absolute path of the file to save - * @param keepOld Rename the original database file instead of deleting + * @param atomic Use atomic file transactions + * @param backup Backup the existing database file, if exists * @return error string, if any */ -QString Database::saveToFile(QString filePath, bool keepOld) +QString Database::saveToFile(QString filePath, bool atomic, bool backup) +{ + QString error; + if (atomic) { + QSaveFile saveFile(filePath); + if (saveFile.open(QIODevice::WriteOnly)) { + // write the database to the file + error = writeDatabase(&saveFile); + if (!error.isEmpty()) { + return error; + } + + if (backup) { + backupDatabase(filePath); + } + + if (saveFile.commit()) { + // successfully saved database file + return {}; + } + } + error = saveFile.errorString(); + } else { + QTemporaryFile tempFile; + if (tempFile.open()) { + // write the database to the file + error = writeDatabase(&tempFile); + if (!error.isEmpty()) { + return error; + } + + tempFile.close(); // flush to disk + + if (backup) { + backupDatabase(filePath); + } + + // Delete the original db and move the temp file in place + QFile::remove(filePath); + if (tempFile.rename(filePath)) { + // successfully saved database file + tempFile.setAutoRemove(false); + return {}; + } + } + error = tempFile.errorString(); + } + // Saving failed + return error; +} + +QString Database::writeDatabase(QIODevice* device) { KeePass2Writer writer; - QTemporaryFile saveFile; - if (saveFile.open()) { - // write the database to the file - setEmitModified(false); - writer.writeDatabase(&saveFile, this); - setEmitModified(true); + setEmitModified(false); + writer.writeDatabase(device, this); + setEmitModified(true); - if (writer.hasError()) { - // the writer failed - return writer.errorString(); - } - - saveFile.close(); // flush to disk - - if (keepOld) { - QFile::remove(filePath + ".old"); - QFile::rename(filePath, filePath + ".old"); - } - - QFile::remove(filePath); - if (saveFile.rename(filePath)) { - // successfully saved database file - saveFile.setAutoRemove(false); - return {}; - } + if (writer.hasError()) { + // the writer failed + return writer.errorString(); } + return {}; +} - return saveFile.errorString(); +/** + * Remove the old backup and replace it with a new one + * backups are named .old.kdbx4 + * + * @param filePath Path to the file to backup + * @return + */ +bool Database::backupDatabase(QString filePath) +{ + QString backupFilePath = filePath; + backupFilePath.replace(".kdbx", ".old.kdbx", Qt::CaseInsensitive); + if (!backupFilePath.endsWith(".old.kdbx")) { + // Fallback in case of poorly named file + backupFilePath = filePath + ".old"; + } + QFile::remove(backupFilePath); + return QFile::copy(filePath, backupFilePath); } QSharedPointer Database::kdf() const diff --git a/src/core/Database.h b/src/core/Database.h index 31d19087..384ca814 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -32,6 +32,7 @@ enum class EntryReferenceType; class Group; class Metadata; class QTimer; +class QIODevice; struct DeletedObject { @@ -111,7 +112,7 @@ public: void emptyRecycleBin(); void setEmitModified(bool value); void merge(const Database* other); - QString saveToFile(QString filePath, bool keepOld = false); + QString saveToFile(QString filePath, bool atomic = true, bool backup = false); /** * Returns a unique id that is only valid as long as the Database exists. @@ -144,6 +145,8 @@ private: Group* findGroupRecursive(const Uuid& uuid, Group* group); void createRecycleBin(); + QString writeDatabase(QIODevice* device); + bool backupDatabase(QString filePath); Metadata* const m_metadata; Group* m_rootGroup; diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 06ff84ed..1765a9cd 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -44,6 +44,7 @@ DatabaseManagerStruct::DatabaseManagerStruct() : dbWidget(nullptr) , modified(false) , readOnly(false) + , saveAttempts(0) { } @@ -324,12 +325,14 @@ bool DatabaseTabWidget::saveDatabase(Database* db, QString filePath) dbStruct.dbWidget->blockAutoReload(true); // TODO: Make this async, but lock out the database widget to prevent re-entrance - QString errorMessage = db->saveToFile(filePath, config()->get("BackupBeforeSave").toBool()); + bool useAtomicSaves = config()->get("UseAtomicSaves").toBool(); + QString errorMessage = db->saveToFile(filePath, useAtomicSaves, config()->get("BackupBeforeSave").toBool()); dbStruct.dbWidget->blockAutoReload(false); if (errorMessage.isEmpty()) { // successfully saved database file dbStruct.modified = false; + dbStruct.saveAttempts = 0; dbStruct.fileInfo = QFileInfo(filePath); dbStruct.dbWidget->databaseSaved(); updateTabName(db); @@ -338,6 +341,22 @@ bool DatabaseTabWidget::saveDatabase(Database* db, QString filePath) } else { dbStruct.modified = true; updateTabName(db); + + if (++dbStruct.saveAttempts > 2 && useAtomicSaves) { + // Saving failed 3 times, issue a warning and attempt to resolve + auto choice = MessageBox::question(this, tr("Disable safe saves?"), + tr("KeePassXC has failed to save the database multiple times. " + "This is likely caused by file sync services holding a lock on " + "the save file.\nDisable safe saves and try again?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + if (choice == QMessageBox::Yes) { + config()->set("UseAtomicSaves", false); + return saveDatabase(db, filePath); + } + // Reset save attempts without changing anything + dbStruct.saveAttempts = 0; + } + emit messageTab(tr("Writing the database failed.").append("\n").append(errorMessage), MessageWidget::Error); return false; diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h index 875c3c90..b216750e 100644 --- a/src/gui/DatabaseTabWidget.h +++ b/src/gui/DatabaseTabWidget.h @@ -40,6 +40,7 @@ struct DatabaseManagerStruct QFileInfo fileInfo; bool modified; bool readOnly; + int saveAttempts; }; Q_DECLARE_TYPEINFO(DatabaseManagerStruct, Q_MOVABLE_TYPE); diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index 12c97088..919edf9f 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -118,6 +118,7 @@ void SettingsWidget::loadSettings() m_generalUi->autoSaveAfterEveryChangeCheckBox->setChecked(config()->get("AutoSaveAfterEveryChange").toBool()); m_generalUi->autoSaveOnExitCheckBox->setChecked(config()->get("AutoSaveOnExit").toBool()); m_generalUi->backupBeforeSaveCheckBox->setChecked(config()->get("BackupBeforeSave").toBool()); + m_generalUi->useAtomicSavesCheckBox->setChecked(config()->get("UseAtomicSaves").toBool()); m_generalUi->autoReloadOnChangeCheckBox->setChecked(config()->get("AutoReloadOnChange").toBool()); m_generalUi->minimizeOnCopyCheckBox->setChecked(config()->get("MinimizeOnCopy").toBool()); m_generalUi->useGroupIconOnEntryCreationCheckBox->setChecked(config()->get("UseGroupIconOnEntryCreation").toBool()); @@ -195,6 +196,7 @@ void SettingsWidget::saveSettings() m_generalUi->autoSaveAfterEveryChangeCheckBox->isChecked()); config()->set("AutoSaveOnExit", m_generalUi->autoSaveOnExitCheckBox->isChecked()); config()->set("BackupBeforeSave", m_generalUi->backupBeforeSaveCheckBox->isChecked()); + config()->set("UseAtomicSaves", m_generalUi->useAtomicSavesCheckBox->isChecked()); config()->set("AutoReloadOnChange", m_generalUi->autoReloadOnChangeCheckBox->isChecked()); config()->set("MinimizeOnCopy", m_generalUi->minimizeOnCopyCheckBox->isChecked()); config()->set("UseGroupIconOnEntryCreation", diff --git a/src/gui/SettingsWidgetGeneral.ui b/src/gui/SettingsWidgetGeneral.ui index a80c8c2f..f8414f07 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -34,131 +34,134 @@ - - - Start only a single instance of KeePassXC + + + Startup - - true - - - - - - - Remember last databases - - - true - - - - - - - Remember last key files and security dongles - - - true - - - - - - - Load previous databases on startup - - - - - - - Automatically save on exit - - - - - - - Automatically save after every change - - - - - - - Backup database file before saving - - - - - - - Automatically reload the database when modified externally - - - - - - - Minimize when copying to clipboard - - - - - - - Minimize window at application startup - - - - - - - Use group icon on entry creation - - - true - - - - - - - Don't mark database as modified for non-data changes (e.g., expanding groups) - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - + - - - Qt::Vertical + + + Start only a single instance of KeePassXC - - QSizePolicy::Fixed + + true - - - 20 - 30 - + + + + + + Remember last databases - + + true + + + + + + + Remember last key files and security dongles + + + true + + + + + + + Load previous databases on startup + + + + + + + Minimize window at application startup + + + + + + + + + + File Management + + + + + + Safely save database files (may be incompatible with DropBox, etc) + + + true + + + + + + + Backup database file before saving + + + + + + + Automatically save after every change + + + + + + + Automatically save on exit + + + + + + + Don't mark database as modified for non-data changes (e.g., expanding groups) + + + + + + + Automatically reload the database when modified externally + + + + + + + + + + Entry Management + + + + + + Use group icon on entry creation + + + true + + + + + + + Minimize when copying to clipboard + + @@ -167,6 +170,15 @@ + + + + + + + General + + @@ -175,114 +187,162 @@ - + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + QLayout::SetMaximumSize + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + false + + + + 0 + 0 + + + + Hide window to system tray when minimized + + + + + + + + + 0 + + + QLayout::SetMaximumSize + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + false + + + Hide window to system tray instead of app exit + + + + + + + + + 0 + + + QLayout::SetMaximumSize + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + false + + + Dark system tray icon + + + + + + + + + + - 0 + 15 - - QLayout::SetMaximumSize - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - - - false - + + - + 0 0 - Hide window to system tray when minimized + Language - - - - - - 0 - - - QLayout::SetMaximumSize - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - - - false - - - Hide window to system tray instead of app exit - - - - - - - - - 0 - - - QLayout::SetMaximumSize - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - - - false - - - Dark system tray icon + + + + 0 + 0 + @@ -291,52 +351,6 @@ - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 30 - - - - - - - - 15 - - - - - - 0 - 0 - - - - Language - - - - - - - - 0 - 0 - - - - - - From 6a4b275d40e98a5b4b2dbd4e586c9531a2f6a5fa Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sun, 28 Jan 2018 10:14:36 -0500 Subject: [PATCH 3/4] Minor changes to address comments --- src/core/Config.cpp | 2 +- src/core/Database.cpp | 11 ++++------- src/gui/DatabaseTabWidget.cpp | 2 +- src/gui/SettingsWidgetGeneral.ui | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/core/Config.cpp b/src/core/Config.cpp index 328dfaed..f42bb604 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -111,7 +111,7 @@ void Config::init(const QString& fileName) m_defaults.insert("RememberLastDatabases", true); m_defaults.insert("RememberLastKeyFiles", true); m_defaults.insert("OpenPreviousDatabasesOnStartup", true); - m_defaults.insert("AutoSaveAfterEveryChange", false); + m_defaults.insert("AutoSaveAfterEveryChange", true); m_defaults.insert("AutoReloadOnChange", true); m_defaults.insert("AutoSaveOnExit", false); m_defaults.insert("BackupBeforeSave", false); diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 9a1fe0b3..70affdc5 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -476,7 +476,7 @@ Database* Database::unlockFromStdin(QString databaseFilename, QString keyFilenam * * This function uses QTemporaryFile instead of QSaveFile due to a bug * in Qt (https://bugreports.qt.io/browse/QTBUG-57299) that may prevent - * the QSaveFile from renaming itself when using DropBox, Drive, or OneDrive. + * the QSaveFile from renaming itself when using Dropbox, Drive, or OneDrive. * * The risk in using QTemporaryFile is that the rename function is not atomic * and may result in loss of data if there is a crash or power loss at the @@ -554,7 +554,7 @@ QString Database::writeDatabase(QIODevice* device) /** * Remove the old backup and replace it with a new one - * backups are named .old.kdbx4 + * backups are named .old.kdbx * * @param filePath Path to the file to backup * @return @@ -562,11 +562,8 @@ QString Database::writeDatabase(QIODevice* device) bool Database::backupDatabase(QString filePath) { QString backupFilePath = filePath; - backupFilePath.replace(".kdbx", ".old.kdbx", Qt::CaseInsensitive); - if (!backupFilePath.endsWith(".old.kdbx")) { - // Fallback in case of poorly named file - backupFilePath = filePath + ".old"; - } + auto re = QRegularExpression("(?:\\.kdbx)?$", QRegularExpression::CaseInsensitiveOption); + backupFilePath.replace(re, ".old.kdbx"); QFile::remove(backupFilePath); return QFile::copy(filePath, backupFilePath); } diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 1765a9cd..47ff597b 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -325,7 +325,7 @@ bool DatabaseTabWidget::saveDatabase(Database* db, QString filePath) dbStruct.dbWidget->blockAutoReload(true); // TODO: Make this async, but lock out the database widget to prevent re-entrance - bool useAtomicSaves = config()->get("UseAtomicSaves").toBool(); + bool useAtomicSaves = config()->get("UseAtomicSaves", true).toBool(); QString errorMessage = db->saveToFile(filePath, useAtomicSaves, config()->get("BackupBeforeSave").toBool()); dbStruct.dbWidget->blockAutoReload(false); diff --git a/src/gui/SettingsWidgetGeneral.ui b/src/gui/SettingsWidgetGeneral.ui index f8414f07..5ed952f1 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -95,7 +95,7 @@ - Safely save database files (may be incompatible with DropBox, etc) + Safely save database files (may be incompatible with Dropbox, etc) true From 8c8a61ddfe55b0dcdb13751b4ce144b6ae91a398 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sun, 28 Jan 2018 14:06:17 -0500 Subject: [PATCH 4/4] Disable auto save for GUI tests --- tests/gui/TestGui.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 44b1d066..cf7b969e 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -67,6 +67,9 @@ void TestGui::initTestCase() { QVERIFY(Crypto::init()); Config::createTempFileInstance(); + // Disable autosave so we can test the modified file indicator + Config::instance()->set("AutoSaveAfterEveryChange", false); + m_mainWindow = new MainWindow(); m_tabWidget = m_mainWindow->findChild("tabWidget"); m_mainWindow->show(); @@ -141,7 +144,6 @@ void TestGui::testCreateDatabase() DatabaseWidget* dbWidget = m_tabWidget->currentDatabaseWidget(); QWidget* databaseNewWidget = dbWidget->findChild("changeMasterKeyWidget"); - QList databaseNewWidgets = dbWidget->findChildren("changeMasterKeyWidget"); PasswordEdit* editPassword = databaseNewWidget->findChild("enterPasswordEdit"); QVERIFY(editPassword->isVisible()); @@ -154,6 +156,7 @@ void TestGui::testCreateDatabase() QTest::keyClicks(editPasswordRepeat, "test"); QTest::keyClick(editPasswordRepeat, Qt::Key_Enter); + // Auto-save after every change is enabled by default, ensure the db saves right away QTRY_VERIFY(m_tabWidget->tabText(m_tabWidget->currentIndex()).contains("*")); m_db = m_tabWidget->currentDatabaseWidget()->database();