diff --git a/scwx-qt/source/scwx/qt/manager/poi_manager.cpp b/scwx-qt/source/scwx/qt/manager/poi_manager.cpp index 658ae4da..9124bed4 100644 --- a/scwx-qt/source/scwx/qt/manager/poi_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/poi_manager.cpp @@ -1,9 +1,14 @@ #include -#include +#include #include +#include +#include #include +#include +#include +#include #include namespace scwx @@ -13,7 +18,7 @@ namespace qt namespace manager { -static const std::string logPrefix_ = "scwx::qt::manager::placefile_manager"; +static const std::string logPrefix_ = "scwx::qt::manager::poi_manager"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static const std::string kNameName_ = "name"; @@ -23,22 +28,27 @@ static const std::string kLongitudeName_ = "longitude"; class POIManager::Impl { public: - class PointOfInterest; + class POIRecord; explicit Impl(POIManager* self) : self_ {self} {} + ~Impl() {} std::string poiSettingsPath_ {}; + std::vector> poiRecords_ {}; POIManager* self_; + void InitializePOISettings(); void ReadPOISettings(); + void WritePOISettings(); + std::shared_ptr GetPOIByName(const std::string& name); }; -class POIManager::Impl::PointOfInterest +class POIManager::Impl::POIRecord { public: - PointOfInterest(std::string name, double latitude, double longitude) : + POIRecord(std::string name, double latitude, double longitude) : name_ {name}, latitude_ {latitude}, longitude_ {longitude} { } @@ -49,28 +59,45 @@ public: friend void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, - const std::shared_ptr& record) + const std::shared_ptr& record) { jv = {{kNameName_, record->name_}, {kLatitudeName_, record->latitude_}, {kLongitudeName_, record->longitude_}}; } - friend PointOfInterest tag_invoke(boost::json::value_to_tag, + friend POIRecord tag_invoke(boost::json::value_to_tag, const boost::json::value& jv) { - return PointOfInterest( + return POIRecord( boost::json::value_to(jv.at(kNameName_)), boost::json::value_to(jv.at(kLatitudeName_)), boost::json::value_to(jv.at(kLongitudeName_))); } }; -POIManager::POIManager() : p(std::make_unique(this)) {} + +void POIManager::Impl::InitializePOISettings() +{ + 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); + } + } + + poiSettingsPath_ = appDataPath + "/points_of_interest.json"; +} void POIManager::Impl::ReadPOISettings() { - logger_->info("Reading point of intrest settings"); + logger_->info("Reading point of interest settings"); boost::json::value poiJson = nullptr; @@ -84,16 +111,18 @@ void POIManager::Impl::ReadPOISettings() { // For each poi entry auto& poiArray = poiJson.as_array(); + poiRecords_.reserve(poiArray.size()); for (auto& poiEntry : poiArray) { try { - PointOfInterest record = - boost::json::value_to(poiEntry); + POIRecord record = + boost::json::value_to(poiEntry); if (!record.name_.empty()) { - // Add record + poiRecords_.emplace_back(std::make_shared( + record.name_, record.latitude_, record.longitude_)); } } catch (const std::exception& ex) @@ -101,9 +130,147 @@ void POIManager::Impl::ReadPOISettings() logger_->warn("Invalid point of interest entry: {}", ex.what()); } } + + logger_->debug("{} point of interest entries", poiRecords_.size()); } } +void POIManager::Impl::WritePOISettings() +{ + logger_->info("Saving point of interest settings"); + + auto poiJson = boost::json::value_from(poiRecords_); + util::json::WriteJsonFile(poiSettingsPath_, poiJson); +} + +std::shared_ptr +POIManager::Impl::GetPOIByName(const std::string& name) +{ + for (auto& poiRecord : poiRecords_) + { + if (poiRecord->name_ == name) + { + return poiRecord; + } + } + + return nullptr; +} + +POIManager::POIManager() : p(std::make_unique(this)) +{ + // TODO THREADING? + try + { + p->InitializePOISettings(); + + // Read POI settings on startup + //main::Application::WaitForInitialization(); + p->ReadPOISettings(); + } + catch (const std::exception& ex) + { + logger_->error(ex.what()); + } +} + +POIManager::~POIManager() +{ + p->WritePOISettings(); +} + +size_t POIManager::poi_count() +{ + return p->poiRecords_.size(); +} + +// TODO deal with out of range/not found +types::PointOfInterest POIManager::get_poi(size_t index) +{ + std::shared_ptr poiRecord = + p->poiRecords_[index]; + return types::PointOfInterest( + poiRecord->name_, poiRecord->latitude_, poiRecord->longitude_); +} + +types::PointOfInterest POIManager::get_poi(const std::string& name) +{ + std::shared_ptr poiRecord = + p->GetPOIByName(name); + return types::PointOfInterest( + poiRecord->name_, poiRecord->latitude_, poiRecord->longitude_); +} + +void POIManager::set_poi(size_t index, const types::PointOfInterest& poi) +{ + std::shared_ptr poiRecord = + p->poiRecords_[index]; + poiRecord->name_ = poi.name_; + poiRecord->latitude_ = poi.latitude_; + poiRecord->longitude_ = poi.longitude_; +} + +void POIManager::set_poi(const std::string& name, + const types::PointOfInterest& poi) +{ + std::shared_ptr poiRecord = + p->GetPOIByName(name); + poiRecord->name_ = poi.name_; + poiRecord->latitude_ = poi.latitude_; + poiRecord->longitude_ = poi.longitude_; +} + +void POIManager::add_poi(const types::PointOfInterest& poi) +{ + p->poiRecords_.emplace_back(std::make_shared( + poi.name_, poi.latitude_, poi.longitude_)); +} + +void POIManager::move_poi(size_t from, size_t to) +{ + if (from >= p->poiRecords_.size() || to >= p->poiRecords_.size()) + { + return; + } + std::shared_ptr poiRecord = + p->poiRecords_[from]; + + if (from == to) + { + } + else if (from < to) + { + for (size_t i = from; i < to; i++) + { + p->poiRecords_[i] = p->poiRecords_[i + 1]; + } + p->poiRecords_[to] = poiRecord; + } + else + { + for (size_t i = from; i > to; i--) + { + p->poiRecords_[i] = p->poiRecords_[i - 1]; + } + p->poiRecords_[to] = poiRecord; + } +} + +std::shared_ptr POIManager::Instance() +{ + static std::weak_ptr poiManagerReference_ {}; + + std::shared_ptr poiManager = poiManagerReference_.lock(); + + if (poiManager == nullptr) + { + poiManager = std::make_shared(); + poiManagerReference_ = poiManager; + } + + return poiManager; +} + } // namespace manager } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/manager/poi_manager.hpp b/scwx-qt/source/scwx/qt/manager/poi_manager.hpp index b0bc574d..63144cc8 100644 --- a/scwx-qt/source/scwx/qt/manager/poi_manager.hpp +++ b/scwx-qt/source/scwx/qt/manager/poi_manager.hpp @@ -2,6 +2,8 @@ #include +#include + #include namespace scwx @@ -19,6 +21,15 @@ public: explicit POIManager(); ~POIManager(); + size_t poi_count(); + types::PointOfInterest get_poi(size_t index); + types::PointOfInterest get_poi(const std::string& name); + void set_poi(size_t index, const types::PointOfInterest& poi); + void set_poi(const std::string& name, const types::PointOfInterest& poi); + void add_poi(const types::PointOfInterest& poi); + void move_poi(size_t from, size_t to); + + static std::shared_ptr Instance(); private: class Impl;