From 6f14745a594d2929c192de8f8423371b8c135f85 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 23 Aug 2023 01:06:51 -0500 Subject: [PATCH] Save (works) and reload (doesn't work) placefiles from settings --- .../scwx/qt/manager/placefile_manager.cpp | 155 +++++++++++++++++- .../scwx/qt/manager/placefile_manager.hpp | 10 +- .../source/scwx/qt/model/placefile_model.cpp | 11 +- 3 files changed, 158 insertions(+), 18 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp b/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp index 9f233d9d..45963124 100644 --- a/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -11,11 +12,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -29,6 +32,11 @@ namespace manager static const std::string logPrefix_ = "scwx::qt::manager::placefile_manager"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); +static const std::string kEnabledName_ = "enabled"; +static const std::string kThresholdedName_ = "thresholded"; +static const std::string kTitleName_ = "title"; +static const std::string kNameName_ = "name"; + class PlacefileManager::Impl { public: @@ -37,12 +45,18 @@ public: explicit Impl(PlacefileManager* self) : self_ {self} {} ~Impl() {} + void InitializePlacefileSettings(); + void ReadPlacefileSettings(); + void WritePlacefileSettings(); + static void LoadResources(const std::shared_ptr& placefile); boost::asio::thread_pool threadPool_ {1u}; PlacefileManager* self_; + std::string placefileSettingsPath_ {}; + std::shared_ptr radarSite_ {}; std::vector> placefileRecords_ {}; @@ -57,8 +71,15 @@ public: explicit PlacefileRecord(Impl* impl, const std::string& name, std::shared_ptr placefile, - bool enabled = true) : - p {impl}, name_ {name}, placefile_ {placefile}, enabled_ {enabled} + const std::string& title = {}, + bool enabled = false, + bool thresholded = false) : + p {impl}, + name_ {name}, + placefile_ {placefile}, + title_ {title}, + enabled_ {enabled}, + thresholded_ {thresholded} { } ~PlacefileRecord() @@ -71,19 +92,56 @@ public: void UpdateAsync(); void UpdatePlacefile(const std::shared_ptr& placefile); + friend void tag_invoke(boost::json::value_from_tag, + boost::json::value& jv, + const std::shared_ptr& record) + { + jv = {{kEnabledName_, record->enabled_}, + {kThresholdedName_, record->thresholded_}, + {kTitleName_, record->title_}, + {kNameName_, record->name_}}; + } + + friend PlacefileRecord tag_invoke(boost::json::value_to_tag, + const boost::json::value& jv) + { + return PlacefileRecord { + nullptr, + boost::json::value_to(jv.at(kNameName_)), + nullptr, + boost::json::value_to(jv.at(kTitleName_)), + jv.at(kEnabledName_).as_bool(), + jv.at(kThresholdedName_).as_bool()}; + } + Impl* p; std::string name_; + std::string title_; std::shared_ptr placefile_; bool enabled_; - bool thresholded_ {false}; + bool thresholded_; boost::asio::thread_pool threadPool_ {1u}; boost::asio::steady_timer refreshTimer_ {threadPool_}; std::mutex refreshMutex_ {}; }; -PlacefileManager::PlacefileManager() : p(std::make_unique(this)) {} -PlacefileManager::~PlacefileManager() = default; +PlacefileManager::PlacefileManager() : p(std::make_unique(this)) +{ + boost::asio::post(p->threadPool_, + [this]() + { + // Read placefile settings on startup + p->InitializePlacefileSettings(); + p->ReadPlacefileSettings(); + }); +} + +PlacefileManager::~PlacefileManager() +{ + // Write placefile settings on shutdown + p->WritePlacefileSettings(); +}; bool PlacefileManager::placefile_enabled(const std::string& name) { @@ -109,6 +167,18 @@ bool PlacefileManager::placefile_thresholded(const std::string& name) return false; } +std::string PlacefileManager::placefile_title(const std::string& name) +{ + std::shared_lock lock(p->placefileRecordLock_); + + auto it = p->placefileRecordMap_.find(name); + if (it != p->placefileRecordMap_.cend()) + { + return it->second->title_; + } + return {}; +} + std::shared_ptr PlacefileManager::placefile(const std::string& name) { @@ -189,6 +259,71 @@ void PlacefileManager::set_placefile_url(const std::string& name, } } +void PlacefileManager::Impl::InitializePlacefileSettings() +{ + std::string appDataPath { + QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + .toStdString()}; + + if (!std::filesystem::exists(appDataPath)) + { + if (!std::filesystem::create_directories(appDataPath)) + { + logger_->error("Unable to create application data directory: \"{}\"", + appDataPath); + } + } + + placefileSettingsPath_ = appDataPath + "/placefiles.json"; +} + +void PlacefileManager::Impl::ReadPlacefileSettings() +{ + logger_->info("Reading placefile settings"); + + boost::json::value placefileJson = nullptr; + + // Determine if placefile settings exists + if (std::filesystem::exists(placefileSettingsPath_)) + { + placefileJson = util::json::ReadJsonFile(placefileSettingsPath_); + } + + // If placefile settings was successfully read + if (placefileJson != nullptr && placefileJson.is_array()) + { + // For each placefile entry + auto& placefileArray = placefileJson.as_array(); + for (auto& placefileEntry : placefileArray) + { + try + { + // Convert placefile entry to a record + PlacefileRecord record = + boost::json::value_to(placefileEntry); + + self_->AddUrl(record.name_, + record.title_, + record.enabled_, + record.thresholded_); + } + catch (const std::exception& ex) + { + logger_->warn("Invalid placefile entry: {}", ex.what()); + } + } + } +} + +void PlacefileManager::Impl::WritePlacefileSettings() +{ + logger_->info("Saving placefile settings"); + + std::shared_lock lock {placefileRecordLock_}; + auto placefileJson = boost::json::value_from(placefileRecords_); + util::json::WriteJsonFile(placefileSettingsPath_, placefileJson); +} + void PlacefileManager::SetRadarSite( std::shared_ptr radarSite) { @@ -231,7 +366,10 @@ PlacefileManager::GetActivePlacefiles() return placefiles; } -void PlacefileManager::AddUrl(const std::string& urlString) +void PlacefileManager::AddUrl(const std::string& urlString, + const std::string& title, + bool enabled, + bool thresholded) { std::string normalizedUrl = util::network::NormalizeUrl(urlString); @@ -254,7 +392,7 @@ void PlacefileManager::AddUrl(const std::string& urlString) // Add an empty placefile record for the new URL auto& record = p->placefileRecords_.emplace_back(std::make_shared( - p.get(), normalizedUrl, nullptr, false)); + p.get(), normalizedUrl, nullptr, title, enabled, thresholded)); p->placefileRecordMap_.insert_or_assign(normalizedUrl, record); lock.unlock(); @@ -303,7 +441,7 @@ void PlacefileManager::LoadFile(const std::string& filename) // If this is a new placefile, add it auto& record = p->placefileRecords_.emplace_back( std::make_shared( - p.get(), placefileName, placefile)); + p.get(), placefileName, placefile, placefile->title(), true)); p->placefileRecordMap_.insert_or_assign(placefileName, record); lock.unlock(); @@ -434,6 +572,7 @@ void PlacefileManager::Impl::PlacefileRecord::Update() { // Update the placefile placefile_ = updatedPlacefile; + title_ = placefile_->title(); // Notify slots of the placefile update Q_EMIT p->self_->PlacefileUpdated(name); diff --git a/scwx-qt/source/scwx/qt/manager/placefile_manager.hpp b/scwx-qt/source/scwx/qt/manager/placefile_manager.hpp index eaa9c21b..498ea9a1 100644 --- a/scwx-qt/source/scwx/qt/manager/placefile_manager.hpp +++ b/scwx-qt/source/scwx/qt/manager/placefile_manager.hpp @@ -20,8 +20,9 @@ public: explicit PlacefileManager(); ~PlacefileManager(); - bool placefile_enabled(const std::string& name); - bool placefile_thresholded(const std::string& name); + bool placefile_enabled(const std::string& name); + bool placefile_thresholded(const std::string& name); + std::string placefile_title(const std::string& name); std::shared_ptr placefile(const std::string& name); void set_placefile_enabled(const std::string& name, bool enabled); @@ -37,7 +38,10 @@ public: */ std::vector> GetActivePlacefiles(); - void AddUrl(const std::string& urlString); + void AddUrl(const std::string& urlString, + const std::string& title = {}, + bool enabled = false, + bool thresholded = false); void LoadFile(const std::string& filename); void RemoveUrl(const std::string& urlString); diff --git a/scwx-qt/source/scwx/qt/model/placefile_model.cpp b/scwx-qt/source/scwx/qt/model/placefile_model.cpp index 5ad286a1..21478936 100644 --- a/scwx-qt/source/scwx/qt/model/placefile_model.cpp +++ b/scwx-qt/source/scwx/qt/model/placefile_model.cpp @@ -159,14 +159,11 @@ QVariant PlacefileModel::data(const QModelIndex& index, int role) const role == Qt::ItemDataRole::ToolTipRole) { std::string description = placefileName; - auto placefile = p->placefileManager_->placefile(placefileName); - if (placefile != nullptr) + std::string title = + p->placefileManager_->placefile_title(placefileName); + if (!title.empty()) { - std::string title = placefile->title(); - if (!title.empty()) - { - description = title + '\n' + description; - } + description = title + '\n' + description; } return QString::fromStdString(description);