diff --git a/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp b/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp index ec496de4..83cf97c1 100644 --- a/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp @@ -66,7 +66,7 @@ public: PlacefileManager::PlacefileManager() : p(std::make_unique(this)) {} PlacefileManager::~PlacefileManager() = default; -bool PlacefileManager::PlacefileEnabled(const std::string& name) +bool PlacefileManager::placefile_enabled(const std::string& name) { std::shared_lock lock(p->placefileRecordLock_); @@ -78,7 +78,7 @@ bool PlacefileManager::PlacefileEnabled(const std::string& name) return false; } -bool PlacefileManager::PlacefileThresholded(const std::string& name) +bool PlacefileManager::placefile_thresholded(const std::string& name) { std::shared_lock lock(p->placefileRecordLock_); @@ -91,7 +91,7 @@ bool PlacefileManager::PlacefileThresholded(const std::string& name) } std::shared_ptr -PlacefileManager::Placefile(const std::string& name) +PlacefileManager::placefile(const std::string& name) { std::shared_lock lock(p->placefileRecordLock_); @@ -103,6 +103,60 @@ PlacefileManager::Placefile(const std::string& name) return nullptr; } +void PlacefileManager::set_placefile_enabled(const std::string& name, + bool enabled) +{ + std::shared_lock lock(p->placefileRecordLock_); + + auto it = p->placefileRecordMap_.find(name); + if (it != p->placefileRecordMap_.cend()) + { + it->second->enabled_ = enabled; + + lock.unlock(); + + Q_EMIT PlacefileEnabled(name, enabled); + } +} + +void PlacefileManager::set_placefile_thresholded(const std::string& name, + bool thresholded) +{ + std::shared_lock lock(p->placefileRecordLock_); + + auto it = p->placefileRecordMap_.find(name); + if (it != p->placefileRecordMap_.cend()) + { + it->second->thresholded_ = thresholded; + + lock.unlock(); + + Q_EMIT PlacefileUpdated(name); + } +} + +void PlacefileManager::set_placefile_url(const std::string& name, + const std::string& newUrl) +{ + std::unique_lock lock(p->placefileRecordLock_); + + auto it = p->placefileRecordMap_.find(name); + auto itNew = p->placefileRecordMap_.find(newUrl); + if (it != p->placefileRecordMap_.cend() && + itNew == p->placefileRecordMap_.cend()) + { + auto placefileRecord = it->second; + placefileRecord->name_ = newUrl; + placefileRecord->placefile_ = nullptr; + p->placefileRecordMap_.erase(it); + p->placefileRecordMap_.emplace(newUrl, placefileRecord); + + lock.unlock(); + + Q_EMIT PlacefileRenamed(name, newUrl); + } +} + std::vector> PlacefileManager::GetActivePlacefiles() { @@ -112,7 +166,7 @@ PlacefileManager::GetActivePlacefiles() for (const auto& record : p->placefileRecords_) { - if (record->enabled_) + if (record->enabled_ && record->placefile_ != nullptr) { placefiles.emplace_back(record->placefile_); } diff --git a/scwx-qt/source/scwx/qt/manager/placefile_manager.hpp b/scwx-qt/source/scwx/qt/manager/placefile_manager.hpp index 4036a3b0..d763ef3a 100644 --- a/scwx-qt/source/scwx/qt/manager/placefile_manager.hpp +++ b/scwx-qt/source/scwx/qt/manager/placefile_manager.hpp @@ -19,9 +19,13 @@ public: explicit PlacefileManager(); ~PlacefileManager(); - bool PlacefileEnabled(const std::string& name); - bool PlacefileThresholded(const std::string& name); - std::shared_ptr Placefile(const std::string& name); + bool placefile_enabled(const std::string& name); + bool placefile_thresholded(const std::string& name); + std::shared_ptr placefile(const std::string& name); + + void set_placefile_enabled(const std::string& name, bool enabled); + void set_placefile_thresholded(const std::string& name, bool thresholded); + void set_placefile_url(const std::string& name, const std::string& newUrl); /** * @brief Gets a list of active placefiles @@ -37,6 +41,8 @@ public: signals: void PlacefileEnabled(const std::string& name, bool enabled); + void PlacefileRenamed(const std::string& oldName, + const std::string& newName); void PlacefileUpdated(const std::string& name); private: diff --git a/scwx-qt/source/scwx/qt/model/placefile_model.cpp b/scwx-qt/source/scwx/qt/model/placefile_model.cpp index 7fbf5984..87d81c28 100644 --- a/scwx-qt/source/scwx/qt/model/placefile_model.cpp +++ b/scwx-qt/source/scwx/qt/model/placefile_model.cpp @@ -40,6 +40,16 @@ public: PlacefileModel::PlacefileModel(QObject* parent) : QAbstractTableModel(parent), p(std::make_unique()) { + connect(p->placefileManager_.get(), + &manager::PlacefileManager::PlacefileEnabled, + this, + &PlacefileModel::HandlePlacefileUpdate); + + connect(p->placefileManager_.get(), + &manager::PlacefileManager::PlacefileRenamed, + this, + &PlacefileModel::HandlePlacefileRenamed); + connect(p->placefileManager_.get(), &manager::PlacefileManager::PlacefileUpdated, this, @@ -65,7 +75,12 @@ Qt::ItemFlags PlacefileModel::flags(const QModelIndex& index) const { case static_cast(Column::Enabled): case static_cast(Column::Thresholds): - flags |= Qt::ItemFlag::ItemIsUserCheckable; + flags |= Qt::ItemFlag::ItemIsUserCheckable | Qt::ItemFlag::ItemIsEditable; + break; + + case static_cast(Column::Placefile): + flags |= Qt::ItemFlag::ItemIsEditable; + break; default: break; @@ -76,6 +91,14 @@ Qt::ItemFlags PlacefileModel::flags(const QModelIndex& index) const QVariant PlacefileModel::data(const QModelIndex& index, int role) const { + static const QString enabledString = QObject::tr("Enabled"); + static const QString disabledString = QObject::tr("Disabled"); + + static const QString thresholdsEnabledString = + QObject::tr("Thresholds Enabled"); + static const QString thresholdsDisabledString = + QObject::tr("Thresholds Disabled"); + if (!index.isValid() || index.row() < 0 || static_cast(index.row()) >= p->placefileNames_.size()) { @@ -84,41 +107,54 @@ QVariant PlacefileModel::data(const QModelIndex& index, int role) const const auto& placefileName = p->placefileNames_.at(index.row()); - if (role == Qt::ItemDataRole::DisplayRole || - role == Qt::ItemDataRole::ToolTipRole) + switch (index.column()) { - static const QString enabledString = QObject::tr("Enabled"); - static const QString disabledString = QObject::tr("Disabled"); - - static const QString thresholdsEnabledString = - QObject::tr("Thresholds Enabled"); - static const QString thresholdsDisabledString = - QObject::tr("Thresholds Disabled"); - - switch (index.column()) + case static_cast(Column::Enabled): + if (role == Qt::ItemDataRole::ToolTipRole) { - case static_cast(Column::Enabled): - if (role == Qt::ItemDataRole::ToolTipRole) - { - return p->placefileManager_->PlacefileEnabled(placefileName) ? - enabledString : - disabledString; - } - break; + return p->placefileManager_->placefile_enabled(placefileName) ? + enabledString : + disabledString; + } + else if (role == Qt::ItemDataRole::CheckStateRole) + { + return static_cast( + p->placefileManager_->placefile_enabled(placefileName) ? + Qt::CheckState::Checked : + Qt::CheckState::Unchecked); + } + else if (role == types::ItemDataRole::SortRole) + { + return p->placefileManager_->placefile_enabled(placefileName); + } + break; - case static_cast(Column::Thresholds): - if (role == Qt::ItemDataRole::ToolTipRole) - { - return p->placefileManager_->PlacefileThresholded(placefileName) ? - thresholdsEnabledString : - thresholdsDisabledString; - } - break; + case static_cast(Column::Thresholds): + if (role == Qt::ItemDataRole::ToolTipRole) + { + return p->placefileManager_->placefile_thresholded(placefileName) ? + thresholdsEnabledString : + thresholdsDisabledString; + } + else if (role == Qt::ItemDataRole::CheckStateRole) + { + return static_cast( + p->placefileManager_->placefile_thresholded(placefileName) ? + Qt::CheckState::Checked : + Qt::CheckState::Unchecked); + } + else if (role == types::ItemDataRole::SortRole) + { + return p->placefileManager_->placefile_thresholded(placefileName); + } + break; - case static_cast(Column::Placefile): + case static_cast(Column::Placefile): + if (role == Qt::ItemDataRole::DisplayRole || + role == Qt::ItemDataRole::ToolTipRole) { std::string description = placefileName; - auto placefile = p->placefileManager_->Placefile(placefileName); + auto placefile = p->placefileManager_->placefile(placefileName); if (placefile != nullptr) { std::string title = placefile->title(); @@ -130,47 +166,15 @@ QVariant PlacefileModel::data(const QModelIndex& index, int role) const return QString::fromStdString(description); } - - default: - break; - } - } - else if (role == types::ItemDataRole::SortRole) - { - switch (index.column()) + else if (role == Qt::ItemDataRole::EditRole || + role == types::ItemDataRole::SortRole) { - case static_cast(Column::Enabled): - return p->placefileManager_->PlacefileEnabled(placefileName); - - case static_cast(Column::Thresholds): - return p->placefileManager_->PlacefileThresholded(placefileName); - - case static_cast(Column::Placefile): return QString::fromStdString(placefileName); - - default: - break; } - } - else if (role == Qt::ItemDataRole::CheckStateRole) - { - switch (index.column()) - { - case static_cast(Column::Enabled): - return static_cast( - p->placefileManager_->PlacefileEnabled(placefileName) ? - Qt::CheckState::Checked : - Qt::CheckState::Unchecked); + break; - case static_cast(Column::Thresholds): - return static_cast( - p->placefileManager_->PlacefileThresholded(placefileName) ? - Qt::CheckState::Checked : - Qt::CheckState::Unchecked); - - default: - break; - } + default: + break; } return QVariant(); @@ -240,6 +244,82 @@ QVariant PlacefileModel::headerData(int section, return QVariant(); } +bool PlacefileModel::setData(const QModelIndex& index, + const QVariant& value, + int role) +{ + if (!index.isValid() || index.row() < 0 || + static_cast(index.row()) >= p->placefileNames_.size()) + { + return false; + } + + const auto& placefileName = p->placefileNames_.at(index.row()); + + switch (index.column()) + { + case static_cast(Column::Enabled): + if (role == Qt::ItemDataRole::CheckStateRole) + { + p->placefileManager_->set_placefile_enabled(placefileName, + value.toBool()); + return true; + } + break; + + case static_cast(Column::Thresholds): + if (role == Qt::ItemDataRole::CheckStateRole) + { + p->placefileManager_->set_placefile_thresholded(placefileName, + value.toBool()); + return true; + } + break; + + case static_cast(Column::Placefile): + if (role == Qt::ItemDataRole::EditRole) + { + p->placefileManager_->set_placefile_url( + placefileName, value.toString().toStdString()); + return true; + } + break; + + default: + break; + } + + return true; +} + +void PlacefileModel::HandlePlacefileRenamed(const std::string& oldName, + const std::string& newName) +{ + auto it = + std::find(p->placefileNames_.begin(), p->placefileNames_.end(), oldName); + + if (it != p->placefileNames_.end()) + { + // Placefile exists, mark row as updated + const int row = std::distance(p->placefileNames_.begin(), it); + QModelIndex topLeft = createIndex(row, kFirstColumn); + QModelIndex bottomRight = createIndex(row, kLastColumn); + + // Rename placefile + *it = newName; + + Q_EMIT dataChanged(topLeft, bottomRight); + } + else + { + // Placefile is new, append row + const int newIndex = static_cast(p->placefileNames_.size()); + beginInsertRows(QModelIndex(), newIndex, newIndex); + p->placefileNames_.push_back(newName); + endInsertRows(); + } +} + void PlacefileModel::HandlePlacefileUpdate(const std::string& name) { auto it = diff --git a/scwx-qt/source/scwx/qt/model/placefile_model.hpp b/scwx-qt/source/scwx/qt/model/placefile_model.hpp index 68bffdcf..f4f01167 100644 --- a/scwx-qt/source/scwx/qt/model/placefile_model.hpp +++ b/scwx-qt/source/scwx/qt/model/placefile_model.hpp @@ -40,7 +40,13 @@ public: Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex& index, + const QVariant& value, + int role = Qt::EditRole) override; + public slots: + void HandlePlacefileRenamed(const std::string& oldName, + const std::string& newName); void HandlePlacefileUpdate(const std::string& name); private: diff --git a/wxdata/include/scwx/gr/placefile.hpp b/wxdata/include/scwx/gr/placefile.hpp index 9a111468..4a4f624b 100644 --- a/wxdata/include/scwx/gr/placefile.hpp +++ b/wxdata/include/scwx/gr/placefile.hpp @@ -84,12 +84,14 @@ public: */ std::vector> GetDrawItems(); + std::string name() const; std::string title() const; std::unordered_map> fonts(); std::shared_ptr font(std::size_t i); static std::shared_ptr Load(const std::string& filename); - static std::shared_ptr Load(std::istream& is); + static std::shared_ptr Load(const std::string& name, + std::istream& is); private: class Impl; diff --git a/wxdata/source/scwx/gr/placefile.cpp b/wxdata/source/scwx/gr/placefile.cpp index 249d7e89..a2e62dcf 100644 --- a/wxdata/source/scwx/gr/placefile.cpp +++ b/wxdata/source/scwx/gr/placefile.cpp @@ -51,6 +51,7 @@ public: static void ProcessEscapeCharacters(std::string& s); static void TrimQuotes(std::string& s); + std::string name_ {}; std::string title_ {}; std::chrono::seconds refresh_ {-1}; @@ -85,6 +86,11 @@ std::vector> Placefile::GetDrawItems() return p->drawItems_; } +std::string Placefile::name() const +{ + return p->name_; +} + std::string Placefile::title() const { return p->title_; @@ -110,13 +116,16 @@ std::shared_ptr Placefile::Load(const std::string& filename) { logger_->debug("Loading placefile: {}", filename); std::ifstream f(filename, std::ios_base::in); - return Load(f); + return Load(filename, f); } -std::shared_ptr Placefile::Load(std::istream& is) +std::shared_ptr Placefile::Load(const std::string& name, + std::istream& is) { std::shared_ptr placefile = std::make_shared(); + placefile->p->name_ = name; + std::string line; while (scwx::util::getline(is, line)) {