Adding map settings

This commit is contained in:
Dan Paulat 2022-06-08 23:31:39 -05:00
parent 0ab89060e9
commit bcf2d7bffc
7 changed files with 330 additions and 30 deletions

View file

@ -76,8 +76,10 @@ set(SRC_MAP source/scwx/qt/map/color_table_layer.cpp
set(HDR_REQUEST source/scwx/qt/request/nexrad_file_request.hpp)
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)
set(SRC_SETTINGS source/scwx/qt/settings/general_settings.cpp
source/scwx/qt/settings/map_settings.cpp
source/scwx/qt/settings/palette_settings.cpp)
set(HDR_TYPES source/scwx/qt/types/radar_product_record.hpp)
set(SRC_TYPES source/scwx/qt/types/radar_product_record.cpp)

View file

@ -20,7 +20,12 @@ namespace SettingsManager
static const std::string logPrefix_ = "scwx::qt::manager::settings_manager";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
static const std::string kGeneralKey = "general";
static const std::string kMapKey = "maps";
static const std::string kPaletteKey = "palette";
static std::shared_ptr<settings::GeneralSettings> generalSettings_ = nullptr;
static std::shared_ptr<settings::MapSettings> mapSettings_ = nullptr;
static std::shared_ptr<settings::PaletteSettings> paletteSettings_ = nullptr;
static boost::json::value ConvertSettingsToJson();
@ -79,6 +84,11 @@ std::shared_ptr<settings::GeneralSettings> general_settings()
return generalSettings_;
}
std::shared_ptr<settings::MapSettings> map_settings()
{
return mapSettings_;
}
std::shared_ptr<settings::PaletteSettings> palette_settings()
{
return paletteSettings_;
@ -88,8 +98,9 @@ static boost::json::value ConvertSettingsToJson()
{
boost::json::object settingsJson;
settingsJson["general"] = generalSettings_->ToJson();
settingsJson["palette"] = paletteSettings_->ToJson();
settingsJson[kGeneralKey] = generalSettings_->ToJson();
settingsJson[kMapKey] = mapSettings_->ToJson();
settingsJson[kPaletteKey] = paletteSettings_->ToJson();
return settingsJson;
}
@ -99,6 +110,7 @@ static void GenerateDefaultSettings()
logger_->info("Generating default settings");
generalSettings_ = settings::GeneralSettings::Create();
mapSettings_ = settings::MapSettings::Create();
paletteSettings_ = settings::PaletteSettings::Create();
}
@ -109,9 +121,11 @@ static bool LoadSettings(const boost::json::object& settingsJson)
bool jsonDirty = false;
generalSettings_ = settings::GeneralSettings::Load(
settingsJson.if_contains("general"), jsonDirty);
settingsJson.if_contains(kGeneralKey), jsonDirty);
mapSettings_ =
settings::MapSettings::Load(settingsJson.if_contains(kMapKey), jsonDirty);
paletteSettings_ = settings::PaletteSettings::Load(
settingsJson.if_contains("palette"), jsonDirty);
settingsJson.if_contains(kPaletteKey), jsonDirty);
return jsonDirty;
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <scwx/qt/settings/general_settings.hpp>
#include <scwx/qt/settings/map_settings.hpp>
#include <scwx/qt/settings/palette_settings.hpp>
namespace scwx
@ -16,6 +17,7 @@ void Initialize();
void ReadSettings(const std::string& settingsPath);
std::shared_ptr<settings::GeneralSettings> general_settings();
std::shared_ptr<settings::MapSettings> map_settings();
std::shared_ptr<settings::PaletteSettings> palette_settings();
} // namespace SettingsManager

View file

