From 1ad67de71b01c3d26fa980f021ed1c957809e733 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 7 Dec 2022 00:09:17 -0600 Subject: [PATCH] Settings container --- scwx-qt/scwx-qt.cmake | 2 + .../scwx/qt/settings/settings_container.cpp | 148 ++++++++++++++++++ .../scwx/qt/settings/settings_container.hpp | 50 ++++++ .../scwx/qt/settings/settings_variable.cpp | 17 +- .../scwx/qt/settings/settings_variable.hpp | 13 +- .../qt/settings/settings_container.test.cpp | 32 ++++ test/test.cmake | 3 +- 7 files changed, 251 insertions(+), 14 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/settings/settings_container.cpp create mode 100644 scwx-qt/source/scwx/qt/settings/settings_container.hpp create mode 100644 test/source/scwx/qt/settings/settings_container.test.cpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 14847ec1..b315eb25 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -110,10 +110,12 @@ set(SRC_REQUEST source/scwx/qt/request/nexrad_file_request.cpp) set(HDR_SETTINGS source/scwx/qt/settings/general_settings.hpp source/scwx/qt/settings/map_settings.hpp source/scwx/qt/settings/palette_settings.hpp + source/scwx/qt/settings/settings_container.hpp source/scwx/qt/settings/settings_variable.hpp) set(SRC_SETTINGS source/scwx/qt/settings/general_settings.cpp source/scwx/qt/settings/map_settings.cpp source/scwx/qt/settings/palette_settings.cpp + source/scwx/qt/settings/settings_container.cpp source/scwx/qt/settings/settings_variable.cpp) set(HDR_TYPES source/scwx/qt/types/qt_types.hpp source/scwx/qt/types/radar_product_record.hpp diff --git a/scwx-qt/source/scwx/qt/settings/settings_container.cpp b/scwx-qt/source/scwx/qt/settings/settings_container.cpp new file mode 100644 index 00000000..9e067622 --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/settings_container.cpp @@ -0,0 +1,148 @@ +#define SETTINGS_CONTAINER_IMPLEMENTATION + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +static const std::string logPrefix_ = "scwx::qt::settings::settings_container"; + +template +class SettingsContainer::Impl +{ +public: + explicit Impl() {} + + ~Impl() {} + + T elementDefault_ {}; + std::optional elementMinimum_ {}; + std::optional elementMaximum_ {}; + std::function elementValidator_ {nullptr}; +}; + +template +SettingsContainer::SettingsContainer(const std::string& name) : + SettingsVariable(name), p(std::make_unique()) +{ +} +template +SettingsContainer::~SettingsContainer() = default; + +template +SettingsContainer::SettingsContainer(SettingsContainer&&) noexcept = + default; +template +SettingsContainer& +SettingsContainer::operator=(SettingsContainer&&) noexcept = default; + +template +bool SettingsContainer::SetValueOrDefault(const Container& c) +{ + bool validated = true; + + Container validatedValues; + validatedValues.reserve(c.size()); + + std::transform( + c.cbegin(), + c.cend(), + std::back_inserter(validatedValues), + [&](auto& value) + { + if (ValidateElement(value)) + { + return value; + } + else if (p->elementMinimum_.has_value() && value < p->elementMinimum_) + { + validated = false; + return *p->elementMinimum_; + } + else if (p->elementMaximum_.has_value() && value > p->elementMaximum_) + { + validated = false; + return *p->elementMaximum_; + } + else + { + validated = false; + return p->elementDefault_; + } + }); + + return SettingsVariable::SetValueOrDefault(validatedValues) && + validated; +} + +template +SettingsContainer::T +SettingsContainer::GetElementDefault() const +{ + return p->elementDefault_; +} + +template +void SettingsContainer::SetElementDefault(const T& value) +{ + p->elementDefault_ = value; +} + +template +void SettingsContainer::SetElementMinimum(const T& value) +{ + p->elementMinimum_ = value; +} + +template +void SettingsContainer::SetElementMaximum(const T& value) +{ + p->elementMaximum_ = value; +} + +template +void SettingsContainer::SetElementValidator( + std::function validator) +{ + p->elementValidator_ = validator; +} + +template +bool SettingsContainer::Validate(const Container& c) const +{ + if (!SettingsVariable::Validate(c)) + { + return false; + } + + for (auto& element : c) + { + if (!ValidateElement(element)) + { + return false; + } + } + + return true; +} + +template +bool SettingsContainer::ValidateElement(const T& value) const +{ + return ( + // Validate minimum + (!p->elementMinimum_.has_value() || value >= p->elementMinimum_) && + // Validate maximum + (!p->elementMaximum_.has_value() || value <= p->elementMaximum_) && + // User-validation + (p->elementValidator_ == nullptr || p->elementValidator_(value))); +} + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/settings/settings_container.hpp b/scwx-qt/source/scwx/qt/settings/settings_container.hpp new file mode 100644 index 00000000..44850bfa --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/settings_container.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +template +class SettingsContainer : public SettingsVariable +{ +public: + using T = Container::value_type; + + explicit SettingsContainer(const std::string& name); + ~SettingsContainer(); + + SettingsContainer(const SettingsContainer&) = delete; + SettingsContainer& operator=(const SettingsContainer&) = delete; + + SettingsContainer(SettingsContainer&&) noexcept; + SettingsContainer& operator=(SettingsContainer&&) noexcept; + + bool SetValueOrDefault(const Container& c) override; + + bool Validate(const Container& c) const override; + bool ValidateElement(const T& value) const; + + T GetElementDefault() const; + + void SetElementDefault(const T& value); + void SetElementMinimum(const T& value); + void SetElementMaximum(const T& value); + void SetElementValidator(std::function validator); + +private: + class Impl; + std::unique_ptr p; +}; + +#ifdef SETTINGS_CONTAINER_IMPLEMENTATION +template class SettingsContainer>; +#endif + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable.cpp b/scwx-qt/source/scwx/qt/settings/settings_variable.cpp index fc813c4e..7d2992c1 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable.cpp @@ -20,8 +20,6 @@ public: ~Impl() {} - bool Validate(const T& value); - const std::string name_; T value_ {}; T default_ {}; @@ -62,7 +60,7 @@ bool SettingsVariable::SetValue(const T& value) { bool validated = false; - if (p->Validate(value)) + if (Validate(value)) { p->value_ = value; validated = true; @@ -76,7 +74,7 @@ bool SettingsVariable::SetValueOrDefault(const T& value) { bool validated = false; - if (p->Validate(value)) + if (Validate(value)) { p->value_ = value; validated = true; @@ -108,7 +106,7 @@ bool SettingsVariable::StageValue(const T& value) { bool validated = false; - if (p->Validate(value)) + if (Validate(value)) { p->staged_ = value; validated = true; @@ -158,11 +156,12 @@ void SettingsVariable::SetValidator(std::function validator) } template -bool SettingsVariable::Impl::Validate(const T& value) +bool SettingsVariable::Validate(const T& value) const { - return ((!minimum_.has_value() || value >= minimum_) && // Validate minimum - (!maximum_.has_value() || value <= maximum_) && // Validate maximum - (validator_ == nullptr || validator_(value))); // User-validation + return ( + (!p->minimum_.has_value() || value >= p->minimum_) && // Validate minimum + (!p->maximum_.has_value() || value <= p->maximum_) && // Validate maximum + (p->validator_ == nullptr || p->validator_(value))); // User-validation } } // namespace settings diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable.hpp b/scwx-qt/source/scwx/qt/settings/settings_variable.hpp index 25889230..6032f29f 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable.hpp @@ -26,14 +26,16 @@ public: std::string name() const; - T GetValue() const; - bool SetValue(const T& value); - bool SetValueOrDefault(const T& value); - void SetValueToDefault(); + T GetValue() const; + bool SetValue(const T& value); + virtual bool SetValueOrDefault(const T& value); + void SetValueToDefault(); bool StageValue(const T& value); void Commit(); + virtual bool Validate(const T& value) const; + T GetDefault() const; void SetDefault(const T& value); @@ -50,6 +52,9 @@ private: template class SettingsVariable; template class SettingsVariable; template class SettingsVariable; + +// Containers are not to be used directly +template class SettingsVariable>; #endif } // namespace settings diff --git a/test/source/scwx/qt/settings/settings_container.test.cpp b/test/source/scwx/qt/settings/settings_container.test.cpp new file mode 100644 index 00000000..dcaab1b5 --- /dev/null +++ b/test/source/scwx/qt/settings/settings_container.test.cpp @@ -0,0 +1,32 @@ +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +TEST(SettingsContainerTest, Integer) +{ + SettingsContainer> intContainer { + "std::vector"}; + intContainer.SetDefault({42, 5, 63}); + intContainer.SetElementMinimum(4); + intContainer.SetElementMaximum(70); + intContainer.SetValueToDefault(); + + EXPECT_EQ(intContainer.name(), "std::vector"); + EXPECT_THAT(intContainer.GetValue(), ::testing::ElementsAre(42, 5, 63)); + EXPECT_EQ(intContainer.SetValueOrDefault({50, 0, 80}), false); + EXPECT_THAT(intContainer.GetValue(), ::testing::ElementsAre(50, 4, 70)); + EXPECT_EQ(intContainer.SetValueOrDefault({10, 20, 30}), true); + EXPECT_THAT(intContainer.GetValue(), ::testing::ElementsAre(10, 20, 30)); +} + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/test/test.cmake b/test/test.cmake index 9843c2f0..fcae73d7 100644 --- a/test/test.cmake +++ b/test/test.cmake @@ -23,7 +23,8 @@ set(SRC_QT_CONFIG_TESTS source/scwx/qt/config/county_database.test.cpp source/scwx/qt/config/radar_site.test.cpp) set(SRC_QT_MANAGER_TESTS source/scwx/qt/manager/settings_manager.test.cpp) set(SRC_QT_MODEL_TESTS source/scwx/qt/model/imgui_context_model.test.cpp) -set(SRC_QT_SETTINGS_TESTS source/scwx/qt/settings/settings_variable.test.cpp) +set(SRC_QT_SETTINGS_TESTS source/scwx/qt/settings/settings_container.test.cpp + source/scwx/qt/settings/settings_variable.test.cpp) set(SRC_UTIL_TESTS source/scwx/util/float.test.cpp source/scwx/util/rangebuf.test.cpp source/scwx/util/streams.test.cpp