From af1eff03c9e839914aab4109970c4a9f6fac8a99 Mon Sep 17 00:00:00 2001 From: aqua Date: Thu, 8 Sep 2022 10:27:30 +0300 Subject: RekonqSettings: add resetValue and remove value's defaultValue parameter - generate default rekonqrc and include it in libsettings - Settings uses :/settings/rekonqrc to provide default values - Add Settings::path() to get the default settings location --- src/settings/CMakeLists.txt | 13 ++++- src/settings/settings.cpp | 51 +++++++++++++++++-- src/settings/settings.hpp | 14 ++++-- src/settings/settings.qrc | 7 +++ src/settings/settingsdialog.cpp | 16 +++--- src/settings/settingswidget.cpp | 42 ---------------- src/settings/settingswidgets.hpp | 6 ++- src/settings/test/rekonqrc | 37 -------------- src/settings/test/settings_mock.hpp | 3 +- src/settings/test/test_settings.cpp | 82 +++++++++++++++++++++++-------- src/settings/test/test_settings.qrc | 7 --- src/settings/test/test_settingsdialog.cpp | 9 +--- 12 files changed, 152 insertions(+), 135 deletions(-) create mode 100644 src/settings/settings.qrc delete mode 100644 src/settings/test/rekonqrc delete mode 100644 src/settings/test/test_settings.qrc (limited to 'src/settings') diff --git a/src/settings/CMakeLists.txt b/src/settings/CMakeLists.txt index 712fd57a..38a35cf6 100644 --- a/src/settings/CMakeLists.txt +++ b/src/settings/CMakeLists.txt @@ -15,11 +15,20 @@ add_custom_command(OUTPUT shortcutssettingswidget.cpp DEPENDS ${PROJECT_SOURCE_D --group=Shortcuts --output=shortcutssettingswidget.cpp ${PROJECT_SOURCE_DIR}/src/rekonq.kcfg) +# generate rekonqrc +execute_process( + COMMAND python3 ${PROJECT_SOURCE_DIR}/scripts/rekonf.py --group=all --output=rekonqrc ${PROJECT_SOURCE_DIR}/src/rekonq.kcfg + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + #OUTPUT rekonqrc + #DEPENDS ${PROJECT_SOURCE_DIR}/scripts/rekonf.py ${PROJECT_SOURCE_DIR}/src/rekonq.kcfg +) + add_library(settings STATIC ${PROJECT_SOURCE_DIR}/include/rsettings.hpp settings.cpp settings.hpp settingsdialog.cpp settingsdialog.h settingsdialog.ui settingswidgets.hpp settingswidget.cpp helpers.hpp generalsettingswidget.cpp appearancesettingswidget.cpp networksettingswidget.cpp shortcutssettingswidget.cpp + settings.qrc rekonqrc ) target_link_libraries(settings PUBLIC Qt6::Widgets) @@ -27,7 +36,7 @@ IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") add_executable(test_settingsdialog test/test_settingsdialog.cpp test/settings_mock.hpp) target_link_libraries(test_settingsdialog GTest::gmock settings) - add_executable(test_settings test/test_settings.cpp test/test_settings.qrc test/settings_mock.hpp) + add_executable(test_settings test/test_settings.cpp test/settings_mock.hpp) target_link_libraries(test_settings PRIVATE GTest::gtest GTest::gmock settings) - gtest_discover_tests(test_settings EXTRA_ARGS rekonqrc) + gtest_discover_tests(test_settings) endif() diff --git a/src/settings/settings.cpp b/src/settings/settings.cpp index 190bc977..d7216b2e 100644 --- a/src/settings/settings.cpp +++ b/src/settings/settings.cpp @@ -8,23 +8,66 @@ * ============================================================ */ #include "settings.hpp" +#include "../rekonq.hpp" +#include "helpers.hpp" +#include #include +#include + +QString Settings::path() +{ + return QDir(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)).filePath("rekonqrc"); +} Settings::Settings(const QString &path, QObject *parent) : RekonqSettings(parent) { d = new QSettings(path, QSettings::IniFormat, this); + b = new QSettings(":/settings/rekonqrc", QSettings::IniFormat, this); } -void Settings::beginGroup(const QString &prefix) { d->beginGroup(prefix); } +Settings::~Settings() +{ + delete d; + delete b; +} -void Settings::endGroup() { d->endGroup(); } +void Settings::beginGroup(const QString &prefix) +{ + d->beginGroup(prefix); + b->beginGroup(prefix); +} + +void Settings::endGroup() +{ + d->endGroup(); + b->endGroup(); +} void Settings::setValue(const QString &key, const QVariant &value) { - d->setValue(key, value); + if (value == b->value(key)) d->remove(key); + else + d->setValue(key, value); emit changed(key, value); } -QVariant Settings::value(const QString &key, const QVariant &defaultValue) const { return d->value(key, defaultValue); } +void Settings::resetValue(const QString &key) { d->remove(key); } + +QVariant Settings::value(const QString &key) const +{ + auto v = d->value(key); + if (v.isValid()) return v; + + if (key == QL1S("standardFontFamily")) return getFont(QFont::System).family(); + if (key == QL1S("fixedFontFamily")) return getFont(QFont::Monospace).family(); + if (key == QL1S("serifFontFamily")) return getFont(QFont::Times).family(); + if (key == QL1S("sansSerifFontFamily")) return getFont(QFont::Helvetica).family(); + if (key == QL1S("cursiveFontFamily")) return getFont(QFont::Cursive).family(); + if (key == QL1S("fantasyFontFamily")) return getFont(QFont::Fantasy).family(); + + v = b->value(key); + Q_ASSERT_X(v.isValid(), __PRETTY_FUNCTION__, qUtf8Printable(key)); + return v; +} QString Settings::filePath() const { return d->fileName(); } diff --git a/src/settings/settings.hpp b/src/settings/settings.hpp index 713ce38d..8d413985 100644 --- a/src/settings/settings.hpp +++ b/src/settings/settings.hpp @@ -12,22 +12,28 @@ #include class QSettings; -class Settings final : public RekonqSettings { +class Settings : public RekonqSettings { Q_OBJECT public: + [[nodiscard]] static QString path(); + explicit Settings(const QString &settingsPath, QObject *parent = nullptr); - ~Settings() override = default; + ~Settings() override; void beginGroup(const QString &prefix) override; void endGroup() override; void setValue(const QString &key, const QVariant &value) override; - [[nodiscard]] QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const override; + void resetValue(const QString &key) override; + [[nodiscard]] QVariant value(const QString &key) const override; [[nodiscard]] QString filePath() const override; +protected: + QSettings *d; + QSettings *b; + private: Q_DISABLE_COPY_MOVE(Settings) - QSettings *d; }; diff --git a/src/settings/settings.qrc b/src/settings/settings.qrc new file mode 100644 index 00000000..71e19674 --- /dev/null +++ b/src/settings/settings.qrc @@ -0,0 +1,7 @@ + + + + + rekonqrc + + diff --git a/src/settings/settingsdialog.cpp b/src/settings/settingsdialog.cpp index 68fa7a26..66a47140 100644 --- a/src/settings/settingsdialog.cpp +++ b/src/settings/settingsdialog.cpp @@ -23,7 +23,7 @@ SettingsDialog::SettingsDialog(RekonqSettings *settings, QWidget *parent) : QDia restoreDefaultsBtn = ui->buttonBox->button(QDialogButtonBox::RestoreDefaults); Q_CHECK_PTR(restoreDefaultsBtn); - if (!settings->value("FirstRun", true).toBool()) saveBtn->setEnabled(false); + if (!settings->value("FirstRun").toBool()) saveBtn->setEnabled(false); addPage(new GeneralSettingsWidget(settings, this)); addPage(new AppearanceSettingsWidget(settings, this)); @@ -32,16 +32,14 @@ SettingsDialog::SettingsDialog(RekonqSettings *settings, QWidget *parent) : QDia connect(ui->listWidget, &QListWidget::currentRowChanged, ui->stackedWidget, &QStackedWidget::setCurrentIndex); - connect(restoreDefaultsBtn, &QPushButton::clicked, this, [this]() { - for (auto *w : ui->stackedWidget->findChildren(QString(), Qt::FindDirectChildrenOnly)) { - w->reset(); - } + connect(restoreDefaultsBtn, &QPushButton::clicked, this, [this, settings]() { + for (auto *w : ui->stackedWidget->findChildren(QString(), Qt::FindDirectChildrenOnly)) w->reset(); + settings->setValue("FirstRun", false); + close(); }); connect(this, &QDialog::accepted, this, [this]() { - for (auto *w : ui->stackedWidget->findChildren(QString(), Qt::FindDirectChildrenOnly)) { - w->save(); - } + for (auto *w : ui->stackedWidget->findChildren(QString(), Qt::FindDirectChildrenOnly)) w->save(); }); } @@ -54,4 +52,4 @@ void SettingsDialog::addPage(SettingsWidget *page) ui->stackedWidget->addWidget(page); connect(page, &SettingsWidget::changed, this, [this]() { saveBtn->setEnabled(true); }); -} \ No newline at end of file +} diff --git a/src/settings/settingswidget.cpp b/src/settings/settingswidget.cpp index b5a2432c..60f2bf62 100644 --- a/src/settings/settingswidget.cpp +++ b/src/settings/settingswidget.cpp @@ -37,45 +37,3 @@ void SettingsWidget::save() if (objectName() != QLatin1String("General")) m_settings->endGroup(); } - -void SettingsWidget::reset() -{ - if (objectName() != QLatin1String("General")) m_settings->beginGroup(objectName()); - - // Int - for (auto *spinbox : findChildren(QString(), Qt::FindDirectChildrenOnly)) { - const auto value = spinbox->property("defaultValue"); - spinbox->setValue(value.toInt()); - m_settings->setValue(spinbox->objectName(), value); - } - - // Bool - for (auto *checkbox : findChildren(QString(), Qt::FindDirectChildrenOnly)) { - const auto value = checkbox->property("defaultValue"); - checkbox->setChecked(value.toBool()); - m_settings->setValue(checkbox->objectName(), value); - } - - // String - for (auto *lineedit : findChildren(QString(), Qt::FindDirectChildrenOnly)) { - const auto value = lineedit->property("defaultValue"); - lineedit->setText(value.toString()); - m_settings->setValue(lineedit->objectName(), value); - } - - // Font - for (auto *font : findChildren(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(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 cb08b591..532a5683 100644 --- a/src/settings/settingswidgets.hpp +++ b/src/settings/settingswidgets.hpp @@ -27,7 +27,7 @@ signals: public slots: void save(); - void reset(); + virtual void reset() = 0; protected: RekonqSettings *m_settings; @@ -38,6 +38,7 @@ class GeneralSettingsWidget final : public SettingsWidget { public: explicit GeneralSettingsWidget(RekonqSettings *, QWidget *parent = nullptr); ~GeneralSettingsWidget() override = default; + void reset() override; }; class AppearanceSettingsWidget final : public SettingsWidget { @@ -45,6 +46,7 @@ class AppearanceSettingsWidget final : public SettingsWidget { public: explicit AppearanceSettingsWidget(RekonqSettings *, QWidget *parent = nullptr); ~AppearanceSettingsWidget() override = default; + void reset() override; }; class NetworkSettingsWidget final : public SettingsWidget { @@ -52,6 +54,7 @@ class NetworkSettingsWidget final : public SettingsWidget { public: explicit NetworkSettingsWidget(RekonqSettings *, QWidget *parent = nullptr); ~NetworkSettingsWidget() override = default; + void reset() override; }; class ShortcutsSettingsWidget final : public SettingsWidget { @@ -59,4 +62,5 @@ class ShortcutsSettingsWidget final : public SettingsWidget { public: explicit ShortcutsSettingsWidget(RekonqSettings *, QWidget *parent = nullptr); ~ShortcutsSettingsWidget() override = default; + void reset() override; }; diff --git a/src/settings/test/rekonqrc b/src/settings/test/rekonqrc deleted file mode 100644 index fe67194c..00000000 --- a/src/settings/test/rekonqrc +++ /dev/null @@ -1,37 +0,0 @@ -[General] -FirstRun=true -lang=TODO: change type to StringList -homepage=about:blank -newtab=about:blank -searchUrl=https://duckduckgo.com/?q=%1 -pluginPath=TODO: change type to Path - -[Network] -downloadPath=TODO: change type to Path -downloadPathAsk=true -userAgent=TODO - -[Appearance] -IconTheme=tabler -defaultFontSize=16 -minFontSize=7 -defaultEncoding=ISO 8859-1 -defaultZoom=10 - -[Shortcuts] -actionShowSidebar=Ctrl+B -actionShowSearchBar=Ctrl+F -actionSettings=Ctrl+S -actionQuit=Ctrl+Q -actionNewTab=Ctrl+T -actionCloseTab=Ctrl+W -actionSwitchTabLeft=Ctrl+Left -actionSwitchTabRight=Ctrl+Right -actionFocusAddressBar=F6 -actionBack=Alt+Left -actionForward=Alt+Right -actionRefresh=F5 -actionReload=Ctrl+F5 -actionOpen=Ctrl+O -actionBookmark=Ctrl+D - diff --git a/src/settings/test/settings_mock.hpp b/src/settings/test/settings_mock.hpp index bc3fbc2f..bf0e137a 100644 --- a/src/settings/test/settings_mock.hpp +++ b/src/settings/test/settings_mock.hpp @@ -21,7 +21,8 @@ public: MOCK_METHOD(void, endGroup, (), (override)); MOCK_METHOD(void, setValue, (const QString &, const QVariant &), (override)); - MOCK_METHOD(QVariant, value, (const QString &, const QVariant &), (const, override)); + MOCK_METHOD(void, resetValue, (const QString &), (override)); + MOCK_METHOD(QVariant, value, (const QString &), (const, override)); MOCK_METHOD(QString, filePath, (), (const, override)); }; diff --git a/src/settings/test/test_settings.cpp b/src/settings/test/test_settings.cpp index 6efc64c3..a797a224 100644 --- a/src/settings/test/test_settings.cpp +++ b/src/settings/test/test_settings.cpp @@ -7,9 +7,10 @@ #include #include -#include +#include #include #include +#include #include #include @@ -19,9 +20,10 @@ #include "../settingsdialog.h" #include "settings_mock.hpp" -using ::testing::_; +using ::testing::_; // NOLINT(bugprone-reserved-identifier) using ::testing::AtLeast; using ::testing::ContainerEq; +using ::testing::Return; using ::testing::ReturnArg; MATCHER_P(QStringEq, a, "") @@ -32,7 +34,7 @@ MATCHER_P(QStringEq, a, "") MATCHER_P(QVariantEq, a, "") { *result_listener << "where the arg is " << qUtf8Printable(arg.toString()); - return arg.toString().compare(a) == 0; + return arg == QVariant(a); } TEST(settings, getFont) @@ -46,15 +48,30 @@ TEST(settings, getFont) TEST(settings, settingsPath) { - const auto path = QDir(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)).filePath("rekonqrc"); + const auto path = Settings::path(); EXPECT_FALSE(path.isEmpty()); EXPECT_TRUE(path.endsWith("rekonqrc")); + + QFile defaultSettingsPath(":/settings/rekonqrc"); + EXPECT_TRUE(defaultSettingsPath.exists()); } +class TestSettings : public Settings { +public: + TestSettings(const QString &path = QString()) : Settings(path, nullptr){}; + ~TestSettings() override = default; + + [[nodiscard]] auto groups() const { return d->childGroups(); } + [[nodiscard]] auto keys() const { return d->childKeys(); } +}; + TEST(settings, Settings) { - Settings settings(":rekonqrc"); - EXPECT_THAT(settings.filePath(), QStringEq(":rekonqrc")); + TestSettings settings; + EXPECT_TRUE(settings.filePath().isEmpty()); + + EXPECT_TRUE(settings.groups().isEmpty()); + EXPECT_TRUE(settings.keys().isEmpty()); const auto FirstRun = settings.value("FirstRun"); EXPECT_TRUE(FirstRun.isValid()); @@ -63,6 +80,9 @@ TEST(settings, Settings) settings.setValue("FirstRun", false); EXPECT_FALSE(settings.value("FirstRun").toBool()); + EXPECT_TRUE(settings.groups().isEmpty()); + EXPECT_EQ(settings.keys().count(), 1); + settings.beginGroup("Network"); const auto downloadPathAsk = settings.value("downloadPathAsk"); EXPECT_TRUE(downloadPathAsk.isValid()); @@ -72,9 +92,12 @@ TEST(settings, Settings) const auto searchUrl = settings.value("searchUrl"); EXPECT_TRUE(searchUrl.isValid()); EXPECT_EQ(searchUrl.toString(), QString("https://duckduckgo.com/?q=%1")); + + EXPECT_TRUE(settings.groups().isEmpty()); + EXPECT_EQ(settings.keys().count(), 1); } -TEST(settings, SettingsDialog) +TEST(settings, SettingsDialog_mock) { constexpr unsigned n_settings = 36; // there are 36 settings in total MockSettings mockSettings; @@ -82,16 +105,20 @@ TEST(settings, SettingsDialog) // beginGroup/endGroup are called twice: during the ctor and when accepted EXPECT_CALL(mockSettings, beginGroup).Times(3 * 4); EXPECT_CALL(mockSettings, endGroup).Times(3 * 4); - EXPECT_CALL(mockSettings, value).Times(n_settings * 2).WillRepeatedly(ReturnArg<1>()); - // 1 setting is hidden and won't be set by the dialog - // save and reset will both call setValue on all non-hidden settings - EXPECT_CALL(mockSettings, setValue(_, _)).Times(n_settings * 2 - 3); + EXPECT_CALL(mockSettings, value).Times(n_settings * 2 - 2).WillRepeatedly(ReturnArg<0>()); + EXPECT_CALL(mockSettings, value(QStringEq("homepage"))).Times(2).WillRepeatedly(Return(QVariant("about:blank"))); + // expect accept to call setValue on all non-hidden settings + EXPECT_CALL(mockSettings, setValue(_, _)).Times(n_settings - 2); EXPECT_CALL(mockSettings, setValue(QStringEq("homepage"), QVariantEq("https://kde.org"))); + EXPECT_CALL(mockSettings, setValue(QStringEq("FirstRun"), QVariantEq(false))); + // expect resetBtn to call resetValue on all non-hidden settings + EXPECT_CALL(mockSettings, resetValue).Times(n_settings - 1); // change setting { SettingsDialog dlg(&mockSettings); auto *homepage = dlg.findChild("homepage"); + ASSERT_FALSE(homepage == nullptr); EXPECT_TRUE(homepage->text() == QLatin1String("about:blank")) << qUtf8Printable(homepage->text()); homepage->setText("https://kde.org"); dlg.accept(); @@ -101,24 +128,37 @@ TEST(settings, SettingsDialog) { SettingsDialog dlg(&mockSettings); auto *resetBtn = dlg.findChild()->button(QDialogButtonBox::RestoreDefaults); - EXPECT_FALSE(resetBtn == nullptr); + ASSERT_FALSE(resetBtn == nullptr); resetBtn->click(); } } +TEST(settings, SettingsDialog) +{ + const auto path = Settings::path(); + ASSERT_FALSE(QFile::exists(path)); + + { + Settings settings(path); + EXPECT_TRUE(settings.value("FirstRun").toBool()); + + SettingsDialog dlg(&settings); + auto *resetBtn = dlg.findChild()->button(QDialogButtonBox::RestoreDefaults); + ASSERT_FALSE(resetBtn == nullptr); + resetBtn->click(); + } + + ASSERT_TRUE(QFile::exists(path)); + ASSERT_TRUE(QFile::remove(path)); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); + Q_INIT_RESOURCE(settings); - // handling fonts requires a QGuiApplication - // The proper platform name needs to be added to the argument list before the QGuiApplication constructor is called - // This needs to be done here for gtest_discover_tests to work - QList args; - for (int i = 0; i < argc; ++i) args.append(argv[i]); - args.append({"-platform", "offscreen"}); - int args_count = args.count(); - - QApplication app(args_count, args.data()); + QApplication app(argc, argv); + QStandardPaths::setTestModeEnabled(true); return RUN_ALL_TESTS(); } diff --git a/src/settings/test/test_settings.qrc b/src/settings/test/test_settings.qrc deleted file mode 100644 index 16e74fef..00000000 --- a/src/settings/test/test_settings.qrc +++ /dev/null @@ -1,7 +0,0 @@ - - - - - rekonqrc - - diff --git a/src/settings/test/test_settingsdialog.cpp b/src/settings/test/test_settingsdialog.cpp index a50cf307..a89ec82d 100644 --- a/src/settings/test/test_settingsdialog.cpp +++ b/src/settings/test/test_settingsdialog.cpp @@ -5,20 +5,15 @@ * Copyright (C) 2022 aqua * ============================================================ */ +#include "../settings.hpp" #include "../settingsdialog.h" -#include "settings_mock.hpp" #include -using ::testing::AtLeast; -using ::testing::NiceMock; -using ::testing::ReturnArg; - int main(int argc, char **argv) { QApplication app(argc, argv); - NiceMock settings; - EXPECT_CALL(settings, value).WillRepeatedly(ReturnArg<1>()); + Settings settings(Settings::path()); SettingsDialog dlg(&settings); dlg.show(); -- cgit v1.2.1