@ -0,0 +1,222 @@
#include <scwx/qt/settings/map_settings.hpp>
#include <scwx/qt/config/radar_site.hpp>
#include <scwx/qt/util/json.hpp>
#include <scwx/common/products.hpp>
#include <scwx/util/logger.hpp>
#include <array>
#include <execution>
namespace scwx
{
namespace qt
{
namespace settings
{
static const std::string logPrefix_ = "scwx::qt::settings::map_settings";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
static constexpr size_t kCount_ = 4u;
static const std::string kDefaultRadarSite_ = "KLSX";
static const std::string kDefaultRadarProductGroup_ = "L3";
static const std::array<std::string, kCount_> kDefaultRadarProduct_ {
"N0B", "N0G", "N0C", "N0X"};
class MapSettingsImpl
{
public:
struct MapData
{
std::string radarSite_;
std::string radarProductGroup_;
std::string radarProduct_;
};
explicit MapSettingsImpl() { SetDefaults(); }
~MapSettingsImpl() {}
void SetDefaults(size_t i)
{
map_[i].radarSite_ = kDefaultRadarSite_;
map_[i].radarProductGroup_ = kDefaultRadarProductGroup_;
map_[i].radarProduct_ = kDefaultRadarProduct_[i];
}
void SetDefaults()
{
for (size_t i = 0; i < kCount_; i++)
{
SetDefaults(i);
}
}
std::array<MapData, kCount_> map_;
};
MapSettings::MapSettings() : p(std::make_unique<MapSettingsImpl>()) {}
MapSettings::~MapSettings() = default;
MapSettings::MapSettings(MapSettings&&) noexcept = default;
MapSettings& MapSettings::operator=(MapSettings&&) noexcept = default;
size_t MapSettings::count() const
{
return kCount_;
}
std::string MapSettings::radar_site(size_t i) const
{
return p->map_[i].radarSite_;
}
std::string MapSettings::radar_product_group(size_t i) const
{
return p->map_[i].radarProductGroup_;
}
std::string MapSettings::radar_product(size_t i) const
{
return p->map_[i].radarProduct_;
}
boost::json::value MapSettings::ToJson() const
{
boost::json::value json;
json = boost::json::value_from(p->map_);
return json;
}
std::shared_ptr<MapSettings> MapSettings::Create()
{
std::shared_ptr<MapSettings> generalSettings =
std::make_shared<MapSettings>();
generalSettings->p->SetDefaults();
return generalSettings;
}
std::shared_ptr<MapSettings> MapSettings::Load(const boost::json::value* json,
bool& jsonDirty)
{
std::shared_ptr<MapSettings> mapSettings = std::make_shared<MapSettings>();
if (json != nullptr && json->is_array())
{
const boost::json::array& mapArray = json->as_array();
for (size_t i = 0; i < kCount_; ++i)
{
if (i < mapArray.size() && mapArray.at(i).is_object())
{
const boost::json::object& mapRecord = mapArray.at(i).as_object();
MapSettingsImpl::MapData& mapRecordSettings =
mapSettings->p->map_[i];
// Load JSON Elements
jsonDirty |=
!util::json::FromJsonString(mapRecord,
"radar_site",
mapRecordSettings.radarSite_,
kDefaultRadarSite_);
jsonDirty |=
!util::json::FromJsonString(mapRecord,
"radar_product_group",
mapRecordSettings.radarProductGroup_,
kDefaultRadarSite_);
jsonDirty |=
!util::json::FromJsonString(mapRecord,
"radar_product",
mapRecordSettings.radarProduct_,
kDefaultRadarSite_);
// Validate Radar Site
if (config::RadarSite::Get(mapRecordSettings.radarSite_) == nullptr)
{
mapRecordSettings.radarSite_ = kDefaultRadarSite_;
jsonDirty = true;
}
// Validate Radar Product Group
common::RadarProductGroup radarProductGroup =
common::GetRadarProductGroup(
mapRecordSettings.radarProductGroup_);
if (radarProductGroup == common::RadarProductGroup::Unknown)
{
mapRecordSettings.radarProductGroup_ =
kDefaultRadarProductGroup_;
radarProductGroup =
common::GetRadarProductGroup(kDefaultRadarProductGroup_);
jsonDirty = true;
}
// Validate Radar Product
if (radarProductGroup == common::RadarProductGroup::Level2 &&
common::GetLevel2Product(mapRecordSettings.radarProduct_) ==
common::Level2Product::Unknown)
{
mapRecordSettings.radarProductGroup_ =
kDefaultRadarProductGroup_;
mapRecordSettings.radarProduct_ = kDefaultRadarProduct_[i];
jsonDirty = true;
}
// TODO: Validate level 3 product
}
else
{
logger_->warn(
"Too few array entries, resetting record {} to defaults", i + 1);
jsonDirty = true;
mapSettings->p->SetDefaults(i);
}
}
}
else
{
if (json == nullptr)
{
logger_->warn("Key is not present, resetting to defaults");
}
else if (!json->is_array())
{
logger_->warn("Invalid json, resetting to defaults");
}
mapSettings->p->SetDefaults();
jsonDirty = true;
}
return mapSettings;
}
void tag_invoke(boost::json::value_from_tag,
boost::json::value& jv,
const MapSettingsImpl::MapData& data)
{
jv = {{"radar_site", data.radarSite_},
{"radar_product_group", data.radarProductGroup_},
{"radar_product", data.radarProduct_}};
}
bool operator==(const MapSettings& lhs, const MapSettings& rhs)
{
return (lhs.p->map_ == rhs.p->map_);
}
bool operator==(const MapSettingsImpl::MapData& lhs,
const MapSettingsImpl::MapData& rhs)
{
return (lhs.radarSite_ == rhs.radarSite_ &&
lhs.radarProductGroup_ == rhs.radarProductGroup_ &&
lhs.radarProduct_ == rhs.radarProduct_);
}
} // namespace settings
} // namespace qt
} // namespace scwx

View file

