diff options
author | Patrick Klein <42714034+libklein@users.noreply.github.com> | 2021-11-08 01:41:17 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-08 01:41:17 +0300 |
commit | 84ff6a13f9cd11214396deb31d54955abbcd7b0b (patch) | |
tree | 0fa0d84475f9f79c4a8ce12d8582715b0f084940 /src/gui | |
parent | 8d7e4918109b1e40660e2988e79e1cf15e899580 (diff) |
Allow specifing database backup paths. (#7035)
- Default backupFilePath is '{DB_FILENAME}.old.kdbx' to conform to existing standards
- Implement backupPathPattern tests.
- Show tooltip on how to format database backup location text field.
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/ApplicationSettingsWidget.cpp | 25 | ||||
-rw-r--r-- | src/gui/ApplicationSettingsWidget.h | 1 | ||||
-rw-r--r-- | src/gui/ApplicationSettingsWidgetGeneral.ui | 50 | ||||
-rw-r--r-- | src/gui/DatabaseWidget.cpp | 25 |
4 files changed, 97 insertions, 4 deletions
diff --git a/src/gui/ApplicationSettingsWidget.cpp b/src/gui/ApplicationSettingsWidget.cpp index 100258120..ac96d23b4 100644 --- a/src/gui/ApplicationSettingsWidget.cpp +++ b/src/gui/ApplicationSettingsWidget.cpp @@ -19,6 +19,8 @@ #include "ApplicationSettingsWidget.h" #include "ui_ApplicationSettingsWidgetGeneral.h" #include "ui_ApplicationSettingsWidgetSecurity.h" +#include <QDesktopServices> +#include <QDir> #include "config-keepassx.h" @@ -28,6 +30,7 @@ #include "gui/MainWindow.h" #include "gui/osutils/OSUtils.h" +#include "FileDialog.h" #include "MessageBox.h" #ifdef Q_OS_MACOS #include "touchid/TouchID.h" @@ -112,6 +115,12 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent) connect(m_generalUi->useAlternativeSaveCheckBox, SIGNAL(toggled(bool)), m_generalUi->alternativeSaveComboBox, SLOT(setEnabled(bool))); + connect(m_generalUi->backupBeforeSaveCheckBox, SIGNAL(toggled(bool)), + m_generalUi->backupFilePath, SLOT(setEnabled(bool))); + connect(m_generalUi->backupBeforeSaveCheckBox, SIGNAL(toggled(bool)), + m_generalUi->backupFilePathPicker, SLOT(setEnabled(bool))); + connect(m_generalUi->backupFilePathPicker, SIGNAL(pressed()), SLOT(selectBackupDirectory())); + connect(m_secUi->clearClipboardCheckBox, SIGNAL(toggled(bool)), m_secUi->clearClipboardSpinBox, SLOT(setEnabled(bool))); connect(m_secUi->clearSearchCheckBox, SIGNAL(toggled(bool)), @@ -188,6 +197,9 @@ void ApplicationSettingsWidget::loadSettings() m_generalUi->autoSaveOnExitCheckBox->setChecked(config()->get(Config::AutoSaveOnExit).toBool()); m_generalUi->autoSaveNonDataChangesCheckBox->setChecked(config()->get(Config::AutoSaveNonDataChanges).toBool()); m_generalUi->backupBeforeSaveCheckBox->setChecked(config()->get(Config::BackupBeforeSave).toBool()); + + m_generalUi->backupFilePath->setText(config()->get(Config::BackupFilePathPattern).toString()); + m_generalUi->useAlternativeSaveCheckBox->setChecked(!config()->get(Config::UseAtomicSaves).toBool()); m_generalUi->alternativeSaveComboBox->setCurrentIndex(config()->get(Config::UseDirectWriteSaves).toBool() ? 1 : 0); m_generalUi->autoReloadOnChangeCheckBox->setChecked(config()->get(Config::AutoReloadOnChange).toBool()); @@ -326,6 +338,9 @@ void ApplicationSettingsWidget::saveSettings() config()->set(Config::AutoSaveOnExit, m_generalUi->autoSaveOnExitCheckBox->isChecked()); config()->set(Config::AutoSaveNonDataChanges, m_generalUi->autoSaveNonDataChangesCheckBox->isChecked()); config()->set(Config::BackupBeforeSave, m_generalUi->backupBeforeSaveCheckBox->isChecked()); + + config()->set(Config::BackupFilePathPattern, m_generalUi->backupFilePath->text()); + config()->set(Config::UseAtomicSaves, !m_generalUi->useAlternativeSaveCheckBox->isChecked()); config()->set(Config::UseDirectWriteSaves, m_generalUi->alternativeSaveComboBox->currentIndex() == 1); config()->set(Config::AutoReloadOnChange, m_generalUi->autoReloadOnChangeCheckBox->isChecked()); @@ -504,3 +519,13 @@ void ApplicationSettingsWidget::checkUpdatesToggled(bool checked) { m_generalUi->checkForUpdatesIncludeBetasCheckBox->setEnabled(checked); } + +void ApplicationSettingsWidget::selectBackupDirectory() +{ + auto backupDirectory = + FileDialog::instance()->getExistingDirectory(this, tr("Select backup storage directory"), QDir::homePath()); + if (!backupDirectory.isEmpty()) { + m_generalUi->backupFilePath->setText( + QDir(backupDirectory).filePath(config()->getDefault(Config::BackupFilePathPattern).toString())); + } +}
\ No newline at end of file diff --git a/src/gui/ApplicationSettingsWidget.h b/src/gui/ApplicationSettingsWidget.h index f36e5ef12..c5f2ed7e3 100644 --- a/src/gui/ApplicationSettingsWidget.h +++ b/src/gui/ApplicationSettingsWidget.h @@ -62,6 +62,7 @@ private slots: void systrayToggled(bool checked); void rememberDatabasesToggled(bool checked); void checkUpdatesToggled(bool checked); + void selectBackupDirectory(); private: QWidget* const m_secWidget; diff --git a/src/gui/ApplicationSettingsWidgetGeneral.ui b/src/gui/ApplicationSettingsWidgetGeneral.ui index 0e18dfde6..7729e7c8f 100644 --- a/src/gui/ApplicationSettingsWidgetGeneral.ui +++ b/src/gui/ApplicationSettingsWidgetGeneral.ui @@ -58,8 +58,8 @@ <rect> <x>0</x> <y>0</y> - <width>581</width> - <height>924</height> + <width>664</width> + <height>1215</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout_8"> @@ -279,6 +279,52 @@ </widget> </item> <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Backup destination</string> + </property> + <property name="buddy"> + <cstring>backupFilePath</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="backupFilePath"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Specifies the database backup file location. Occurences of "{DB_FILENAME}" are replaced with the filename of the saved database without extension. {TIME:<format>} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. <format> defaults to format string "dd_MM_yyyy_hh-mm-ss".</string> + </property> + <property name="placeholderText"> + <string>{DB_FILENAME}.old.kdbx</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="backupFilePathPicker"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Choose...</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"/> + </item> + <item> <widget class="QCheckBox" name="useAlternativeSaveCheckBox"> <property name="text"> <string>Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.)</string> diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 7a7d961ae..6d88a6613 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -27,6 +27,7 @@ #include <QProcess> #include <QSplitter> #include <QTextEdit> +#include <core/Tools.h> #include "autotype/AutoType.h" #include "core/EntrySearcher.h" @@ -1879,11 +1880,31 @@ bool DatabaseWidget::performSave(QString& errorMessage, const QString& fileName) } } + QString backupFilePath; + if (config()->get(Config::BackupBeforeSave).toBool()) { + backupFilePath = config()->get(Config::BackupFilePathPattern).toString(); + // Fall back to default + if (backupFilePath.isEmpty()) { + backupFilePath = config()->getDefault(Config::BackupFilePathPattern).toString(); + } + + QFileInfo dbFileInfo(m_db->filePath()); + backupFilePath = Tools::substituteBackupFilePath(backupFilePath, dbFileInfo.canonicalFilePath()); + if (!backupFilePath.isNull()) { + // Note that we cannot guarantee that backupFilePath is actually a valid filename. QT currently provides + // no function for this. Moreover, we don't check if backupFilePath is a file and not a directory. + // If this isn't the case, just let the backup fail. + if (QDir::isRelativePath(backupFilePath)) { + backupFilePath = QDir::cleanPath(dbFileInfo.absolutePath() + QDir::separator() + backupFilePath); + } + } + } + bool ok; if (fileName.isEmpty()) { - ok = m_db->save(saveAction, config()->get(Config::BackupBeforeSave).toBool(), &errorMessage); + ok = m_db->save(saveAction, backupFilePath, &errorMessage); } else { - ok = m_db->saveAs(fileName, saveAction, config()->get(Config::BackupBeforeSave).toBool(), &errorMessage); + ok = m_db->saveAs(fileName, saveAction, backupFilePath, &errorMessage); } // Return control |