diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index cbfda0636..e9535f973 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -219,18 +219,30 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ApplicationSettingsWidgetGeneral
@@ -306,22 +318,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -501,6 +501,46 @@
number of days warning for password expiration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ApplicationSettingsWidgetSecurity
@@ -566,18 +606,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -594,6 +622,14 @@
+
+
+
+
+
+
+
+
AutoType
diff --git a/src/core/Config.cpp b/src/core/Config.cpp
index 871c26419..a38b307be 100644
--- a/src/core/Config.cpp
+++ b/src/core/Config.cpp
@@ -302,6 +302,45 @@ void Config::resetToDefaults()
}
}
+bool Config::importSettings(const QString& fileName)
+{
+ // Ensure file is valid ini with values
+ QSettings settings(fileName, QSettings::IniFormat);
+ if (settings.status() != QSettings::NoError || settings.allKeys().isEmpty()) {
+ return false;
+ }
+
+ // Only import valid roaming settings
+ auto isValidSetting = [](const QString& key) {
+ for (const auto& value : configStrings.values()) {
+ if (value.type == ConfigType::Roaming && value.name == key) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ // Clear existing settings and set valid items
+ m_settings->clear();
+ for (const auto& key : settings.allKeys()) {
+ if (isValidSetting(key)) {
+ m_settings->setValue(key, settings.value(key));
+ }
+ }
+
+ sync();
+
+ return true;
+}
+
+void Config::exportSettings(const QString& fileName) const
+{
+ QSettings settings(fileName, QSettings::IniFormat);
+ for (const auto& key : m_settings->allKeys()) {
+ settings.setValue(key, m_settings->value(key));
+ }
+}
+
/**
* Map of configuration file settings that are either deprecated, or have
* had their name changed to their new config enum values.
diff --git a/src/core/Config.h b/src/core/Config.h
index af24427a0..0f39beafb 100644
--- a/src/core/Config.h
+++ b/src/core/Config.h
@@ -217,6 +217,9 @@ public:
void sync();
void resetToDefaults();
+ bool importSettings(const QString& fileName);
+ void exportSettings(const QString& fileName) const;
+
QList getShortcuts() const;
void setShortcuts(const QList& shortcuts);
diff --git a/src/gui/ApplicationSettingsWidget.cpp b/src/gui/ApplicationSettingsWidget.cpp
index cbe431043..27f27eb6d 100644
--- a/src/gui/ApplicationSettingsWidget.cpp
+++ b/src/gui/ApplicationSettingsWidget.cpp
@@ -117,6 +117,8 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent)
connect(m_generalUi->systrayShowCheckBox, SIGNAL(toggled(bool)), SLOT(systrayToggled(bool)));
connect(m_generalUi->rememberLastDatabasesCheckBox, SIGNAL(toggled(bool)), SLOT(rememberDatabasesToggled(bool)));
connect(m_generalUi->resetSettingsButton, SIGNAL(clicked()), SLOT(resetSettings()));
+ connect(m_generalUi->importSettingsButton, SIGNAL(clicked()), SLOT(importSettings()));
+ connect(m_generalUi->exportSettingsButton, SIGNAL(clicked()), SLOT(exportSettings()));
connect(m_generalUi->useAlternativeSaveCheckBox, SIGNAL(toggled(bool)),
m_generalUi->alternativeSaveComboBox, SLOT(setEnabled(bool)));
@@ -233,6 +235,10 @@ void ApplicationSettingsWidget::loadSettings()
m_generalUi->autoTypeEntryURLMatchCheckBox->setChecked(config()->get(Config::AutoTypeEntryURLMatch).toBool());
m_generalUi->autoTypeHideExpiredEntryCheckBox->setChecked(config()->get(Config::AutoTypeHideExpiredEntry).toBool());
m_generalUi->faviconTimeoutSpinBox->setValue(config()->get(Config::FaviconDownloadTimeout).toInt());
+ m_generalUi->ConfirmMoveEntryToRecycleBinCheckBox->setChecked(
+ !config()->get(Config::Security_NoConfirmMoveEntryToRecycleBin).toBool());
+ m_generalUi->EnableCopyOnDoubleClickCheckBox->setChecked(
+ config()->get(Config::Security_EnableCopyOnDoubleClick).toBool());
m_generalUi->languageComboBox->clear();
QList> languages = Translator::availableLanguages();
@@ -244,6 +250,8 @@ void ApplicationSettingsWidget::loadSettings()
m_generalUi->languageComboBox->setCurrentIndex(defaultIndex);
}
+ m_generalUi->menubarShowCheckBox->setChecked(!config()->get(Config::GUI_HideMenubar).toBool());
+ m_generalUi->toolbarShowCheckBox->setChecked(!config()->get(Config::GUI_HideToolbar).toBool());
m_generalUi->toolbarMovableCheckBox->setChecked(config()->get(Config::GUI_MovableToolbar).toBool());
m_generalUi->monospaceNotesCheckBox->setChecked(config()->get(Config::GUI_MonospaceNotes).toBool());
m_generalUi->colorPasswordsCheckBox->setChecked(config()->get(Config::GUI_ColorPasswords).toBool());
@@ -332,10 +340,6 @@ void ApplicationSettingsWidget::loadSettings()
config()->get(Config::Security_HidePasswordPreviewPanel).toBool());
m_secUi->hideTotpCheckBox->setChecked(config()->get(Config::Security_HideTotpPreviewPanel).toBool());
m_secUi->hideNotesCheckBox->setChecked(config()->get(Config::Security_HideNotes).toBool());
- m_secUi->NoConfirmMoveEntryToRecycleBinCheckBox->setChecked(
- config()->get(Config::Security_NoConfirmMoveEntryToRecycleBin).toBool());
- m_secUi->EnableCopyOnDoubleClickCheckBox->setChecked(
- config()->get(Config::Security_EnableCopyOnDoubleClick).toBool());
m_secUi->quickUnlockCheckBox->setEnabled(getQuickUnlock()->isAvailable());
m_secUi->quickUnlockCheckBox->setChecked(config()->get(Config::Security_QuickUnlock).toBool());
@@ -386,6 +390,9 @@ void ApplicationSettingsWidget::saveSettings()
config()->set(Config::AutoTypeEntryURLMatch, m_generalUi->autoTypeEntryURLMatchCheckBox->isChecked());
config()->set(Config::AutoTypeHideExpiredEntry, m_generalUi->autoTypeHideExpiredEntryCheckBox->isChecked());
config()->set(Config::FaviconDownloadTimeout, m_generalUi->faviconTimeoutSpinBox->value());
+ config()->set(Config::Security_NoConfirmMoveEntryToRecycleBin,
+ !m_generalUi->ConfirmMoveEntryToRecycleBinCheckBox->isChecked());
+ config()->set(Config::Security_EnableCopyOnDoubleClick, m_generalUi->EnableCopyOnDoubleClickCheckBox->isChecked());
auto language = m_generalUi->languageComboBox->currentData().toString();
if (config()->get(Config::GUI_Language) != language) {
@@ -396,6 +403,8 @@ void ApplicationSettingsWidget::saveSettings()
}
config()->set(Config::GUI_Language, language);
+ config()->set(Config::GUI_HideMenubar, !m_generalUi->menubarShowCheckBox->isChecked());
+ config()->set(Config::GUI_HideToolbar, !m_generalUi->toolbarShowCheckBox->isChecked());
config()->set(Config::GUI_MovableToolbar, m_generalUi->toolbarMovableCheckBox->isChecked());
config()->set(Config::GUI_MonospaceNotes, m_generalUi->monospaceNotesCheckBox->isChecked());
config()->set(Config::GUI_ColorPasswords, m_generalUi->colorPasswordsCheckBox->isChecked());
@@ -446,9 +455,6 @@ void ApplicationSettingsWidget::saveSettings()
config()->set(Config::Security_HidePasswordPreviewPanel, m_secUi->passwordPreviewCleartextCheckBox->isChecked());
config()->set(Config::Security_HideTotpPreviewPanel, m_secUi->hideTotpCheckBox->isChecked());
config()->set(Config::Security_HideNotes, m_secUi->hideNotesCheckBox->isChecked());
- config()->set(Config::Security_NoConfirmMoveEntryToRecycleBin,
- m_secUi->NoConfirmMoveEntryToRecycleBinCheckBox->isChecked());
- config()->set(Config::Security_EnableCopyOnDoubleClick, m_secUi->EnableCopyOnDoubleClickCheckBox->isChecked());
if (m_secUi->quickUnlockCheckBox->isEnabled()) {
config()->set(Config::Security_QuickUnlock, m_secUi->quickUnlockCheckBox->isChecked());
@@ -476,8 +482,8 @@ void ApplicationSettingsWidget::resetSettings()
{
// Confirm reset
auto ans = MessageBox::question(this,
- tr("Reset Settings?"),
- tr("Are you sure you want to reset all general and security settings to default?"),
+ tr("Confirm Reset"),
+ tr("Are you sure you want to reset all settings to default?"),
MessageBox::Reset | MessageBox::Cancel,
MessageBox::Cancel);
if (ans == MessageBox::Cancel) {
@@ -512,6 +518,33 @@ void ApplicationSettingsWidget::resetSettings()
emit settingsReset();
}
+void ApplicationSettingsWidget::importSettings()
+{
+ auto file = fileDialog()->getOpenFileName(this, tr("Import KeePassXC Settings"), {}, "*.ini");
+ if (file.isEmpty()) {
+ return;
+ }
+
+ if (!config()->importSettings(file)) {
+ showMessage(tr("Failed to import settings from %1, not a valid settings file.").arg(file),
+ MessageWidget::Error);
+ return;
+ }
+
+ loadSettings();
+ emit settingsReset();
+}
+
+void ApplicationSettingsWidget::exportSettings()
+{
+ auto file = fileDialog()->getSaveFileName(this, tr("Export KeePassXC Settings"), {}, "*.ini");
+ if (file.isEmpty()) {
+ return;
+ }
+
+ config()->exportSettings(file);
+}
+
void ApplicationSettingsWidget::reject()
{
// register the old key again as it might have changed
diff --git a/src/gui/ApplicationSettingsWidget.h b/src/gui/ApplicationSettingsWidget.h
index 5c6572173..7e43196b1 100644
--- a/src/gui/ApplicationSettingsWidget.h
+++ b/src/gui/ApplicationSettingsWidget.h
@@ -54,6 +54,8 @@ signals:
private slots:
void saveSettings();
void resetSettings();
+ void importSettings();
+ void exportSettings();
void reject();
void autoSaveToggled(bool checked);
void hideWindowOnCopyCheckBoxToggled(bool checked);
diff --git a/src/gui/ApplicationSettingsWidgetGeneral.ui b/src/gui/ApplicationSettingsWidgetGeneral.ui
index 1af95e5ea..6e74205ff 100644
--- a/src/gui/ApplicationSettingsWidgetGeneral.ui
+++ b/src/gui/ApplicationSettingsWidgetGeneral.ui
@@ -58,8 +58,8 @@
0
0
- 566
- 975
+ 568
+ 1153
@@ -268,31 +268,25 @@
-
-
-
- QLayout::SetMaximumSize
-
+
6
-
-
+
+ QLayout::SetMaximumSize
+
+
-
On database unlock, show entries that will expire within
- -
+
-
true
-
-
- 0
- 0
-
-
Qt::StrongFocus
@@ -313,7 +307,7 @@
- -
+
-
Qt::Horizontal
@@ -374,6 +368,25 @@
-
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 30
+ 20
+
+
+
+
-
@@ -383,41 +396,70 @@
- Backup destination
+ Destination format:
backupFilePath
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 6
+ 20
+
+
+
+
-
false
- Specifies the database backup file location. Occurrences 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".
+ <html><head/><body><p><span style=" font-weight:600;">{DB_FILENAME}</span> is replaced with the filename of the saved database without extension</p><p><span style=" font-weight:600;">{TIME:<format>}</span> is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)</p><p>See the User Guide for more details</p></body></html>
{DB_FILENAME}.old.kdbx
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 6
+ 20
+
+
+
+
-
false
- Choose...
+ Choose folder...
- -
-
-
-
@@ -487,6 +529,20 @@
Entry Management
+
-
+
+
+ Show confirmation before moving entries to recycle bin
+
+
+
+ -
+
+
+ Copy data on double clicking field in entry view
+
+
+
-
@@ -643,6 +699,35 @@
10
+
-
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ Movable toolbar
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
-
@@ -662,19 +747,28 @@
- -
-
+
-
+
true
-
+
0
0
+
+ margin-right: 5px
+
- Movable toolbar
+ Toolbar button style:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ toolButtonStyleComboBox
@@ -720,46 +814,25 @@
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
- margin-right: 5px
-
-
- Toolbar button style:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- toolButtonStyleComboBox
-
-
-
+ -
+
+
+ Show toolbar
+
+
+
+ -
+
+
+ Show the menu bar by pressing the Alt key
+
+
+ Show menubar
+
+
+
-
@@ -941,7 +1014,7 @@
-
- 0
+ 6
QLayout::SetMaximumSize
@@ -954,21 +1027,32 @@
-
-
+
Qt::Horizontal
-
- QSizePolicy::Expanding
-
- 50
+ 40
20
+ -
+
+
+ Import settings…
+
+
+
+ -
+
+
+ Export settings…
+
+
+
-
@@ -1265,6 +1349,8 @@
backupFilePathPicker
useAlternativeSaveCheckBox
alternativeSaveComboBox
+ ConfirmMoveEntryToRecycleBinCheckBox
+ EnableCopyOnDoubleClickCheckBox
useGroupIconOnEntryCreationCheckBox
minimizeOnOpenUrlCheckBox
hideWindowOnCopyCheckBox
@@ -1274,6 +1360,8 @@
languageComboBox
toolButtonStyleComboBox
toolbarMovableCheckBox
+ toolbarShowCheckBox
+ menubarShowCheckBox
colorPasswordsCheckBox
monospaceNotesCheckBox
minimizeOnCloseCheckBox
@@ -1281,6 +1369,8 @@
trayIconAppearance
systrayMinimizeToTrayCheckBox
resetSettingsButton
+ importSettingsButton
+ exportSettingsButton
autoTypeEntryTitleMatchCheckBox
autoTypeEntryURLMatchCheckBox
autoTypeAskCheckBox
diff --git a/src/gui/ApplicationSettingsWidgetSecurity.ui b/src/gui/ApplicationSettingsWidgetSecurity.ui
index 84f1083ac..c4cb0e01f 100644
--- a/src/gui/ApplicationSettingsWidgetSecurity.ui
+++ b/src/gui/ApplicationSettingsWidgetSecurity.ui
@@ -7,7 +7,7 @@
0
0
364
- 493
+ 505
@@ -31,7 +31,7 @@
Timeouts
-
+
-
@@ -160,11 +160,11 @@
-
-
+
- Convenience
+ Lock Options
-
+
-
@@ -179,13 +179,6 @@
- -
-
-
- Lock databases after minimizing the window
-
-
-
-
@@ -194,12 +187,21 @@
-
-
+
- Hide passwords when editing them
+ Lock databases after minimizing the window
+
+
+
+ -
+
+
+ Convenience
+
+
-
@@ -207,6 +209,13 @@
+ -
+
+
+ Hide passwords when editing them
+
+
+
-
@@ -224,21 +233,7 @@
-
- Hide entry notes by default
-
-
-
- -
-
-
- Move entries to recycle bin without confirmation
-
-
-
- -
-
-
- Enable double click to copy the username/password entry columns
+ Hide notes in the entry preview panel
@@ -284,19 +279,17 @@
clearClipboardSpinBox
lockDatabaseIdleCheckBox
lockDatabaseIdleSpinBox
- lockDatabasesOnUserSwitchCheckBox
clearSearchCheckBox
clearSearchSpinBox
quickUnlockCheckBox
lockDatabaseOnScreenLockCheckBox
+ lockDatabasesOnUserSwitchCheckBox
lockDatabaseMinimizeCheckBox
- passwordsHiddenCheckBox
passwordShowDotsCheckBox
+ passwordsHiddenCheckBox
passwordPreviewCleartextCheckBox
hideTotpCheckBox
hideNotesCheckBox
- NoConfirmMoveEntryToRecycleBinCheckBox
- EnableCopyOnDoubleClickCheckBox
fallbackToSearch
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index 9e38dcda9..7f223a3a4 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -1704,6 +1704,8 @@ void MainWindow::applySettingsChanges()
m_inactivityTimer->deactivate();
}
+ m_ui->actionShowToolbar->setChecked(!config()->get(Config::GUI_HideToolbar).toBool());
+ m_ui->actionShowMenubar->setChecked(!config()->get(Config::GUI_HideMenubar).toBool());
m_ui->menubar->setHidden(config()->get(Config::GUI_HideMenubar).toBool());
m_ui->toolBar->setHidden(config()->get(Config::GUI_HideToolbar).toBool());
auto movable = config()->get(Config::GUI_MovableToolbar).toBool();