Implement 'Save Database Backup' option
Add an option in the 'Database' menu to save a backup of the current database. Add unit test for saving database copy * Open a test database, mark it as modified, and save a copy * Fail if the copy is not a valid database * Fail if the original database is saved * Fail if the original database is no longer marked as modified
This commit is contained in:
committed by
Jonathan White
parent
2237cf0188
commit
45848c3f61
@@ -393,6 +393,20 @@ bool DatabaseTabWidget::saveDatabaseAs(int index)
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool DatabaseTabWidget::saveDatabaseBackup(int index)
|
||||
{
|
||||
if (index == -1) {
|
||||
index = currentIndex();
|
||||
}
|
||||
|
||||
auto* dbWidget = databaseWidgetFromIndex(index);
|
||||
bool ok = dbWidget->saveBackup();
|
||||
if (ok) {
|
||||
updateLastDatabases(dbWidget->database()->filePath());
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void DatabaseTabWidget::closeDatabaseFromSender()
|
||||
{
|
||||
auto* dbWidget = qobject_cast<DatabaseWidget*>(sender());
|
||||
|
||||
@@ -68,6 +68,7 @@ public slots:
|
||||
void importOpVaultDatabase();
|
||||
bool saveDatabase(int index = -1);
|
||||
bool saveDatabaseAs(int index = -1);
|
||||
bool saveDatabaseBackup(int index = -1);
|
||||
void exportToCsv();
|
||||
void exportToHtml();
|
||||
|
||||
|
||||
@@ -1866,6 +1866,53 @@ bool DatabaseWidget::saveAs()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save copy of database under a new user-selected filename.
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool DatabaseWidget::saveBackup()
|
||||
{
|
||||
while (true) {
|
||||
QString oldFilePath = m_db->filePath();
|
||||
if (!QFileInfo::exists(oldFilePath)) {
|
||||
oldFilePath = QDir::toNativeSeparators(config()->get(Config::LastDir).toString() + "/"
|
||||
+ tr("Passwords").append(".kdbx"));
|
||||
}
|
||||
const QString newFilePath = fileDialog()->getSaveFileName(this,
|
||||
tr("Save database backup"),
|
||||
oldFilePath,
|
||||
tr("KeePass 2 Database").append(" (*.kdbx)"),
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (!newFilePath.isEmpty()) {
|
||||
// Ensure we don't recurse back into this function
|
||||
m_db->setReadOnly(false);
|
||||
m_db->setFilePath(newFilePath);
|
||||
m_saveAttempts = 0;
|
||||
|
||||
bool modified = m_db->isModified();
|
||||
|
||||
if (!save()) {
|
||||
// Failed to save, try again
|
||||
m_db->setFilePath(oldFilePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
m_db->setFilePath(oldFilePath);
|
||||
if (modified) {
|
||||
// Source database is marked as clean when copy is saved, even if source has unsaved changes
|
||||
m_db->markAsModified();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Canceled file selection
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWidget::showMessage(const QString& text,
|
||||
MessageWidget::MessageType type,
|
||||
bool showClosebutton,
|
||||
|
||||
@@ -158,6 +158,7 @@ public slots:
|
||||
bool lock();
|
||||
bool save();
|
||||
bool saveAs();
|
||||
bool saveBackup();
|
||||
|
||||
void replaceDatabase(QSharedPointer<Database> db);
|
||||
void createEntry();
|
||||
|
||||
@@ -324,6 +324,7 @@ MainWindow::MainWindow()
|
||||
m_ui->actionDatabaseOpen->setIcon(resources()->icon("document-open"));
|
||||
m_ui->actionDatabaseSave->setIcon(resources()->icon("document-save"));
|
||||
m_ui->actionDatabaseSaveAs->setIcon(resources()->icon("document-save-as"));
|
||||
m_ui->actionDatabaseSaveBackup->setIcon(resources()->icon("document-save-copy"));
|
||||
m_ui->actionDatabaseClose->setIcon(resources()->icon("document-close"));
|
||||
m_ui->actionReports->setIcon(resources()->icon("reports"));
|
||||
m_ui->actionChangeDatabaseSettings->setIcon(resources()->icon("document-edit"));
|
||||
@@ -396,6 +397,7 @@ MainWindow::MainWindow()
|
||||
connect(m_ui->actionDatabaseOpen, SIGNAL(triggered()), m_ui->tabWidget, SLOT(openDatabase()));
|
||||
connect(m_ui->actionDatabaseSave, SIGNAL(triggered()), m_ui->tabWidget, SLOT(saveDatabase()));
|
||||
connect(m_ui->actionDatabaseSaveAs, SIGNAL(triggered()), m_ui->tabWidget, SLOT(saveDatabaseAs()));
|
||||
connect(m_ui->actionDatabaseSaveBackup, SIGNAL(triggered()), m_ui->tabWidget, SLOT(saveDatabaseBackup()));
|
||||
connect(m_ui->actionDatabaseClose, SIGNAL(triggered()), m_ui->tabWidget, SLOT(closeCurrentDatabaseTab()));
|
||||
connect(m_ui->actionDatabaseMerge, SIGNAL(triggered()), m_ui->tabWidget, SLOT(mergeDatabase()));
|
||||
connect(m_ui->actionChangeMasterKey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(changeMasterKey()));
|
||||
@@ -681,6 +683,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|
||||
m_ui->actionChangeDatabaseSettings->setEnabled(true);
|
||||
m_ui->actionDatabaseSave->setEnabled(m_ui->tabWidget->canSave());
|
||||
m_ui->actionDatabaseSaveAs->setEnabled(true);
|
||||
m_ui->actionDatabaseSaveBackup->setEnabled(true);
|
||||
m_ui->menuExport->setEnabled(true);
|
||||
m_ui->actionExportCsv->setEnabled(true);
|
||||
m_ui->actionExportHtml->setEnabled(true);
|
||||
@@ -736,6 +739,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|
||||
m_ui->actionChangeDatabaseSettings->setEnabled(false);
|
||||
m_ui->actionDatabaseSave->setEnabled(false);
|
||||
m_ui->actionDatabaseSaveAs->setEnabled(false);
|
||||
m_ui->actionDatabaseSaveBackup->setEnabled(false);
|
||||
m_ui->menuExport->setEnabled(false);
|
||||
m_ui->actionExportCsv->setEnabled(false);
|
||||
m_ui->actionExportHtml->setEnabled(false);
|
||||
@@ -764,6 +768,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
|
||||
m_ui->actionChangeDatabaseSettings->setEnabled(false);
|
||||
m_ui->actionDatabaseSave->setEnabled(false);
|
||||
m_ui->actionDatabaseSaveAs->setEnabled(false);
|
||||
m_ui->actionDatabaseSaveBackup->setEnabled(false);
|
||||
m_ui->actionDatabaseClose->setEnabled(false);
|
||||
m_ui->menuExport->setEnabled(false);
|
||||
m_ui->actionExportCsv->setEnabled(false);
|
||||
|
||||
@@ -260,6 +260,7 @@
|
||||
<addaction name="menuRecentDatabases"/>
|
||||
<addaction name="actionDatabaseSave"/>
|
||||
<addaction name="actionDatabaseSaveAs"/>
|
||||
<addaction name="actionDatabaseSaveBackup"/>
|
||||
<addaction name="actionDatabaseClose"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionChangeMasterKey"/>
|
||||
@@ -332,9 +333,6 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionEntryOpenUrl"/>
|
||||
<addaction name="actionEntryDownloadIcon"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionEntryAddToAgent"/>
|
||||
<addaction name="actionEntryRemoveFromAgent"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuGroups">
|
||||
<property name="title">
|
||||
@@ -808,6 +806,14 @@
|
||||
<string notr="true">Ctrl+/</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDatabaseSaveBackup">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save Database Backup...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEntryAddToAgent">
|
||||
<property name="text">
|
||||
<string>Add key to SSH Agent</string>
|
||||
|
||||
Reference in New Issue
Block a user