Update displayed layers when the layer model changes

This commit is contained in:
Dan Paulat 2023-11-05 06:03:54 -06:00
parent c81d9d9ba6
commit 2b6f70697c
5 changed files with 142 additions and 181 deletions

View file

@ -23,7 +23,8 @@ 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<QMapLibreGL::Map> map,
static std::vector<std::string>
AddAlertLayer(std::shared_ptr<QMapLibreGL::Map> map,
awips::Phenomenon phenomenon,
bool alertActive,
const QString& beforeLayer);
@ -139,15 +140,17 @@ AlertLayer::AlertLayer(std::shared_ptr<MapContext> context) :
AlertLayer::~AlertLayer() = default;
void AlertLayer::AddLayers(awips::Phenomenon phenomenon,
std::vector<std::string> AlertLayer::AddLayers(awips::Phenomenon phenomenon,
const std::string& before)
{
logger_->debug("AddLayers(): {}", awips::GetPhenomenonCode(phenomenon));
std::vector<std::string> 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<QMapLibreGL::Feature>*
@ -387,7 +370,8 @@ std::shared_ptr<AlertLayerHandler> AlertLayerHandler::Instance()
return alertLayerHandler;
}
static void AddAlertLayer(std::shared_ptr<QMapLibreGL::Map> map,
static std::vector<std::string>
AddAlertLayer(std::shared_ptr<QMapLibreGL::Map> map,
awips::Phenomenon phenomenon,
bool alertActive,
const QString& beforeLayer)
@ -438,6 +422,8 @@ static void AddAlertLayer(std::shared_ptr<QMapLibreGL::Map> 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

View file

@ -4,6 +4,8 @@
#include <scwx/qt/map/map_context.hpp>
#include <memory>
#include <string>
#include <vector>
namespace scwx
{
@ -20,8 +22,8 @@ public:
explicit AlertLayer(std::shared_ptr<MapContext> context);
~AlertLayer();
void AddLayers(awips::Phenomenon phenomenon, const std::string& before = {});
void AddLayers(const std::string& before = {});
std::vector<std::string> AddLayers(awips::Phenomenon phenomenon,
const std::string& before = {});
private:
std::unique_ptr<AlertLayerImpl> p;

View file

@ -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<model::LayerModel> layerModel_ {
model::LayerModel::Instance()};
std::shared_ptr<manager::PlacefileManager> placefileManager_ {
manager::PlacefileManager::Instance()};
std::shared_ptr<manager::RadarProductManager> radarProductManager_;
@ -186,7 +187,6 @@ public:
std::shared_ptr<PlacefileLayer> placefileLayer_;
std::shared_ptr<ColorTableLayer> colorTableLayer_;
std::set<std::string> enabledPlacefiles_ {};
std::list<std::shared_ptr<PlacefileLayer>> 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<int>& /* roles */)
{
static const int enabledColumn =
static_cast<int>(model::LayerModel::Column::Enabled);
const int displayColumn =
static_cast<int>(model::LayerModel::Column::DisplayMap1) +
static_cast<int>(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<awips::Phenomenon>(description), before);
auto newLayers = alertLayer_->AddLayers(
std::get<awips::Phenomenon>(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<QMapLibreGL::CustomLayerHostInterface> pHost =
std::make_unique<LayerWrapper>(layer);
try
{
map_->addCustomLayer(id.c_str(), std::move(pHost), before.c_str());
layerList_.push_back(id);
}
catch (const std::exception&)
{
// When dragging and dropping, a temporary duplicate layer exists
}
}
void MapWidget::enterEvent(QEnterEvent* /* ev */)

View file

@ -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<std::string>(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,
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<std::string>(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<int>(Column::Description));
QModelIndex bottomRight =
self_->createIndex(row, static_cast<int>(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<std::string>(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<int>(column));
QModelIndex bottomRight =
self_->createIndex(row, static_cast<int>(column));
Q_EMIT dataChanged(topLeft, bottomRight);
Q_EMIT self_->dataChanged(topLeft, bottomRight);
}
else
{
// Placefile doesn't exist, add row
p->AddPlacefile(name);
AddPlacefile(name);
}
}

View file

@ -77,12 +77,6 @@ public:
static std::shared_ptr<LayerModel> 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<Impl> p;