From 1ab0d62b1fd33cab983a0178e75e1b193a4ea9ff Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 10 Oct 2022 14:44:07 -0500 Subject: [PATCH] Separating tree model from radar product model --- scwx-qt/source/scwx/qt/main/main_window.cpp | 5 +- .../scwx/qt/model/radar_product_model.cpp | 44 ++++----- .../scwx/qt/model/radar_product_model.hpp | 9 +- scwx-qt/source/scwx/qt/model/tree_item.cpp | 92 ++++++++++++------- scwx-qt/source/scwx/qt/model/tree_item.hpp | 8 +- scwx-qt/source/scwx/qt/model/tree_model.cpp | 87 ++++++++++++++++-- scwx-qt/source/scwx/qt/model/tree_model.hpp | 16 +++- 7 files changed, 182 insertions(+), 79 deletions(-) diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index 6b2c4e0f..0f944510 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -45,6 +45,7 @@ public: level2ProductsWidget_ {nullptr}, level2SettingsWidget_ {nullptr}, radarSiteDialog_ {nullptr}, + radarProductModel_ {nullptr}, maps_ {}, elevationCuts_ {}, elevationButtonsChanged_ {false}, @@ -104,6 +105,8 @@ public: ui::RadarSiteDialog* radarSiteDialog_; + std::shared_ptr radarProductModel_; + std::vector maps_; std::vector elevationCuts_; @@ -144,7 +147,7 @@ MainWindow::MainWindow(QWidget* parent) : // Configure Docks ui->resourceExplorerDock->setVisible(false); - ui->resourceTreeView->setModel(new model::RadarProductModel(this)); + p->radarProductModel_ = std::make_shared(); // Configure Map p->ConfigureMapLayout(); diff --git a/scwx-qt/source/scwx/qt/model/radar_product_model.cpp b/scwx-qt/source/scwx/qt/model/radar_product_model.cpp index 9af76a52..3608f49f 100644 --- a/scwx-qt/source/scwx/qt/model/radar_product_model.cpp +++ b/scwx-qt/source/scwx/qt/model/radar_product_model.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -22,38 +23,24 @@ public: explicit RadarProductModelImpl(RadarProductModel* self); ~RadarProductModelImpl() = default; - void AppendRow(TreeItem* parent, TreeItem* child); - - RadarProductModel* self_; - std::shared_ptr rootItem_; + RadarProductModel* self_; + std::unique_ptr model_; }; -RadarProductModel::RadarProductModel(QObject* parent) : - TreeModel(parent), p(std::make_unique(this)) +RadarProductModel::RadarProductModel() : + p(std::make_unique(this)) { } RadarProductModel::~RadarProductModel() = default; -const std::shared_ptr RadarProductModel::root_item() const +QAbstractItemModel* RadarProductModel::model() { - return p->rootItem_; -} - -void RadarProductModelImpl::AppendRow(TreeItem* parent, TreeItem* child) -{ - const QModelIndex parentIndex = self_->createIndex(parent->row(), 0, parent); - const int childCount = parent->child_count(); - const int first = childCount; - const int last = childCount; - - self_->beginInsertRows(parentIndex, first, last); - parent->AppendChild(child); - self_->endInsertRows(); + return p->model_.get(); } RadarProductModelImpl::RadarProductModelImpl(RadarProductModel* self) : self_ {self}, - rootItem_ {std::make_shared( + model_ {std::make_unique( std::vector {QObject::tr("Product")})} { connect( @@ -67,12 +54,13 @@ RadarProductModelImpl::RadarProductModelImpl(RadarProductModel* self) : const QString radarSiteName {QString::fromStdString(radarSite)}; // Find existing radar site item (e.g., KLSX, KEAX) - TreeItem* radarSiteItem = rootItem_->FindChild(0, radarSiteName); + TreeItem* radarSiteItem = + model_->root_item()->FindChild(0, radarSiteName); if (radarSiteItem == nullptr) { radarSiteItem = new TreeItem({radarSiteName}); - AppendRow(rootItem_.get(), radarSiteItem); + model_->AppendRow(model_->root_item(), radarSiteItem); } connect( @@ -93,7 +81,7 @@ RadarProductModelImpl::RadarProductModelImpl(RadarProductModel* self) : { // Existing group item was not found, create it groupItem = new TreeItem({groupName}); - AppendRow(radarSiteItem, groupItem); + model_->AppendRow(radarSiteItem, groupItem); } TreeItem* productItem = nullptr; @@ -113,14 +101,14 @@ RadarProductModelImpl::RadarProductModelImpl(RadarProductModel* self) : { // Existing product item was not found, create it productItem = new TreeItem({productName}); - AppendRow(groupItem, productItem); + model_->AppendRow(groupItem, productItem); } } // Create leaf item for product time - AppendRow(productItem, - new TreeItem {QString::fromStdString( - util::TimeString(latestTime))}); + model_->AppendRow(productItem, + new TreeItem {QString::fromStdString( + util::TimeString(latestTime))}); }, Qt::QueuedConnection); }); diff --git a/scwx-qt/source/scwx/qt/model/radar_product_model.hpp b/scwx-qt/source/scwx/qt/model/radar_product_model.hpp index 9fb45aa2..20ac0d2c 100644 --- a/scwx-qt/source/scwx/qt/model/radar_product_model.hpp +++ b/scwx-qt/source/scwx/qt/model/radar_product_model.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace scwx { @@ -11,14 +11,13 @@ namespace model class RadarProductModelImpl; -class RadarProductModel : public TreeModel +class RadarProductModel { public: - explicit RadarProductModel(QObject* parent = nullptr); + explicit RadarProductModel(); ~RadarProductModel(); -protected: - const std::shared_ptr root_item() const override; + QAbstractItemModel* model(); private: std::unique_ptr p; diff --git a/scwx-qt/source/scwx/qt/model/tree_item.cpp b/scwx-qt/source/scwx/qt/model/tree_item.cpp index e43ef4c2..34e2289b 100644 --- a/scwx-qt/source/scwx/qt/model/tree_item.cpp +++ b/scwx-qt/source/scwx/qt/model/tree_item.cpp @@ -18,9 +18,9 @@ public: } ~Impl() { qDeleteAll(childItems_); } - std::vector childItems_; - std::vector itemData_; - TreeItem* parentItem_; + QList childItems_; + std::vector itemData_; + TreeItem* parentItem_; }; TreeItem::TreeItem(const std::vector& data, TreeItem* parent) : @@ -38,30 +38,6 @@ TreeItem::~TreeItem() {} TreeItem::TreeItem(TreeItem&&) noexcept = default; TreeItem& TreeItem::operator=(TreeItem&&) noexcept = default; -void TreeItem::AppendChild(TreeItem* item) -{ - item->p->parentItem_ = this; - p->childItems_.push_back(item); -} - -TreeItem* TreeItem::FindChild(int column, const QVariant& data) -{ - auto it = std::find_if(p->childItems_.begin(), - p->childItems_.end(), - [&](auto& item) { - return (column < item->column_count() && - item->data(column) == data); - }); - - TreeItem* item = nullptr; - if (it != p->childItems_.end()) - { - item = *it; - } - - return item; -} - const TreeItem* TreeItem::child(int row) const { const TreeItem* item = nullptr; @@ -88,7 +64,9 @@ TreeItem* TreeItem::child(int row) std::vector TreeItem::children() { - return p->childItems_; + std::vector children(p->childItems_.cbegin(), + p->childItems_.cend()); + return children; } int TreeItem::child_count() const @@ -119,10 +97,7 @@ int TreeItem::row() const if (p->parentItem_ != nullptr) { - const auto& childItems = p->parentItem_->p->childItems_; - row = - std::distance(childItems.cbegin(), - std::find(childItems.cbegin(), childItems.cend(), this)); + row = p->parentItem_->p->childItems_.indexOf(this); } return row; @@ -133,6 +108,59 @@ const TreeItem* TreeItem::parent_item() const return p->parentItem_; } +void TreeItem::AppendChild(TreeItem* item) +{ + item->p->parentItem_ = this; + p->childItems_.push_back(item); +} + +TreeItem* TreeItem::FindChild(int column, const QVariant& data) +{ + auto it = std::find_if(p->childItems_.begin(), + p->childItems_.end(), + [&](auto& item) { + return (column < item->column_count() && + item->data(column) == data); + }); + + TreeItem* item = nullptr; + if (it != p->childItems_.end()) + { + item = *it; + } + + return item; +} + +bool TreeItem::InsertChildren(int position, int count, int columns) +{ + if (position < 0 || position > p->childItems_.size()) + { + return false; + } + + std::vector data(columns); + + for (int row = 0; row < count; ++row) + { + TreeItem* item = new TreeItem(data, this); + p->childItems_.insert(position, item); + } + + return true; +} + +bool TreeItem::SetData(int column, const QVariant& value) +{ + if (column < 0 || column >= p->itemData_.size()) + { + return false; + } + + p->itemData_[column] = value; + return true; +} + } // namespace model } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/model/tree_item.hpp b/scwx-qt/source/scwx/qt/model/tree_item.hpp index de3eb54e..625bfbd9 100644 --- a/scwx-qt/source/scwx/qt/model/tree_item.hpp +++ b/scwx-qt/source/scwx/qt/model/tree_item.hpp @@ -27,9 +27,6 @@ public: TreeItem(TreeItem&&) noexcept; TreeItem& operator=(TreeItem&&) noexcept; - void AppendChild(TreeItem* child); - TreeItem* FindChild(int column, const QVariant& data); - const TreeItem* child(int row) const; TreeItem* child(int row); std::vector children(); @@ -39,6 +36,11 @@ public: int row() const; const TreeItem* parent_item() const; + void AppendChild(TreeItem* child); + TreeItem* FindChild(int column, const QVariant& data); + bool InsertChildren(int position, int count, int columns); + bool SetData(int column, const QVariant& value); + private: class Impl; std::unique_ptr p; diff --git a/scwx-qt/source/scwx/qt/model/tree_model.cpp b/scwx-qt/source/scwx/qt/model/tree_model.cpp index e24585a3..e816a580 100644 --- a/scwx-qt/source/scwx/qt/model/tree_model.cpp +++ b/scwx-qt/source/scwx/qt/model/tree_model.cpp @@ -12,21 +12,42 @@ static const std::string logPrefix_ = "scwx::qt::model::tree_model"; class TreeModelImpl { public: - explicit TreeModelImpl(TreeModel* self) : self_ {self} {}; + explicit TreeModelImpl(TreeModel* self, + const std::vector& headerData) : + self_ {self}, rootItem_ {std::make_unique(headerData)} {}; ~TreeModelImpl() = default; const TreeItem* item(const QModelIndex& index) const; TreeItem* item(const QModelIndex& index); - TreeModel* self_; + TreeModel* self_; + std::unique_ptr rootItem_; }; -TreeModel::TreeModel(QObject* parent) : - QAbstractItemModel(parent), p(std::make_unique(this)) +TreeModel::TreeModel(const std::vector& headerData, QObject* parent) : + QAbstractItemModel(parent), + p(std::make_unique(this, headerData)) { } + +TreeModel::TreeModel(std::initializer_list headerData, + QObject* parent) : + TreeModel(std::vector {headerData}, parent) +{ +} + TreeModel::~TreeModel() = default; +const TreeItem* TreeModel::root_item() const +{ + return p->rootItem_.get(); +} + +TreeItem* TreeModel::root_item() +{ + return p->rootItem_.get(); +} + int TreeModel::rowCount(const QModelIndex& parent) const { const TreeItem* parentItem = p->item(parent); @@ -110,7 +131,7 @@ QModelIndex TreeModel::parent(const QModelIndex& index) const const TreeItem* childItem = p->item(index); const TreeItem* parentItem = childItem ? childItem->parent_item() : nullptr; - if (parentItem == root_item().get() || parentItem == nullptr) + if (parentItem == p->rootItem_.get() || parentItem == nullptr) { return QModelIndex(); } @@ -118,6 +139,58 @@ QModelIndex TreeModel::parent(const QModelIndex& index) const return createIndex(parentItem->row(), 0, parentItem); } +bool TreeModel::insertRows(int row, int count, const QModelIndex& parent) +{ + TreeItem* parentItem = p->item(parent); + if (parentItem == nullptr) + { + return false; + } + + beginInsertRows(parent, row, row + count - 1); + bool result = parentItem->InsertChildren(row, count, columnCount(parent)); + endInsertRows(); + + return result; +} + +bool TreeModel::setData(const QModelIndex& index, + const QVariant& value, + int role) +{ + if (!index.isValid() || role != Qt::EditRole) + { + return false; + } + + TreeItem* item = p->item(index); + if (item == nullptr) + { + return false; + } + + bool result = item->SetData(index.column(), value); + + if (result) + { + emit dataChanged(index, index); + } + + return result; +} + +void TreeModel::AppendRow(TreeItem* parent, TreeItem* child) +{ + const QModelIndex parentIndex = createIndex(parent->row(), 0, parent); + const int childCount = parent->child_count(); + const int first = childCount; + const int last = childCount; + + beginInsertRows(parentIndex, first, last); + parent->AppendChild(child); + endInsertRows(); +} + const TreeItem* TreeModelImpl::item(const QModelIndex& index) const { if (index.isValid()) @@ -129,7 +202,7 @@ const TreeItem* TreeModelImpl::item(const QModelIndex& index) const return item; } } - return self_->root_item().get(); + return rootItem_.get(); } TreeItem* TreeModelImpl::item(const QModelIndex& index) @@ -142,7 +215,7 @@ TreeItem* TreeModelImpl::item(const QModelIndex& index) return item; } } - return self_->root_item().get(); + return rootItem_.get(); } } // namespace model diff --git a/scwx-qt/source/scwx/qt/model/tree_model.hpp b/scwx-qt/source/scwx/qt/model/tree_model.hpp index eae47254..80cd428a 100644 --- a/scwx-qt/source/scwx/qt/model/tree_model.hpp +++ b/scwx-qt/source/scwx/qt/model/tree_model.hpp @@ -16,9 +16,15 @@ class TreeModelImpl; class TreeModel : public QAbstractItemModel { public: - explicit TreeModel(QObject* parent = nullptr); + explicit TreeModel(const std::vector& headerData, + QObject* parent = nullptr); + explicit TreeModel(std::initializer_list headerData, + QObject* parent = nullptr); virtual ~TreeModel(); + const TreeItem* root_item() const; + TreeItem* root_item(); + int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; @@ -33,8 +39,12 @@ public: const QModelIndex& parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& index) const override; -protected: - virtual const std::shared_ptr root_item() const = 0; + bool insertRows(int row, int count, const QModelIndex& parent) override; + bool setData(const QModelIndex& index, + const QVariant& value, + int role = Qt::EditRole) override; + + void AppendRow(TreeItem* parent, TreeItem* child); private: friend class TreeModelImpl;