mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 04:00:04 +00:00 
			
		
		
		
	Read layer settings from JSON
This commit is contained in:
		
							parent
							
								
									10fe904011
								
							
						
					
					
						commit
						2fe3facbd2
					
				
					 1 changed files with 158 additions and 60 deletions
				
			
		|  | @ -17,6 +17,7 @@ | |||
| #include <QStyle> | ||||
| #include <QStyleOption> | ||||
| #include <QStandardPaths> | ||||
| #include <boost/container/stable_vector.hpp> | ||||
| #include <boost/json.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
|  | @ -47,73 +48,41 @@ typedef std:: | |||
|    variant<std::monostate, types::Layer, awips::Phenomenon, std::string> | ||||
|       LayerDescription; | ||||
| 
 | ||||
| class LayerModel::Impl | ||||
| struct LayerInfo | ||||
| { | ||||
| public: | ||||
|    struct LayerInfo | ||||
|    { | ||||
|    types::LayerType             type_; | ||||
|    LayerDescription             description_; | ||||
|    bool                         movable_; | ||||
|    std::array<bool, kMapCount_> displayed_ {true, true, true, true}; | ||||
|    }; | ||||
| }; | ||||
| 
 | ||||
|    typedef std::vector<LayerInfo> LayerVector; | ||||
| typedef boost::container::stable_vector<LayerInfo> LayerVector; | ||||
| 
 | ||||
|    explicit Impl(LayerModel* self) : self_ {self} | ||||
|    { | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Information, types::Layer::MapOverlay, false); | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Information, types::Layer::ColorTable, false); | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Alert, awips::Phenomenon::Tornado, true); | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Alert, awips::Phenomenon::SnowSquall, true); | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Alert, awips::Phenomenon::SevereThunderstorm, true); | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Alert, awips::Phenomenon::FlashFlood, true); | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Alert, awips::Phenomenon::Marine, true); | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Map, types::Layer::MapSymbology, false); | ||||
|       layers_.emplace_back(types::LayerType::Radar, std::monostate {}, true); | ||||
|       layers_.emplace_back( | ||||
|          types::LayerType::Map, types::Layer::MapUnderlay, false); | ||||
|    } | ||||
| static const std::vector<LayerInfo> kDefaultLayers_ { | ||||
|    {types::LayerType::Information, types::Layer::MapOverlay, false}, | ||||
|    {types::LayerType::Information, types::Layer::ColorTable, false}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::Tornado, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::SnowSquall, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::SevereThunderstorm, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::FlashFlood, true}, | ||||
|    {types::LayerType::Alert, awips::Phenomenon::Marine, true}, | ||||
|    {types::LayerType::Map, types::Layer::MapSymbology, false}, | ||||
|    {types::LayerType::Radar, std::monostate {}, true}, | ||||
|    {types::LayerType::Map, types::Layer::MapUnderlay, false}, | ||||
| }; | ||||
| 
 | ||||
| class LayerModel::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl(LayerModel* self) : self_ {self} {} | ||||
|    ~Impl() = default; | ||||
| 
 | ||||
|    void AddPlacefile(const std::string& name); | ||||
|    void InitializeLayerSettings(); | ||||
|    void ReadLayerSettings(); | ||||
|    void WriteLayerSettings(); | ||||
| 
 | ||||
|    friend void tag_invoke(boost::json::value_from_tag, | ||||
|                           boost::json::value& jv, | ||||
|                           const LayerInfo&    record) | ||||
|    { | ||||
|       std::string description {}; | ||||
| 
 | ||||
|       if (std::holds_alternative<awips::Phenomenon>(record.description_)) | ||||
|       { | ||||
|          description = awips::GetPhenomenonCode( | ||||
|             std::get<awips::Phenomenon>(record.description_)); | ||||
|       } | ||||
|       else if (std::holds_alternative<types::Layer>(record.description_)) | ||||
|       { | ||||
|          description = | ||||
|             types::GetLayerName(std::get<types::Layer>(record.description_)); | ||||
|       } | ||||
|       else if (std::holds_alternative<std::string>(record.description_)) | ||||
|       { | ||||
|          description = std::get<std::string>(record.description_); | ||||
|       } | ||||
| 
 | ||||
|       jv = {{kTypeName_, types::GetLayerTypeName(record.type_)}, | ||||
|             {kDescriptionName_, description}, | ||||
|             {kMovableName_, record.movable_}, | ||||
|             {kDisplayedName_, boost::json::value_from(record.displayed_)}}; | ||||
|    } | ||||
|    static void ValidateLayerSettings(LayerVector& layers); | ||||
| 
 | ||||