@ -0,0 +1,48 @@
#pragma once
#include <memory>
#include <string>
#include <boost/json.hpp>
namespace scwx
{
namespace qt
{
namespace settings
{
class MapSettingsImpl;
class MapSettings
{
public:
explicit MapSettings();
~MapSettings();
MapSettings(const MapSettings&) = delete;
MapSettings& operator=(const MapSettings&) = delete;
MapSettings(MapSettings&&) noexcept;
MapSettings& operator=(MapSettings&&) noexcept;
size_t count() const;
std::string radar_site(size_t i) const;
std::string radar_product_group(size_t i) const;
std::string radar_product(size_t i) const;
boost::json::value ToJson() const;
static std::shared_ptr<MapSettings> Create();
static std::shared_ptr<MapSettings> Load(const boost::json::value* json,
bool& jsonDirty);
friend bool operator==(const MapSettings& lhs, const MapSettings& rhs);
private:
std::unique_ptr<MapSettingsImpl> p;
};
} // namespace settings
} // namespace qt
} // namespace scwx

@ -1 +1 @@
Subproject commit 288b2cb9b2dd540d44f684229973a97e61c79911
Subproject commit e1aea58dcbb7ad961b974a6a00a83971031f4e0b

View file

@ -1,4 +1,5 @@
#include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/config/radar_site.hpp>
#include <filesystem>
#include <fstream>
@ -17,8 +18,20 @@ static const std::string DEFAULT_SETTINGS_FILE =
static const std::string TEMP_SETTINGS_FILE =
std::string(SCWX_TEST_DATA_DIR) + "/json/settings/settings-temp.json";
class SettingsManagerTest : public testing::Test
{
virtual void SetUp() { scwx::qt::config::RadarSite::Initialize(); }
};
class DefaultSettingsTest : public testing::TestWithParam<std::string>
{
virtual void SetUp() { scwx::qt::config::RadarSite::Initialize(); }
};
class BadSettingsTest :
public testing::TestWithParam<std::pair<std::string, std::string>>
{
virtual void SetUp() { scwx::qt::config::RadarSite::Initialize(); }
};
void VerifyDefaults()
@ -45,8 +58,10 @@ void CompareFiles(const std::string& file1, const std::string& file2)
EXPECT_EQ(buffer1.str(), buffer2.str());
}
TEST(SettingsManager, CreateJson)
TEST_F(SettingsManagerTest, CreateJson)
{
scwx::qt::config::RadarSite::Initialize();
std::string filename {TEMP_SETTINGS_FILE};
// Verify file doesn't exist prior to test start
@ -63,7 +78,7 @@ TEST(SettingsManager, CreateJson)
EXPECT_EQ(std::filesystem::exists(filename), false);
}
TEST(SettingsManager, SettingsKeax)
TEST_F(SettingsManagerTest, SettingsKeax)
{
std::string filename(std::string(SCWX_TEST_DATA_DIR) +
"/json/settings/settings-keax.json");
@ -71,6 +86,10 @@ TEST(SettingsManager, SettingsKeax)
SettingsManager::ReadSettings(filename);
EXPECT_EQ(SettingsManager::general_settings()->default_radar_site(), "KEAX");
for (size_t i = 0; i < SettingsManager::map_settings()->count(); ++i)
{
EXPECT_EQ(SettingsManager::map_settings()->radar_site(i), "KEAX");
}
}
TEST_P(DefaultSettingsTest, DefaultSettings)
@ -95,39 +114,32 @@ INSTANTIATE_TEST_SUITE_P(SettingsManager,
"settings-empty-groups.json",
"settings-empty-object.json"));
TEST(SettingsManager, SettingsBadMinimum)
TEST_P(BadSettingsTest, BadSettings)
{
std::string minimumFile(std::string(SCWX_TEST_DATA_DIR) +
"/json/settings/settings-minimum.json");
std::string sourceFile(std::string(SCWX_TEST_DATA_DIR) +
"/json/settings/settings-bad-minimum.json");
std::string filename {TEMP_SETTINGS_FILE};
auto& [goodFilename, badFilename] = GetParam();
const std::string goodFile(std::string(SCWX_TEST_DATA_DIR) +
"/json/settings/" + goodFilename);
const std::string sourceFile(std::string(SCWX_TEST_DATA_DIR) +
"/json/settings/" + badFilename);
const std::string filename {TEMP_SETTINGS_FILE};
std::filesystem::copy_file(sourceFile, filename);
SettingsManager::ReadSettings(filename);
CompareFiles(filename, minimumFile);
CompareFiles(filename, goodFile);
std::filesystem::remove(filename);
}
TEST(SettingsManager, SettingsBadMaximum)
{
std::string maximumFile(std::string(SCWX_TEST_DATA_DIR) +
"/json/settings/settings-maximum.json");
std::string sourceFile(std::string(SCWX_TEST_DATA_DIR) +
"/json/settings/settings-bad-maximum.json");
std::string filename {TEMP_SETTINGS_FILE};
std::filesystem::copy_file(sourceFile, filename);
SettingsManager::ReadSettings(filename);
CompareFiles(filename, maximumFile);
std::filesystem::remove(filename);
}
INSTANTIATE_TEST_SUITE_P(
SettingsManager,
BadSettingsTest,
testing::Values(
std::make_pair("settings-minimum.json", "settings-bad-minimum.json"),
std::make_pair("settings-maximum.json", "settings-bad-maximum.json"),
std::make_pair("settings-maps.json", "settings-bad-maps.json")));
} // namespace manager
} // namespace qt