summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraqua <aqua@iserlohn-fortress.net>2022-08-24 16:38:49 +0300
committeraqua <aqua@iserlohn-fortress.net>2022-08-28 09:49:20 +0300
commitc5ed279da0e74adb79c6c2a3e485cb9668b1c130 (patch)
tree4271dcd3530bec7df25b01190317bee56533df94
parentLoad plugins from AppLocalDataLocation by default (diff)
downloadrekonq-c5ed279da0e74adb79c6c2a3e485cb9668b1c130.tar.xz
SettingsDialog: save settings when changed
- connect Restore Defaults button
-rwxr-xr-xscripts/rekonf.py93
-rw-r--r--src/application.cpp9
-rw-r--r--src/main.cpp5
-rw-r--r--src/settings/CMakeLists.txt2
-rw-r--r--src/settings/settingsdialog.cpp36
-rw-r--r--src/settings/settingsdialog.h5
-rw-r--r--src/settings/settingsdialog.ui32
-rw-r--r--src/settings/settingswidget.cpp81
-rw-r--r--src/settings/settingswidgets.hpp29
-rw-r--r--src/settings/test/test_settings.cpp37
10 files changed, 219 insertions, 110 deletions
diff --git a/scripts/rekonf.py b/scripts/rekonf.py
index 48706c3d..941c29c7 100755
--- a/scripts/rekonf.py
+++ b/scripts/rekonf.py
@@ -13,56 +13,59 @@ import sys
from xml.etree import ElementTree
-def write_int_entry(entry):
- '''Add a QSpinBox connected to an Int entry'''
- obj = entry.attrib['key']
- default = entry.find('{*}default').text
+def write_int_entry(obj, name, default):
+ """Add a QSpinBox connected to an Int (obj, name, default)"""
print(f' auto* { obj } = new QSpinBox(this);')
print(f' { obj }->setValue(s->value("{ obj }", { default }).toInt());')
- print(f' formLayout->addRow(tr("{ entry.attrib["name"] }"), { obj });')
+ print(f' connect({ obj }, &QSpinBox::valueChanged, this, [this]() {{ emit changed(); }});')
+ print(f' formLayout->addRow(tr("{ name }"), { obj });')
-def write_bool_entry(entry):
- '''Add a QCheckBox connected to a Bool entry'''
- obj = entry.attrib['key']
- default = entry.find('{*}default').text
- print(f' auto* { obj } = new QCheckBox(tr("{ entry.attrib["name"] }"), this);')
+def write_bool_entry(obj, name, default):
+ """Add a QCheckBox connected to a Bool (obj, name, default)"""
+ print(f' auto* { obj } = new QCheckBox(tr("{ name }"), this);')
print(f' { obj }->setChecked(s->value("{ obj }", { default }).toBool());')
+ print(f' connect({ obj }, &QCheckBox::stateChanged, this, [this]() {{ emit changed(); }});')
print(f' formLayout->addRow(QString(), { obj });')
-def write_string_entry(entry):
- '''Add a QLineEdit connected to a String entry'''
- obj = entry.attrib['key']
- default = entry.find('{*}default').text
+def write_string_entry(obj, name, default):
+ """Add a QLineEdit connected to a String (obj, name, default)"""
print(f' auto* {obj} = new QLineEdit(this);')
- print(f' {obj}->setText(s->value("{ obj }", "{ default }").toString());')
- print(f' formLayout->addRow(tr("{ entry.attrib["name"] }"), { obj });')
+ print(f' { obj }->setText(s->value("{ obj }", "{ default }").toString());')
+ print(f' connect({ obj }, &QLineEdit::textChanged, this, [this]() {{ emit changed(); }});')
+ print(f' formLayout->addRow(tr("{ name }"), { obj });')
-def write_font_entry(entry):
- '''Add a QFontComboBox connected to a Font entry'''
- obj = entry.attrib['key']
- default = entry.find('{*}default').text
+def write_font_entry(obj, name, default):
+ """Add a QFontComboBox connected to a Font (obj, name, default)"""
print(f' auto* { obj } = new QFontComboBox(this);')
print(f' { obj }->setCurrentFont(s->value("{ obj }", "{ default }").toString());')
- print(f' formLayout->addRow(tr("{ entry.attrib["name"] }"), { obj });')
+ print(f' connect({ obj }, &QFontComboBox::currentFontChanged, this, [this]() {{ emit changed(); }});')
+ print(f' formLayout->addRow(tr("{ name }"), { obj });')
-def write_shortcut_entry(entry):
- '''Add a QKeySequenceEdit connected to a Shortcut entry'''
- obj = entry.attrib['key']
- default = entry.find('{*}default').text
- print(f' auto* { entry.attrib["key"] } = new QKeySequenceEdit(this);')
+def write_shortcut_entry(obj, name, default):
+ """Add a QKeySequenceEdit connected to a Shortcut (obj, name, default)"""
+ print(f' auto* { obj } = new QKeySequenceEdit(this);')
print(f' { obj }->setKeySequence(s->value("{ obj }", "{ default }").toString());')
- print(f' formLayout->addRow(tr("{ entry.attrib["name"] }"), { obj });')
+ print(f' connect({ obj }, &QKeySequenceEdit::keySequenceChanged, this, [this]() {{ emit changed(); }});')
+ print(f' formLayout->addRow(tr("{ name }"), { obj });')
def generate_group_widget(root, group):
- '''Generate a class based on the group name'''
+ """Generate a class based on the group name"""
class_group = group.attrib["name"].replace(' ', '')
class_name = group.attrib["name"].replace(' ', '') + 'SettingsWidget'
+ write_entry_fn = {
+ 'Int': write_int_entry,
+ 'Bool': write_bool_entry,
+ 'String': write_string_entry,
+ 'Font': write_font_entry,
+ 'Shortcut': write_shortcut_entry
+ }
+
# includes
print('// Includes')
print('#include "settingswidgets.hpp"')
@@ -78,8 +81,11 @@ def generate_group_widget(root, group):
print(f'#include <{ include.text }>')
print('')
+ # ctor
print(f'{ class_name }::{ class_name }(RekonqSettings *s, QWidget *parent) : SettingsWidget(s, parent) {{')
- print(f' s->beginGroup("{ class_group }");')
+ print(f' setObjectName("{ class_group }");')
+ if class_group != 'General':
+ print(f' s->beginGroup("{ class_group }");')
print(' auto *formLayout = new QFormLayout;')
print(' setLayout(formLayout);')
print('')
@@ -88,28 +94,22 @@ def generate_group_widget(root, group):
for entry in group.findall('{http://www.kde.org/standards/kcfg/1.0}entry'):
if entry.attrib.get("hidden") == "true":
print(f' // hidden entry { entry.attrib.get("name") }')
- elif entry.attrib['type'] == 'Int':
- write_int_entry(entry)
- elif entry.attrib['type'] == 'Bool':
- write_bool_entry(entry)
- elif entry.attrib['type'] == 'String':
- write_string_entry(entry)
- elif entry.attrib['type'] == 'Font':
- write_font_entry(entry)
- elif entry.attrib['type'] == 'Shortcut':
- write_shortcut_entry(entry)
else:
- print(f'#error entry with unknown type { entry.attrib["type"] }')
+ obj = entry.attrib['key']
+ name = entry.attrib["name"]
+ default = entry.find('{*}default').text
+ write_entry_fn.get(entry.attrib['type'])(obj, name, default)
+ print(f' { obj }->setObjectName("{ obj }");')
+ print(f' { obj }->setProperty("defaultValue", "{ default }");')
print('')
- print(' s->endGroup();')
+ if class_group != 'General':
+ print(' s->endGroup();')
print('}\n')
- print(f'void { class_name }::save() {{ }}')
- print(f'void { class_name }::reset() {{ }}')
-
-def generate_group_ini(root, group):
+def generate_group_ini(group):
+ """Generate settings in ini format for group"""
group_name = group.attrib["name"].replace(' ', '')
print(f'[{ group_name }]')
for entry in group.findall('{http://www.kde.org/standards/kcfg/1.0}entry'):
@@ -122,6 +122,7 @@ def generate_group_ini(root, group):
def main():
+ """main function"""
parser = argparse.ArgumentParser(description='Generate SettingsWidgets')
parser.add_argument('file', type=str, help='kcfg file')
parser.add_argument('--group', type=str, required=True, help='Group')
@@ -134,7 +135,7 @@ def main():
if args.group == 'all':
for group in root.findall('{http://www.kde.org/standards/kcfg/1.0}group'):
- generate_group_ini(root, group)
+ generate_group_ini(group)
else:
for group in root.findall('{http://www.kde.org/standards/kcfg/1.0}group'):
if group.attrib["name"] == args.group:
diff --git a/src/application.cpp b/src/application.cpp
index 814bfab8..a2031de4 100644
--- a/src/application.cpp
+++ b/src/application.cpp
@@ -14,6 +14,7 @@
#include "plugins/rplugininterface.hpp"
#include "rekonqwindow.h"
#include "settings/settings.hpp"
+#include "settings/settingsdialog.h"
#include <QDir>
#include <QPluginLoader>
#include <QStandardPaths>
@@ -33,6 +34,14 @@ Application::Application(int &argc, char *argv[]) : SingleApplication(argc, argv
spdlog::info("Loading rekonq configuration: {}", qUtf8Printable(settingsPath));
m_settings = new Settings(settingsPath, this);
+ if (m_settings->value("FirstRun", true).toBool()) {
+ spdlog::info("First run");
+ if ((new SettingsDialog(m_settings, nullptr))->exec()) {
+ spdlog::info("new settings saved");
+ m_settings->setValue("FirstRun", false);
+ }
+ }
+
// load default plugins
for (const auto &location : QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation)) {
QDir dir(location + "/plugins");
diff --git a/src/main.cpp b/src/main.cpp
index 1d6e30da..51e68716 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -10,9 +10,14 @@
* ============================================================ */
#include "application.hpp"
+#include <spdlog/spdlog.h>
int main(int argc, char **argv)
{
+#ifdef QT_DEBUG
+ spdlog::set_level(spdlog::level::debug);
+#endif
+
// When loading QtWebEngine from a plugin, set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
diff --git a/src/settings/CMakeLists.txt b/src/settings/CMakeLists.txt
index f597cfb9..29a011c1 100644
--- a/src/settings/CMakeLists.txt
+++ b/src/settings/CMakeLists.txt
@@ -18,7 +18,7 @@ add_custom_command(OUTPUT shortcutssettingswidget.cpp DEPENDS ${PROJECT_SOURCE_D
add_library(settings STATIC
${PROJECT_SOURCE_DIR}/include/rsettings.hpp settings.cpp settings.hpp
settingsdialog.cpp settingsdialog.h settingsdialog.ui
- settingswidgets.hpp helpers.hpp
+ settingswidgets.hpp settingswidget.cpp helpers.hpp
generalsettingswidget.cpp appearancesettingswidget.cpp networksettingswidget.cpp shortcutssettingswidget.cpp
)
target_link_libraries(settings PUBLIC Qt6::Widgets)
diff --git a/src/settings/settingsdialog.cpp b/src/settings/settingsdialog.cpp
index 0c54856e..68fa7a26 100644
--- a/src/settings/settingsdialog.cpp
+++ b/src/settings/settingsdialog.cpp
@@ -13,17 +13,45 @@
#include "settingsdialog.h"
#include "settingswidgets.hpp"
#include "ui_settingsdialog.h"
+#include <QPushButton>
SettingsDialog::SettingsDialog(RekonqSettings *settings, QWidget *parent) : QDialog(parent), ui(new Ui::SettingsDialog)
{
ui->setupUi(this);
+ saveBtn = ui->buttonBox->button(QDialogButtonBox::Save);
+ Q_CHECK_PTR(saveBtn);
+ restoreDefaultsBtn = ui->buttonBox->button(QDialogButtonBox::RestoreDefaults);
+ Q_CHECK_PTR(restoreDefaultsBtn);
- ui->stackedWidget->addWidget(new GeneralSettingsWidget(settings, this));
- ui->stackedWidget->addWidget(new AppearanceSettingsWidget(settings, this));
- ui->stackedWidget->addWidget(new NetworkSettingsWidget(settings, this));
- ui->stackedWidget->addWidget(new ShortcutsSettingsWidget(settings, this));
+ if (!settings->value("FirstRun", true).toBool()) saveBtn->setEnabled(false);
+
+ addPage(new GeneralSettingsWidget(settings, this));
+ addPage(new AppearanceSettingsWidget(settings, this));
+ addPage(new NetworkSettingsWidget(settings, this));
+ addPage(new ShortcutsSettingsWidget(settings, this));
connect(ui->listWidget, &QListWidget::currentRowChanged, ui->stackedWidget, &QStackedWidget::setCurrentIndex);
+
+ connect(restoreDefaultsBtn, &QPushButton::clicked, this, [this]() {
+ for (auto *w : ui->stackedWidget->findChildren<SettingsWidget *>(QString(), Qt::FindDirectChildrenOnly)) {
+ w->reset();
+ }
+ });
+
+ connect(this, &QDialog::accepted, this, [this]() {
+ for (auto *w : ui->stackedWidget->findChildren<SettingsWidget *>(QString(), Qt::FindDirectChildrenOnly)) {
+ w->save();
+ }
+ });
}
SettingsDialog::~SettingsDialog() { delete ui; }
+
+void SettingsDialog::addPage(SettingsWidget *page)
+{
+ auto *item = new QListWidgetItem(page->objectName(), ui->listWidget);
+ item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ ui->stackedWidget->addWidget(page);
+
+ connect(page, &SettingsWidget::changed, this, [this]() { saveBtn->setEnabled(true); });
+} \ No newline at end of file
diff --git a/src/settings/settingsdialog.h b/src/settings/settingsdialog.h
index 0c793f9e..433857b3 100644
--- a/src/settings/settingsdialog.h
+++ b/src/settings/settingsdialog.h
@@ -15,6 +15,7 @@
#include <QDialog>
class RekonqSettings;
+class SettingsWidget;
namespace Ui {
class SettingsDialog;
@@ -28,5 +29,9 @@ public:
~SettingsDialog() override;
private:
+ void addPage(SettingsWidget *page);
+
Ui::SettingsDialog *ui;
+ QPushButton *saveBtn;
+ QPushButton *restoreDefaultsBtn;
};
diff --git a/src/settings/settingsdialog.ui b/src/settings/settingsdialog.ui
index 1c19380d..14ab30ef 100644
--- a/src/settings/settingsdialog.ui
+++ b/src/settings/settingsdialog.ui
@@ -33,38 +33,6 @@
<property name="itemAlignment">
<set>Qt::AlignVCenter</set>
</property>
- <item>
- <property name="text">
- <string>General</string>
- </property>
- <property name="textAlignment">
- <set>AlignCenter</set>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Appearance</string>
- </property>
- <property name="textAlignment">
- <set>AlignCenter</set>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Network</string>
- </property>
- <property name="textAlignment">
- <set>AlignCenter</set>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Shortcuts</string>
- </property>
- <property name="textAlignment">
- <set>AlignCenter</set>
- </property>
- </item>
</widget>
</item>
<item>
diff --git a/src/settings/settingswidget.cpp b/src/settings/settingswidget.cpp
new file mode 100644
index 00000000..b5a2432c
--- /dev/null
+++ b/src/settings/settingswidget.cpp
@@ -0,0 +1,81 @@
+#include "settingswidgets.hpp"
+
+#include <QCheckBox>
+#include <QFontComboBox>
+#include <QKeySequenceEdit>
+#include <QLineEdit>
+#include <QSpinBox>
+
+void SettingsWidget::save()
+{
+ if (objectName() != QLatin1String("General")) m_settings->beginGroup(objectName());
+
+ // Int
+ for (const auto *spinbox : findChildren<QSpinBox *>(QString(), Qt::FindDirectChildrenOnly)) {
+ m_settings->setValue(spinbox->objectName(), spinbox->value());
+ }
+
+ // Bool
+ for (const auto *checkbox : findChildren<QCheckBox *>(QString(), Qt::FindDirectChildrenOnly)) {
+ m_settings->setValue(checkbox->objectName(), checkbox->isChecked());
+ }
+
+ // String
+ for (const auto *lineedit : findChildren<QLineEdit *>(QString(), Qt::FindDirectChildrenOnly)) {
+ m_settings->setValue(lineedit->objectName(), lineedit->text());
+ }
+
+ // Font
+ for (const auto *font : findChildren<QFontComboBox *>(QString(), Qt::FindDirectChildrenOnly)) {
+ m_settings->setValue(font->objectName(), font->currentFont().family());
+ }
+
+ // Shortcut
+ for (const auto *shortcut : findChildren<QKeySequenceEdit *>(QString(), Qt::FindDirectChildrenOnly)) {
+ m_settings->setValue(shortcut->objectName(), shortcut->keySequence());
+ }
+
+ if (objectName() != QLatin1String("General")) m_settings->endGroup();
+}
+
+void SettingsWidget::reset()
+{
+ if (objectName() != QLatin1String("General")) m_settings->beginGroup(objectName());
+
+ // Int
+ for (auto *spinbox : findChildren<QSpinBox *>(QString(), Qt::FindDirectChildrenOnly)) {
+ const auto value = spinbox->property("defaultValue");
+ spinbox->setValue(value.toInt());
+ m_settings->setValue(spinbox->objectName(), value);
+ }
+
+ // Bool
+ for (auto *checkbox : findChildren<QCheckBox *>(QString(), Qt::FindDirectChildrenOnly)) {
+ const auto value = checkbox->property("defaultValue");
+ checkbox->setChecked(value.toBool());
+ m_settings->setValue(checkbox->objectName(), value);
+ }
+
+ // String
+ for (auto *lineedit : findChildren<QLineEdit *>(QString(), Qt::FindDirectChildrenOnly)) {
+ const auto value = lineedit->property("defaultValue");
+ lineedit->setText(value.toString());
+ m_settings->setValue(lineedit->objectName(), value);
+ }
+
+ // Font
+ for (auto *font : findChildren<QFontComboBox *>(QString(), Qt::FindDirectChildrenOnly)) {
+ const auto value = font->property("defaultValue");
+ font->setFont(QFont(value.toString()));
+ m_settings->setValue(font->objectName(), value);
+ }
+
+ // Shortcut
+ for (auto *shortcut : findChildren<QKeySequenceEdit *>(QString(), Qt::FindDirectChildrenOnly)) {
+ const auto value = shortcut->property("defaultValue");
+ shortcut->setKeySequence(value.toString());
+ m_settings->setValue(shortcut->objectName(), value);
+ }
+
+ if (objectName() != QLatin1String("General")) m_settings->endGroup();
+} \ No newline at end of file
diff --git a/src/settings/settingswidgets.hpp b/src/settings/settingswidgets.hpp
index 27ebe8a2..25fbe0a4 100644
--- a/src/settings/settingswidgets.hpp
+++ b/src/settings/settingswidgets.hpp
@@ -16,51 +16,42 @@ class SettingsWidget : public QWidget {
Q_OBJECT
public:
- explicit SettingsWidget(RekonqSettings *, QWidget *parent = nullptr) : QWidget(parent) {}
+ explicit SettingsWidget(RekonqSettings *settings, QWidget *parent = nullptr) : QWidget(parent)
+ {
+ m_settings = settings;
+ }
signals:
void changed();
+
public slots:
- virtual void save() = 0;
- virtual void reset() = 0;
+ void save();
+ void reset();
+
+protected:
+ RekonqSettings *m_settings;
};
class GeneralSettingsWidget final : public SettingsWidget {
Q_OBJECT
public:
explicit GeneralSettingsWidget(RekonqSettings *, QWidget *parent = nullptr);
-
-public slots:
- void save() override;
- void reset() override;
};
class AppearanceSettingsWidget final : public SettingsWidget {
Q_OBJECT
public:
explicit AppearanceSettingsWidget(RekonqSettings *, QWidget *parent = nullptr);
-
-public slots:
- void save() override;
- void reset() override;
};
class NetworkSettingsWidget final : public SettingsWidget {
Q_OBJECT
public:
explicit NetworkSettingsWidget(RekonqSettings *, QWidget *parent = nullptr);
-
-public slots:
- void save() override;
- void reset() override;
};
class ShortcutsSettingsWidget final : public SettingsWidget {
Q_OBJECT
public:
explicit ShortcutsSettingsWidget(RekonqSettings *, QWidget *parent = nullptr);
-
-public slots:
- void save() override;
- void reset() override;
};
diff --git a/src/settings/test/test_settings.cpp b/src/settings/test/test_settings.cpp
index 2ca5ba1a..fdb976f6 100644
--- a/src/settings/test/test_settings.cpp
+++ b/src/settings/test/test_settings.cpp
@@ -7,22 +7,34 @@
#include <QApplication>
#include <QDir>
+#include <QLineEdit>
#include <QStandardPaths>
#include <gtest/gtest.h>
-#include <iostream>
-
// Software under Test
#include "../helpers.hpp"
#include "../settings.hpp"
#include "../settingsdialog.h"
#include "settings_mock.hpp"
+using ::testing::_;
using ::testing::AtLeast;
+using ::testing::ContainerEq;
using ::testing::ReturnArg;
const char *settingsFile = nullptr;
+MATCHER_P(QStringEq, a, "")
+{
+ *result_listener << "where the arg is " << qUtf8Printable(arg);
+ return arg.compare(a) == 0;
+}
+MATCHER_P(QVariantEq, a, "")
+{
+ *result_listener << "where the arg is " << qUtf8Printable(arg.toString());
+ return arg.toString().compare(a) == 0;
+}
+
TEST(settings, getFont)
{
const auto serif = getFont(QFont::Serif);
@@ -60,12 +72,21 @@ TEST(settings, Settings)
TEST(settings, SettingsDialog)
{
- MockSettings settings;
- EXPECT_CALL(settings, beginGroup).Times(4);
- EXPECT_CALL(settings, endGroup).Times(4);
- EXPECT_CALL(settings, value).Times(AtLeast(4)).WillRepeatedly(ReturnArg<1>());
-
- SettingsDialog dlg(&settings);
+ MockSettings mockSettings;
+ // There are 4 groups in total, but General should not be calling beginGroup/endGroup
+ // beginGroup/endGroup are called twice: during the ctor and when accepted
+ EXPECT_CALL(mockSettings, beginGroup).Times(3 * 2);
+ EXPECT_CALL(mockSettings, endGroup).Times(3 * 2);
+ // There are 35 settings in total, one of which is hidden and won't be set by the dialog
+ EXPECT_CALL(mockSettings, value).Times(35).WillRepeatedly(ReturnArg<1>());
+ EXPECT_CALL(mockSettings, setValue(_, _)).Times(33);
+ EXPECT_CALL(mockSettings, setValue(QStringEq("homepage"), QVariantEq("about:blank")));
+
+ SettingsDialog dlg(&mockSettings);
+ auto *homepage = dlg.findChild<QLineEdit *>("homepage");
+ EXPECT_TRUE(homepage->text() == QLatin1String("http://www.kde.org/")) << qUtf8Printable(homepage->text());
+ homepage->setText("about:blank");
+ dlg.accept();
}
int main(int argc, char **argv)