diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index 82a7bb3c..d1676d7a 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -23,10 +23,11 @@ namespace map static const std::string logPrefix_ = "scwx::qt::map::alert_layer"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); -static void AddAlertLayer(std::shared_ptr map, - awips::Phenomenon phenomenon, - bool alertActive, - const QString& beforeLayer); +static std::vector +AddAlertLayer(std::shared_ptr map, + awips::Phenomenon phenomenon, + bool alertActive, + const QString& beforeLayer); static QMapLibreGL::Feature CreateFeature(const awips::CodedLocation& codedLocation); static QMapLibreGL::Coordinate @@ -139,15 +140,17 @@ AlertLayer::AlertLayer(std::shared_ptr context) : AlertLayer::~AlertLayer() = default; -void AlertLayer::AddLayers(awips::Phenomenon phenomenon, - const std::string& before) +std::vector AlertLayer::AddLayers(awips::Phenomenon phenomenon, + const std::string& before) { logger_->debug("AddLayers(): {}", awips::GetPhenomenonCode(phenomenon)); + std::vector layers {}; + auto map = p->context_->map().lock(); if (map == nullptr) { - return; + return layers; } const QString beforeLayer {QString::fromStdString(before)}; @@ -156,31 +159,11 @@ void AlertLayer::AddLayers(awips::Phenomenon phenomenon, for (bool alertActive : {false, true}) { p->UpdateSource(phenomenon, alertActive); - AddAlertLayer(map, phenomenon, alertActive, beforeLayer); - } -} - -void AlertLayer::AddLayers(const std::string& before) -{ - logger_->debug("AddLayers()"); - - auto map = p->context_->map().lock(); - if (map == nullptr) - { - return; + auto newLayers = AddAlertLayer(map, phenomenon, alertActive, beforeLayer); + layers.insert(layers.end(), newLayers.cbegin(), newLayers.cend()); } - const QString beforeLayer {QString::fromStdString(before)}; - - // Add/update GeoJSON sources and create layers - for (auto& phenomenon : kAlertPhenomena_) - { - for (bool alertActive : {false, true}) - { - p->UpdateSource(phenomenon, alertActive); - AddAlertLayer(map, phenomenon, alertActive, beforeLayer); - } - } + return layers; } std::list* @@ -387,10 +370,11 @@ std::shared_ptr AlertLayerHandler::Instance() return alertLayerHandler; } -static void AddAlertLayer(std::shared_ptr map, - awips::Phenomenon phenomenon, - bool alertActive, - const QString& beforeLayer) +static std::vector +AddAlertLayer(std::shared_ptr map, + awips::Phenomenon phenomenon, + bool alertActive, + const QString& beforeLayer) { settings::PaletteSettings& paletteSettings = settings::PaletteSettings::Instance(); @@ -438,6 +422,8 @@ static void AddAlertLayer(std::shared_ptr map, .arg(outlineColor[3])); map->setPaintProperty(fgLayerId, "line-opacity", QString("%1").arg(opacity)); map->setPaintProperty(fgLayerId, "line-width", "3"); + + return {bgLayerId.toStdString(), fgLayerId.toStdString()}; } static QMapLibreGL::Feature diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.hpp b/scwx-qt/source/scwx/qt/map/alert_layer.hpp index e728118a..6ce681a9 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.hpp @@ -4,6 +4,8 @@ #include #include +#include +#include namespace scwx { @@ -20,8 +22,8 @@ public: explicit AlertLayer(std::shared_ptr context); ~AlertLayer(); - void AddLayers(awips::Phenomenon phenomenon, const std::string& before = {}); - void AddLayers(const std::string& before = {}); + std::vector AddLayers(awips::Phenomenon phenomenon, + const std::string& before = {}); private: std::unique_ptr p; diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index ff5a53b4..52c177bd 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -131,7 +131,7 @@ public: const std::string& before = {}); void AddLayers(); void AddPlacefileLayer(const std::string& placefileName, - const std::string& before = "colorTable"); + const std::string& before); void ConnectSignals(); void ImGuiCheckFonts(); void InitializeNewRadarProductView(const std::string& colorPalette); @@ -139,11 +139,9 @@ public: void RadarProductManagerDisconnect(); void RadarProductViewConnect(); void RadarProductViewDisconnect(); - void RemovePlacefileLayer(const std::string& placefileName); void RunMousePicking(); void SetRadarSite(const std::string& radarSite); void UpdateLoadedStyle(); - void UpdatePlacefileLayers(); bool UpdateStoredMapParameters(); std::string FindMapSymbologyLayer(); @@ -174,6 +172,9 @@ public: bool imGuiRendererInitialized_; std::uint64_t imGuiFontsBuildCount_ {}; + std::shared_ptr layerModel_ { + model::LayerModel::Instance()}; + std::shared_ptr placefileManager_ { manager::PlacefileManager::Instance()}; std::shared_ptr radarProductManager_; @@ -186,7 +187,6 @@ public: std::shared_ptr placefileLayer_; std::shared_ptr colorTableLayer_; - std::set enabledPlacefiles_ {}; std::list> placefileLayers_ {}; bool autoRefreshEnabled_; @@ -237,62 +237,59 @@ MapWidget::~MapWidget() void MapWidgetImpl::ConnectSignals() { - connect(placefileManager_.get(), - &manager::PlacefileManager::PlacefileEnabled, - widget_, - [this](const std::string& name, bool enabled) - { - if (enabled && !enabledPlacefiles_.contains(name)) - { - // Placefile enabled, add layer - enabledPlacefiles_.emplace(name); - UpdatePlacefileLayers(); - } - else if (!enabled && enabledPlacefiles_.contains(name)) - { - // Placefile disabled, remove layer - enabledPlacefiles_.erase(name); - RemovePlacefileLayer(name); - } - widget_->update(); - }); - connect(placefileManager_.get(), - &manager::PlacefileManager::PlacefileRemoved, - widget_, - [this](const std::string& name) - { - if (enabledPlacefiles_.contains(name)) - { - // Placefile removed, remove layer - enabledPlacefiles_.erase(name); - RemovePlacefileLayer(name); - } - widget_->update(); - }); - connect(placefileManager_.get(), - &manager::PlacefileManager::PlacefileRenamed, - widget_, - [this](const std::string& oldName, const std::string& newName) - { - if (enabledPlacefiles_.contains(oldName)) - { - // Remove old placefile layer - enabledPlacefiles_.erase(oldName); - RemovePlacefileLayer(oldName); - } - if (!enabledPlacefiles_.contains(newName) && - placefileManager_->placefile_enabled(newName)) - { - // Add new placefile layer - enabledPlacefiles_.emplace(newName); - UpdatePlacefileLayers(); - } - widget_->update(); - }); connect(placefileManager_.get(), &manager::PlacefileManager::PlacefileUpdated, widget_, [this]() { widget_->update(); }); + + // When the layer model changes, update the layers + connect(layerModel_.get(), + &QAbstractItemModel::dataChanged, + widget_, + [this](const QModelIndex& topLeft, + const QModelIndex& bottomRight, + const QList& /* roles */) + { + static const int enabledColumn = + static_cast(model::LayerModel::Column::Enabled); + const int displayColumn = + static_cast(model::LayerModel::Column::DisplayMap1) + + static_cast(id_); + + // Update layers if the displayed or enabled state of the layer + // has changed + if ((topLeft.column() <= displayColumn && + displayColumn <= bottomRight.column()) || + (topLeft.column() <= enabledColumn && + enabledColumn <= bottomRight.column())) + { + AddLayers(); + } + }); + connect(layerModel_.get(), + &QAbstractItemModel::modelReset, + widget_, + [this]() { AddLayers(); }); + connect(layerModel_.get(), + &QAbstractItemModel::rowsInserted, + widget_, + [this](const QModelIndex& /* parent */, // + int /* first */, + int /* last */) { AddLayers(); }); + connect(layerModel_.get(), + &QAbstractItemModel::rowsMoved, + widget_, + [this](const QModelIndex& /* sourceParent */, + int /* sourceStart */, + int /* sourceEnd */, + const QModelIndex& /* destinationParent */, + int /* destinationRow */) { AddLayers(); }); + connect(layerModel_.get(), + &QAbstractItemModel::rowsRemoved, + widget_, + [this](const QModelIndex& /* parent */, // + int /* first */, + int /* last */) { AddLayers(); }); } common::Level3ProductCategoryMap MapWidget::GetAvailableLevel3Categories() @@ -756,7 +753,7 @@ void MapWidget::changeStyle() void MapWidget::DumpLayerList() const { - logger_->debug("Layers: {}", p->map_->layerIds().join(", ").toStdString()); + logger_->info("Layers: {}", p->map_->layerIds().join(", ").toStdString()); } std::string MapWidgetImpl::FindMapSymbologyLayer() @@ -789,6 +786,12 @@ std::string MapWidgetImpl::FindMapSymbologyLayer() void MapWidgetImpl::AddLayers() { + if (styleLayers_.isEmpty()) + { + // Skip if the map has not yet been initialized + return; + } + logger_->debug("Add Layers"); // Clear custom layers @@ -855,7 +858,9 @@ void MapWidgetImpl::AddLayer(types::LayerType type, else if (type == types::LayerType::Alert) { // Add the alert layer for the phenomenon - alertLayer_->AddLayers(std::get(description), before); + auto newLayers = alertLayer_->AddLayers( + std::get(description), before); + layerList_.insert(layerList_.end(), newLayers.cbegin(), newLayers.cend()); } else if (type == types::LayerType::Placefile) { @@ -904,6 +909,7 @@ void MapWidgetImpl::AddLayer(types::LayerType type, radarProductView->range(), {radarSite->latitude(), radarSite->longitude()}, QString::fromStdString(before)); + layerList_.push_back(types::GetLayerName(type, description)); } break; @@ -913,52 +919,6 @@ void MapWidgetImpl::AddLayer(types::LayerType type, } } -void MapWidgetImpl::RemovePlacefileLayer(const std::string& placefileName) -{ - std::string layerName = GetPlacefileLayerName(placefileName); - - // Remove layer from map - map_->removeLayer(layerName.c_str()); - - // Remove layer from internal layer list - auto layerIt = std::find(layerList_.begin(), layerList_.end(), layerName); - if (layerIt != layerList_.end()) - { - layerList_.erase(layerIt); - } - - // Determine if a layer exists for the placefile - auto placefileIt = - std::find_if(placefileLayers_.begin(), - placefileLayers_.end(), - [&placefileName](auto& layer) - { return placefileName == layer->placefile_name(); }); - if (placefileIt != placefileLayers_.end()) - { - placefileLayers_.erase(placefileIt); - } -} - -void MapWidgetImpl::UpdatePlacefileLayers() -{ - // Loop through enabled placefiles - for (auto& placefileName : enabledPlacefiles_) - { - // Determine if a layer exists for the placefile - auto it = std::find_if(placefileLayers_.begin(), - placefileLayers_.end(), - [&placefileName](auto& layer) { - return placefileName == layer->placefile_name(); - }); - - // If the layer doesn't exist, create it - if (it == placefileLayers_.end()) - { - AddPlacefileLayer(placefileName); - } - } -} - void MapWidgetImpl::AddPlacefileLayer(const std::string& placefileName, const std::string& before) { @@ -988,9 +948,16 @@ void MapWidgetImpl::AddLayer(const std::string& id, std::unique_ptr pHost = std::make_unique(layer); - map_->addCustomLayer(id.c_str(), std::move(pHost), before.c_str()); + try + { + map_->addCustomLayer(id.c_str(), std::move(pHost), before.c_str()); - layerList_.push_back(id); + layerList_.push_back(id); + } + catch (const std::exception&) + { + // When dragging and dropping, a temporary duplicate layer exists + } } void MapWidget::enterEvent(QEnterEvent* /* ev */) diff --git a/scwx-qt/source/scwx/qt/model/layer_model.cpp b/scwx-qt/source/scwx/qt/model/layer_model.cpp index f52475e1..a153f4f2 100644 --- a/scwx-qt/source/scwx/qt/model/layer_model.cpp +++ b/scwx-qt/source/scwx/qt/model/layer_model.cpp @@ -71,6 +71,10 @@ public: ~Impl() = default; void AddPlacefile(const std::string& name); + void HandlePlacefileRemoved(const std::string& name); + void HandlePlacefileRenamed(const std::string& oldName, + const std::string& newName); + void HandlePlacefileUpdate(const std::string& name, Column column); void InitializeLayerSettings(); void ReadLayerSettings(); void SynchronizePlacefileLayers(); @@ -102,22 +106,26 @@ LayerModel::LayerModel(QObject* parent) : connect(p->placefileManager_.get(), &manager::PlacefileManager::PlacefileEnabled, this, - &LayerModel::HandlePlacefileUpdate); + [this](const std::string& name, bool /* enabled */) + { p->HandlePlacefileUpdate(name, Column::Enabled); }); connect(p->placefileManager_.get(), &manager::PlacefileManager::PlacefileRemoved, this, - &LayerModel::HandlePlacefileRemoved); + [this](const std::string& name) + { p->HandlePlacefileRemoved(name); }); connect(p->placefileManager_.get(), &manager::PlacefileManager::PlacefileRenamed, this, - &LayerModel::HandlePlacefileRenamed); + [this](const std::string& oldName, const std::string& newName) + { p->HandlePlacefileRenamed(oldName, newName); }); connect(p->placefileManager_.get(), &manager::PlacefileManager::PlacefileUpdated, this, - &LayerModel::HandlePlacefileUpdate); + [this](const std::string& name) + { p->HandlePlacefileUpdate(name, Column::Description); }); p->InitializeLayerSettings(); p->ReadLayerSettings(); @@ -908,88 +916,92 @@ bool LayerModel::moveRows(const QModelIndex& sourceParent, return moved; } -void LayerModel::HandlePlacefileRemoved(const std::string& name) +void LayerModel::Impl::HandlePlacefileRemoved(const std::string& name) { auto it = - std::find_if(p->layers_.begin(), - p->layers_.end(), + std::find_if(layers_.begin(), + layers_.end(), [&name](const auto& layer) { return layer.type_ == types::LayerType::Placefile && std::get(layer.description_) == name; }); - if (it != p->layers_.end()) + if (it != layers_.end()) { // Placefile exists, delete row - const int row = std::distance(p->layers_.begin(), it); + const int row = std::distance(layers_.begin(), it); - beginRemoveRows(QModelIndex(), row, row); - p->layers_.erase(it); - endRemoveRows(); + self_->beginRemoveRows(QModelIndex(), row, row); + layers_.erase(it); + self_->endRemoveRows(); } } -void LayerModel::HandlePlacefileRenamed(const std::string& oldName, - const std::string& newName) +void LayerModel::Impl::HandlePlacefileRenamed(const std::string& oldName, + const std::string& newName) { auto it = std::find_if( - p->layers_.begin(), - p->layers_.end(), + layers_.begin(), + layers_.end(), [&oldName](const auto& layer) { return layer.type_ == types::LayerType::Placefile && std::get(layer.description_) == oldName; }); - if (it != p->layers_.end()) + if (it != layers_.end()) { // Placefile exists, mark row as updated - const int row = std::distance(p->layers_.begin(), it); - QModelIndex topLeft = createIndex(row, kFirstColumn); - QModelIndex bottomRight = createIndex(row, kLastColumn); + const int row = std::distance(layers_.begin(), it); + QModelIndex topLeft = + self_->createIndex(row, static_cast(Column::Description)); + QModelIndex bottomRight = + self_->createIndex(row, static_cast(Column::Description)); // Rename placefile it->description_ = newName; - Q_EMIT dataChanged(topLeft, bottomRight); + Q_EMIT self_->dataChanged(topLeft, bottomRight); } else { // Placefile doesn't exist, add row - p->AddPlacefile(newName); + AddPlacefile(newName); } } -void LayerModel::HandlePlacefileUpdate(const std::string& name) +void LayerModel::Impl::HandlePlacefileUpdate(const std::string& name, + Column column) { - if (!p->placefilesInitialized_) + if (!placefilesInitialized_) { - p->initialPlacefiles_.push_back(name); + initialPlacefiles_.push_back(name); } auto it = - std::find_if(p->layers_.begin(), - p->layers_.end(), + std::find_if(layers_.begin(), + layers_.end(), [&name](const auto& layer) { return layer.type_ == types::LayerType::Placefile && std::get(layer.description_) == name; }); - if (it != p->layers_.end()) + if (it != layers_.end()) { // Placefile exists, mark row as updated - const int row = std::distance(p->layers_.begin(), it); - QModelIndex topLeft = createIndex(row, kFirstColumn); - QModelIndex bottomRight = createIndex(row, kLastColumn); + const int row = std::distance(layers_.begin(), it); + QModelIndex topLeft = self_->createIndex(row, static_cast(column)); + QModelIndex bottomRight = + self_->createIndex(row, static_cast(column)); - Q_EMIT dataChanged(topLeft, bottomRight); + Q_EMIT self_->dataChanged(topLeft, bottomRight); } else { // Placefile doesn't exist, add row - p->AddPlacefile(name); + AddPlacefile(name); } } diff --git a/scwx-qt/source/scwx/qt/model/layer_model.hpp b/scwx-qt/source/scwx/qt/model/layer_model.hpp index 893264bc..426615c7 100644 --- a/scwx-qt/source/scwx/qt/model/layer_model.hpp +++ b/scwx-qt/source/scwx/qt/model/layer_model.hpp @@ -77,12 +77,6 @@ public: static std::shared_ptr Instance(); -public slots: - void HandlePlacefileRemoved(const std::string& name); - void HandlePlacefileRenamed(const std::string& oldName, - const std::string& newName); - void HandlePlacefileUpdate(const std::string& name); - private: class Impl; std::unique_ptr p;