Skip to content

Commit

Permalink
Add Import/Export to application settings
Browse files Browse the repository at this point in the history
* Closes #9452 - add import/export buttons to application settings

* Fixes #11120 - duplicate both menubar and toolbar visibility settings into the application settings

* Fixes #8561 - improve placement of various settings between General and Security pages

* Improve tool tip for backup database setting
* Improve wording of various settings
  • Loading branch information
droidmonkey committed Oct 7, 2024
1 parent ba0fc3b commit 684122c
Show file tree
Hide file tree
Showing 8 changed files with 333 additions and 135 deletions.
86 changes: 61 additions & 25 deletions share/translations/keepassxc_en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,27 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Settings?</source>
<source>Select backup storage directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to reset all general and security settings to default?</source>
<source>Confirm Reset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select backup storage directory</source>
<source>Are you sure you want to reset all settings to default?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import KeePassXC Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to import settings from %1, not a valid settings file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Export KeePassXC Settings</source>
<translation type="unfinished"></translation>
</message>
</context>
Expand Down Expand Up @@ -306,22 +318,10 @@
<source>Backup database file before saving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Backup destination</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Specifies the database backup file location. Occurrences of &quot;{DB_FILENAME}&quot; are replaced with the filename of the saved database without extension. {TIME:&lt;format&gt;} is replaced with the backup time, see https://doc.qt.io/qt-5/qdatetime.html#toString. &lt;format&gt; defaults to format string &quot;dd_MM_yyyy_hh-mm-ss&quot;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>{DB_FILENAME}.old.kdbx</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Choose...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use alternative saving method (may solve problems with Dropbox, Google Drive, GVFS, etc.)</source>
<translation type="unfinished"></translation>
Expand Down Expand Up @@ -501,6 +501,46 @@
<comment>number of days warning for password expiration</comment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Destination format:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;{DB_FILENAME}&lt;/span&gt; is replaced with the filename of the saved database without extension&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;{TIME:&amp;lt;format&amp;gt;}&lt;/span&gt; is replaced with the specified time format (default: dd_MM_yyyy_hh-mm-ss)&lt;/p&gt;&lt;p&gt;See the User Guide for more details&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Choose folder...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show confirmation before moving entries to recycle bin</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy data on double clicking field in entry view</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show toolbar</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show the menu bar by pressing the Alt key</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Show menubar</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import settings…</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Export settings…</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ApplicationSettingsWidgetSecurity</name>
Expand Down Expand Up @@ -567,31 +607,27 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide entry notes by default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Move entries to recycle bin without confirmation</source>
<source>Privacy</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable double click to copy the username/password entry columns</source>
<source>Use DuckDuckGo service to download website icons</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Privacy</source>
<source>Hide TOTP in the entry preview panel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use DuckDuckGo service to download website icons</source>
<source>Lock databases when switching user</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide TOTP in the entry preview panel</source>
<source>Lock Options</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Lock databases when switching user</source>
<source>Hide notes in the entry preview panel</source>
<translation type="unfinished"></translation>
</message>
</context>
Expand Down
39 changes: 39 additions & 0 deletions src/core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions src/core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ class Config : public QObject
void sync();
void resetToDefaults();

bool importSettings(const QString& fileName);
void exportSettings(const QString& fileName) const;

QList<ShortcutEntry> getShortcuts() const;
void setShortcuts(const QList<ShortcutEntry>& shortcuts);

Expand Down
51 changes: 42 additions & 9 deletions src/gui/ApplicationSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)));

Expand Down Expand Up @@ -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<QPair<QString, QString>> languages = Translator::availableLanguages();
Expand All @@ -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());
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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) {
Expand All @@ -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());
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/gui/ApplicationSettingsWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class ApplicationSettingsWidget : public EditWidget
private slots:
void saveSettings();
void resetSettings();
void importSettings();
void exportSettings();
void reject();
void autoSaveToggled(bool checked);
void hideWindowOnCopyCheckBoxToggled(bool checked);
Expand Down
Loading

0 comments on commit 684122c

Please sign in to comment.