Refactor layer types from layer model

This commit is contained in:
Dan Paulat 2023-11-01 00:05:32 -05:00
parent f7851488d6
commit a5cee797d9
4 changed files with 147 additions and 133 deletions

View file

@ -1,13 +1,11 @@
#include <scwx/qt/model/layer_model.hpp> #include <scwx/qt/model/layer_model.hpp>
#include <scwx/qt/manager/placefile_manager.hpp> #include <scwx/qt/manager/placefile_manager.hpp>
#include <scwx/qt/types/layer_types.hpp>
#include <scwx/qt/types/qt_types.hpp> #include <scwx/qt/types/qt_types.hpp>
#include <scwx/qt/util/json.hpp> #include <scwx/qt/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <filesystem> #include <filesystem>
#include <set> #include <set>
#include <variant>
#include <QApplication> #include <QApplication>
#include <QCheckBox> #include <QCheckBox>
@ -17,7 +15,6 @@
#include <QStyle> #include <QStyle>
#include <QStyleOption> #include <QStyleOption>
#include <QStandardPaths> #include <QStandardPaths>
#include <boost/container/stable_vector.hpp>
#include <boost/json.hpp> #include <boost/json.hpp>
namespace scwx namespace scwx
@ -39,30 +36,7 @@ static constexpr std::size_t kMapCount_ = 4u;
static const QString kMimeFormat {"application/x.scwx-layer-model"}; static const QString kMimeFormat {"application/x.scwx-layer-model"};
static const std::string kTypeName_ {"type"}; static const std::vector<types::LayerInfo> kDefaultLayers_ {
static const std::string kDescriptionName_ {"description"};
static const std::string kMovableName_ {"movable"};
static const std::string kDisplayedName_ {"displayed"};
typedef std::variant<std::monostate,
types::DataLayer,
types::InformationLayer,
types::MapLayer,
awips::Phenomenon,
std::string>
LayerDescription;
struct LayerInfo
{
types::LayerType type_;
LayerDescription description_;
bool movable_ {true};
std::array<bool, kMapCount_> displayed_ {true, true, true, true};
};
typedef boost::container::stable_vector<LayerInfo> LayerVector;
static const std::vector<LayerInfo> kDefaultLayers_ {
{types::LayerType::Information, types::InformationLayer::MapOverlay, false}, {types::LayerType::Information, types::InformationLayer::MapOverlay, false},
{types::LayerType::Information, types::InformationLayer::ColorTable, false}, {types::LayerType::Information, types::InformationLayer::ColorTable, false},
{types::LayerType::Data, types::DataLayer::RadarRange, true}, {types::LayerType::Data, types::DataLayer::RadarRange, true},
@ -76,7 +50,7 @@ static const std::vector<LayerInfo> kDefaultLayers_ {
{types::LayerType::Map, types::MapLayer::MapUnderlay, false}, {types::LayerType::Map, types::MapLayer::MapUnderlay, false},
}; };
static const std::vector<LayerInfo> kImmovableLayers_ { static const std::vector<types::LayerInfo> kImmovableLayers_ {
{types::LayerType::Information, types::InformationLayer::MapOverlay, false}, {types::LayerType::Information, types::InformationLayer::MapOverlay, false},
{types::LayerType::Information, types::InformationLayer::ColorTable, false}, {types::LayerType::Information, types::InformationLayer::ColorTable, false},
{types::LayerType::Map, types::MapLayer::MapSymbology, false}, {types::LayerType::Map, types::MapLayer::MapSymbology, false},
@ -102,7 +76,7 @@ public:
void SynchronizePlacefileLayers(); void SynchronizePlacefileLayers();
void WriteLayerSettings(); void WriteLayerSettings();
static void ValidateLayerSettings(LayerVector& layers); static void ValidateLayerSettings(types::LayerVector& layers);
LayerModel* self_; LayerModel* self_;
@ -114,7 +88,7 @@ public:
std::shared_ptr<manager::PlacefileManager> placefileManager_ { std::shared_ptr<manager::PlacefileManager> placefileManager_ {
manager::PlacefileManager::Instance()}; manager::PlacefileManager::Instance()};
LayerVector layers_ {}; types::LayerVector layers_ {};
}; };
LayerModel::LayerModel(QObject* parent) : LayerModel::LayerModel(QObject* parent) :
@ -183,7 +157,7 @@ void LayerModel::Impl::ReadLayerSettings()
logger_->info("Reading layer settings"); logger_->info("Reading layer settings");
boost::json::value layerJson = nullptr; boost::json::value layerJson = nullptr;
LayerVector newLayers {}; types::LayerVector newLayers {};
// Determine if layer settings exists // Determine if layer settings exists
if (std::filesystem::exists(layerSettingsPath_)) if (std::filesystem::exists(layerSettingsPath_))
@ -202,7 +176,7 @@ void LayerModel::Impl::ReadLayerSettings()
{ {
// Convert layer entry to a LayerInfo record, and add to new layers // Convert layer entry to a LayerInfo record, and add to new layers
newLayers.emplace_back( newLayers.emplace_back(
boost::json::value_to<LayerInfo>(layerEntry)); boost::json::value_to<types::LayerInfo>(layerEntry));
} }
catch (const std::exception& ex) catch (const std::exception& ex)
{ {
@ -218,7 +192,7 @@ void LayerModel::Impl::ReadLayerSettings()
} }
} }
void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers) void LayerModel::Impl::ValidateLayerSettings(types::LayerVector& layers)
{ {
// Validate layer properties // Validate layer properties
for (auto it = layers.begin(); it != layers.end();) for (auto it = layers.begin(); it != layers.end();)
@ -252,10 +226,10 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers)
} }
// Validate immovable layers // Validate immovable layers
std::vector<LayerVector::iterator> immovableIterators {}; std::vector<types::LayerVector::iterator> immovableIterators {};
LayerVector::iterator colorTableIterator {}; types::LayerVector::iterator colorTableIterator {};
LayerVector::iterator mapSymbologyIterator {}; types::LayerVector::iterator mapSymbologyIterator {};
LayerVector::iterator mapUnderlayIterator {}; types::LayerVector::iterator mapUnderlayIterator {};
for (auto& immovableLayer : kImmovableLayers_) for (auto& immovableLayer : kImmovableLayers_)
{ {
// Set the default displayed state for a layer that is not found // Set the default displayed state for a layer that is not found
@ -264,7 +238,7 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers)
// Find the immovable layer // Find the immovable layer
auto it = std::find_if(layers.begin(), auto it = std::find_if(layers.begin(),
layers.end(), layers.end(),
[&immovableLayer](const LayerInfo& layer) [&immovableLayer](const types::LayerInfo& layer)
{ {
return layer.type_ == immovableLayer.type_ && return layer.type_ == immovableLayer.type_ &&
layer.description_ == layer.description_ ==
@ -289,7 +263,7 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers)
{ {
// If this is the first immovable layer, insert at the beginning, // If this is the first immovable layer, insert at the beginning,
// otherwise, insert after the previous immovable layer // otherwise, insert after the previous immovable layer
LayerVector::iterator insertPosition = types::LayerVector::iterator insertPosition =
immovableIterators.empty() ? layers.begin() : immovableIterators.empty() ? layers.begin() :
immovableIterators.back() + 1; immovableIterators.back() + 1;
it = layers.insert(insertPosition, immovableLayer); it = layers.insert(insertPosition, immovableLayer);
@ -333,13 +307,13 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers)
} }
// Validate data layers // Validate data layers
std::vector<LayerVector::iterator> dataIterators {}; std::vector<types::LayerVector::iterator> dataIterators {};
for (const auto& dataLayer : types::DataLayerIterator()) for (const auto& dataLayer : types::DataLayerIterator())
{ {
// Find the data layer // Find the data layer
auto it = std::find_if(layers.begin(), auto it = std::find_if(layers.begin(),
layers.end(), layers.end(),
[&dataLayer](const LayerInfo& layer) [&dataLayer](const types::LayerInfo& layer)
{ {
return layer.type_ == types::LayerType::Data && return layer.type_ == types::LayerType::Data &&
std::get<types::DataLayer>( std::get<types::DataLayer>(
@ -350,9 +324,9 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers)
{ {
// If this is the first data layer, insert after the color table layer, // If this is the first data layer, insert after the color table layer,
// otherwise, insert after the previous data layer // otherwise, insert after the previous data layer
LayerVector::iterator insertPosition = dataIterators.empty() ? types::LayerVector::iterator insertPosition =
colorTableIterator + 1 : dataIterators.empty() ? colorTableIterator + 1 :
dataIterators.back() + 1; dataIterators.back() + 1;
it = it =
layers.insert(insertPosition, {types::LayerType::Data, dataLayer}); layers.insert(insertPosition, {types::LayerType::Data, dataLayer});
} }
@ -361,13 +335,13 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers)
} }
// Validate alert layers // Validate alert layers
std::vector<LayerVector::iterator> alertIterators {}; std::vector<types::LayerVector::iterator> alertIterators {};
for (auto& phenomenon : kAlertPhenomena_) for (auto& phenomenon : kAlertPhenomena_)
{ {
// Find the alert layer // Find the alert layer
auto it = std::find_if(layers.begin(), auto it = std::find_if(layers.begin(),
layers.end(), layers.end(),
[&phenomenon](const LayerInfo& layer) [&phenomenon](const types::LayerInfo& layer)
{ {
return layer.type_ == types::LayerType::Alert && return layer.type_ == types::LayerType::Alert &&
std::get<awips::Phenomenon>( std::get<awips::Phenomenon>(
@ -387,7 +361,7 @@ void LayerModel::Impl::ValidateLayerSettings(LayerVector& layers)
// Validate the radar layer // Validate the radar layer
auto it = std::find_if(layers.begin(), auto it = std::find_if(layers.begin(),
layers.end(), layers.end(),
[](const LayerInfo& layer) [](const types::LayerInfo& layer)
{ return layer.type_ == types::LayerType::Radar; }); { return layer.type_ == types::LayerType::Radar; });
if (it == layers.end()) if (it == layers.end())
{ {
@ -405,16 +379,21 @@ void LayerModel::Impl::WriteLayerSettings()
util::json::WriteJsonFile(layerSettingsPath_, layerJson); util::json::WriteJsonFile(layerSettingsPath_, layerJson);
} }
types::LayerVector LayerModel::GetLayers() const
{
return p->layers_;
}
void LayerModel::ResetLayers() void LayerModel::ResetLayers()
{ {
// Initialize a new layer vector from the default // Initialize a new layer vector from the default
LayerVector newLayers {}; types::LayerVector newLayers {};
newLayers.assign(kDefaultLayers_.cbegin(), kDefaultLayers_.cend()); newLayers.assign(kDefaultLayers_.cbegin(), kDefaultLayers_.cend());
auto colorTableIterator = std::find_if( auto colorTableIterator = std::find_if(
newLayers.begin(), newLayers.begin(),
newLayers.end(), newLayers.end(),
[](const LayerInfo& layerInfo) [](const types::LayerInfo& layerInfo)
{ {
return std::holds_alternative<types::InformationLayer>( return std::holds_alternative<types::InformationLayer>(
layerInfo.description_) && layerInfo.description_) &&
@ -852,7 +831,7 @@ bool LayerModel::dropMimeData(const QMimeData* data,
} }
// Create a copy of the layers to insert (don't insert in-place) // Create a copy of the layers to insert (don't insert in-place)
std::vector<LayerInfo> newLayers {}; std::vector<types::LayerInfo> newLayers {};
for (auto& sourceRow : sourceRows) for (auto& sourceRow : sourceRows)
{ {
newLayers.push_back(p->layers_.at(sourceRow)); newLayers.push_back(p->layers_.at(sourceRow));
@ -1047,7 +1026,7 @@ void LayerModel::Impl::AddPlacefile(const std::string& name)
auto insertPosition = std::find_if( auto insertPosition = std::find_if(
layers_.begin(), layers_.begin(),
layers_.end(), layers_.end(),
[](const LayerInfo& layerInfo) [](const types::LayerInfo& layerInfo)
{ {
return std::holds_alternative<types::InformationLayer>( return std::holds_alternative<types::InformationLayer>(
layerInfo.description_) && layerInfo.description_) &&
@ -1065,44 +1044,6 @@ void LayerModel::Impl::AddPlacefile(const std::string& name)
self_->endInsertRows(); 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::DataLayer>(record.description_))
{
description = types::GetDataLayerName(
std::get<types::DataLayer>(record.description_));
}
else if (std::holds_alternative<types::InformationLayer>(
record.description_))
{
description = types::GetInformationLayerName(
std::get<types::InformationLayer>(record.description_));
}
else if (std::holds_alternative<types::MapLayer>(record.description_))
{
description =
types::GetMapLayerName(std::get<types::MapLayer>(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> template<typename T, std::size_t n>
std::array<T, n> tag_invoke(boost::json::value_to_tag<std::array<T, n>>, std::array<T, n> tag_invoke(boost::json::value_to_tag<std::array<T, n>>,
const boost::json::value& jv) const boost::json::value& jv)
@ -1118,48 +1059,6 @@ std::array<T, n> tag_invoke(boost::json::value_to_tag<std::array<T, n>>,
return array; 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)
{
description = types::GetMapLayer(descriptionName);
}
else if (layerType == types::LayerType::Information)
{
description = types::GetInformationLayer(descriptionName);
}
else if (layerType == types::LayerType::Data)
{
description = types::GetDataLayer(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_))};
}
std::shared_ptr<LayerModel> LayerModel::Instance() std::shared_ptr<LayerModel> LayerModel::Instance()
{ {
static std::weak_ptr<LayerModel> layerModelReference_ {}; static std::weak_ptr<LayerModel> layerModelReference_ {};

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <scwx/qt/types/text_event_key.hpp> #include <scwx/qt/types/layer_types.hpp>
#include <scwx/common/geographic.hpp>
#include <scwx/util/iterator.hpp> #include <scwx/util/iterator.hpp>
#include <memory> #include <memory>
@ -37,6 +36,8 @@ public:
explicit LayerModel(QObject* parent = nullptr); explicit LayerModel(QObject* parent = nullptr);
~LayerModel(); ~LayerModel();
types::LayerVector GetLayers() const;
void ResetLayers(); void ResetLayers();
int rowCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override;

View file

@ -3,6 +3,7 @@
#include <unordered_map> #include <unordered_map>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/json.hpp>
namespace scwx namespace scwx
{ {
@ -33,6 +34,11 @@ static const std::unordered_map<MapLayer, std::string> mapLayerName_ {
{MapLayer::MapUnderlay, "Map Underlay"}, {MapLayer::MapUnderlay, "Map Underlay"},
{MapLayer::Unknown, "?"}}; {MapLayer::Unknown, "?"}};
static const std::string kTypeName_ {"type"};
static const std::string kDescriptionName_ {"description"};
static const std::string kMovableName_ {"movable"};
static const std::string kDisplayedName_ {"displayed"};
LayerType GetLayerType(const std::string& name) LayerType GetLayerType(const std::string& name)
{ {
auto result = auto result =
@ -125,6 +131,83 @@ std::string GetMapLayerName(MapLayer layer)
return mapLayerName_.at(layer); return mapLayerName_.at(layer);
} }
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<DataLayer>(record.description_))
{
description = GetDataLayerName(std::get<DataLayer>(record.description_));
}
else if (std::holds_alternative<InformationLayer>(record.description_))
{
description = GetInformationLayerName(
std::get<InformationLayer>(record.description_));
}
else if (std::holds_alternative<MapLayer>(record.description_))
{
description = GetMapLayerName(std::get<MapLayer>(record.description_));
}
else if (std::holds_alternative<std::string>(record.description_))
{
description = std::get<std::string>(record.description_);
}
jv = {{kTypeName_, GetLayerTypeName(record.type_)},
{kDescriptionName_, description},
{kMovableName_, record.movable_},
{kDisplayedName_, boost::json::value_from(record.displayed_)}};
}
LayerInfo tag_invoke(boost::json::value_to_tag<LayerInfo>,
const boost::json::value& jv)
{
const LayerType layerType =
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 == LayerType::Map)
{
description = GetMapLayer(descriptionName);
}
else if (layerType == LayerType::Information)
{
description = GetInformationLayer(descriptionName);
}
else if (layerType == LayerType::Data)
{
description = GetDataLayer(descriptionName);
}
else if (layerType == LayerType::Radar)
{
description = std::monostate {};
}
else if (layerType == 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 types } // namespace types
} // namespace qt } // namespace qt
} // namespace scwx } // namespace scwx

View file

@ -1,8 +1,15 @@
#pragma once #pragma once
#include <scwx/awips/phenomenon.hpp>
#include <scwx/util/iterator.hpp> #include <scwx/util/iterator.hpp>
#include <array>
#include <string> #include <string>
#include <variant>
#include <boost/container/stable_vector.hpp>
#include <boost/json/conversion.hpp>
#include <boost/json/value.hpp>
namespace scwx namespace scwx
{ {
@ -45,6 +52,24 @@ enum class MapLayer
Unknown Unknown
}; };
typedef std::variant<std::monostate,
DataLayer,
InformationLayer,
MapLayer,
awips::Phenomenon,
std::string>
LayerDescription;
struct LayerInfo
{
LayerType type_;
LayerDescription description_;
bool movable_ {true};
std::array<bool, 4> displayed_ {true, true, true, true};
};
typedef boost::container::stable_vector<LayerInfo> LayerVector;
LayerType GetLayerType(const std::string& name); LayerType GetLayerType(const std::string& name);
std::string GetLayerTypeName(LayerType layerType); std::string GetLayerTypeName(LayerType layerType);
@ -57,6 +82,12 @@ std::string GetInformationLayerName(InformationLayer layer);
MapLayer GetMapLayer(const std::string& name); MapLayer GetMapLayer(const std::string& name);
std::string GetMapLayerName(MapLayer layer); std::string GetMapLayerName(MapLayer layer);
void tag_invoke(boost::json::value_from_tag,
boost::json::value& jv,
const LayerInfo& record);
LayerInfo tag_invoke(boost::json::value_to_tag<LayerInfo>,
const boost::json::value& jv);
} // namespace types } // namespace types
} // namespace qt } // namespace qt
} // namespace scwx } // namespace scwx