|    LayerModel* self_; | ||||
| 
 | ||||
|  | @ -149,6 +118,12 @@ LayerModel::LayerModel(QObject* parent) : | |||
|            &LayerModel::HandlePlacefileUpdate); | ||||
| 
 | ||||
|    p->InitializeLayerSettings(); | ||||
|    p->ReadLayerSettings(); | ||||
| 
 | ||||
|    if (p->layers_.empty()) | ||||
|    { | ||||
|       p->layers_.assign(kDefaultLayers_.cbegin(), kDefaultLayers_.cend()); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| LayerModel::~LayerModel() | ||||
|  | @ -175,6 +150,52 @@ void LayerModel::Impl::InitializeLayerSettings() | |||
|    layerSettingsPath_ = appDataPath + "/layers.json"; | ||||
| } | ||||
| 
 | ||||
| void LayerModel::Impl::ReadLayerSettings() | ||||
| { | ||||
|    logger_->info("Reading layer settings"); | ||||
| 
 | ||||
|    boost::json::value layerJson = nullptr; | ||||
|    LayerVector        newLayers {}; | ||||
| 
 | ||||
|    // Determine if layer settings exists
 | ||||
|    if (std::filesystem::exists(layerSettingsPath_)) | ||||
|    { | ||||
|       layerJson = util::json::ReadJsonFile(layerSettingsPath_); | ||||
|    } | ||||
| 
 | ||||
|    // If layer settings was successfully read
 | ||||
|    if (layerJson != nullptr && layerJson.is_array()) | ||||
|    { | ||||
|       // For each layer entry
 | ||||
|       auto& layerArray = layerJson.as_array(); | ||||
|       for (auto& layerEntry : layerArray) | ||||
|       { | ||||
|          try | ||||
|          { | ||||
|             // Convert layer entry to a LayerInfo record, and add to new layers
 | ||||
|             newLayers.emplace_back( | ||||
|                boost::json::value_to<LayerInfo>(layerEntry)); | ||||
|          } | ||||
|          catch (const std::exception& ex) | ||||
|          { | ||||
|             logger_->warn("Invalid layer entry: {}", ex.what()); | ||||
|          } | ||||
|       } | ||||
| 
 | ||||
|       // Validate and correct read layers
 | ||||
|       ValidateLayerSettings(newLayers); | ||||
| 
 | ||||
|       // Assign read layers
 | ||||
|       layers_.swap(newLayers); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers) | ||||
| { | ||||
|    // TODO
 | ||||
|    Q_UNUSED(layers); | ||||
| } | ||||
| 
 | ||||
| void LayerModel::Impl::WriteLayerSettings() | ||||
| { | ||||
|    logger_->info("Saving layer settings"); | ||||
|  | @ -555,7 +576,7 @@ bool LayerModel::dropMimeData(const QMimeData* data, | |||
|    } | ||||
| 
 | ||||
|    // Create a copy of the layers to insert (don't insert in-place)
 | ||||
|    std::vector<Impl::LayerInfo> newLayers {}; | ||||
|    std::vector<LayerInfo> newLayers {}; | ||||
|    for (auto& sourceRow : sourceRows) | ||||
|    { | ||||
|       newLayers.push_back(p->layers_.at(sourceRow)); | ||||
|  | @ -744,7 +765,7 @@ void LayerModel::Impl::AddPlacefile(const std::string& name) | |||
|    auto insertPosition = std::find_if( | ||||
|       layers_.begin(), | ||||
|       layers_.end(), | ||||
|       [](const Impl::LayerInfo& layerInfo) | ||||
|       [](const LayerInfo& layerInfo) | ||||
|       { | ||||
|          return std::holds_alternative<types::Layer>(layerInfo.description_) && | ||||
|                 std::get<types::Layer>(layerInfo.description_) == | ||||
|  | @ -761,6 +782,83 @@ void LayerModel::Impl::AddPlacefile(const std::string& name) | |||
|    self_->endInsertRows(); | ||||
| } | ||||
| 
 | ||||
| void tag_invoke(boost::json::value_from_tag, | ||||
|                 boost::json::value& jv, | ||||
|                 const LayerInfo&    record) | ||||
| { | ||||
|    std::string description {}; | ||||
| 
 | ||||
|    if (std::holds_alternative<awips::Phenomenon>(record.description_)) | ||||
|    { | ||||
|       description = awips::GetPhenomenonCode( | ||||
|          std::get<awips::Phenomenon>(record.description_)); | ||||
|    } | ||||
|    else if (std::holds_alternative<types::Layer>(record.description_)) | ||||
|    { | ||||
|       description = | ||||
|          types::GetLayerName(std::get<types::Layer>(record.description_)); | ||||
|    } | ||||
|    else if (std::holds_alternative<std::string>(record.description_)) | ||||
|    { | ||||
|       description = std::get<std::string>(record.description_); | ||||
|    } | ||||
| 
 | ||||
|    jv = {{kTypeName_, types::GetLayerTypeName(record.type_)}, | ||||
|          {kDescriptionName_, description}, | ||||
|          {kMovableName_, record.movable_}, | ||||
|          {kDisplayedName_, boost::json::value_from(record.displayed_)}}; | ||||
| } | ||||
| 
 | ||||
| template<typename T, std::size_t n> | ||||
| std::array<T, n> tag_invoke(boost::json::value_to_tag<std::array<T, n>>, | ||||
|                             const boost::json::value& jv) | ||||
| { | ||||
|    std::array<T, n>   array {}; | ||||
|    boost::json::array jsonArray = jv.as_array(); | ||||
| 
 | ||||
|    for (std::size_t i = 0; i < n && i < jsonArray.size(); ++i) | ||||
|    { | ||||
|       array[i] = jsonArray[i]; | ||||
|    } | ||||
| 
 | ||||
|    return array; | ||||
| } | ||||
| 
 | ||||
| LayerInfo tag_invoke(boost::json::value_to_tag<LayerInfo>, | ||||
|                      const boost::json::value& jv) | ||||
| { | ||||
|    const types::LayerType layerType = types::GetLayerType( | ||||
|       boost::json::value_to<std::string>(jv.at(kTypeName_))); | ||||
|    const std::string descriptionName = | ||||
|       boost::json::value_to<std::string>(jv.at(kDescriptionName_)); | ||||
| 
 | ||||
|    LayerDescription description {}; | ||||
| 
 | ||||
|    if (layerType == types::LayerType::Map || | ||||
|        layerType == types::LayerType::Information) | ||||
|    { | ||||
|       description = types::GetLayer(descriptionName); | ||||
|    } | ||||
|    else if (layerType == types::LayerType::Radar) | ||||
|    { | ||||
|       description = std::monostate {}; | ||||
|    } | ||||
|    else if (layerType == types::LayerType::Alert) | ||||
|    { | ||||
|       description = awips::GetPhenomenon(descriptionName); | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       description = descriptionName; | ||||
|    } | ||||
| 
 | ||||
|    return LayerInfo { | ||||
|       layerType, | ||||
|       description, | ||||
|       jv.at(kMovableName_).as_bool(), | ||||
|       boost::json::value_to<std::array<bool, 4>>(jv.at(kDisplayedName_))}; | ||||
| } | ||||
| 
 | ||||
| } // namespace model
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat