mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 07:30:04 +00:00 
			
		
		
		
	Merge branch 'feature/resource-explorer' into develop
This commit is contained in:
		
						commit
						b2b413c48d
					
				
					 12 changed files with 708 additions and 6 deletions
				
			
		|  | @ -50,9 +50,11 @@ set(HDR_GL_DRAW source/scwx/qt/gl/draw/draw_item.hpp | |||
| set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp | ||||
|                 source/scwx/qt/gl/draw/rectangle.cpp) | ||||
| set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp | ||||
|                 source/scwx/qt/manager/radar_product_manager_notifier.hpp | ||||
|                 source/scwx/qt/manager/resource_manager.hpp | ||||
|                 source/scwx/qt/manager/settings_manager.hpp) | ||||
| set(SRC_MANAGER source/scwx/qt/manager/radar_product_manager.cpp | ||||
|                 source/scwx/qt/manager/radar_product_manager_notifier.cpp | ||||
|                 source/scwx/qt/manager/resource_manager.cpp | ||||
|                 source/scwx/qt/manager/settings_manager.cpp) | ||||
| set(HDR_MAP source/scwx/qt/map/color_table_layer.hpp | ||||
|  | @ -73,6 +75,12 @@ set(SRC_MAP source/scwx/qt/map/color_table_layer.cpp | |||
|             source/scwx/qt/map/overlay_layer.cpp | ||||
|             source/scwx/qt/map/radar_product_layer.cpp | ||||
|             source/scwx/qt/map/radar_range_layer.cpp) | ||||
| set(HDR_MODEL source/scwx/qt/model/radar_product_model.hpp | ||||
|               source/scwx/qt/model/tree_item.hpp | ||||
|               source/scwx/qt/model/tree_model.hpp) | ||||
| set(SRC_MODEL source/scwx/qt/model/radar_product_model.cpp | ||||
|               source/scwx/qt/model/tree_item.cpp | ||||
|               source/scwx/qt/model/tree_model.cpp) | ||||
| set(HDR_REQUEST source/scwx/qt/request/nexrad_file_request.hpp) | ||||
| set(SRC_REQUEST source/scwx/qt/request/nexrad_file_request.cpp) | ||||
| set(HDR_SETTINGS source/scwx/qt/settings/general_settings.hpp | ||||
|  | @ -140,6 +148,8 @@ set(PROJECT_SOURCES ${HDR_MAIN} | |||
|                     ${UI_MAIN} | ||||
|                     ${HDR_MAP} | ||||
|                     ${SRC_MAP} | ||||
|                     ${HDR_MODEL} | ||||
|                     ${SRC_MODEL} | ||||
|                     ${HDR_REQUEST} | ||||
|                     ${SRC_REQUEST} | ||||
|                     ${HDR_SETTINGS} | ||||
|  | @ -172,6 +182,8 @@ source_group("Source Files\\manager"  FILES ${SRC_MANAGER}) | |||
| source_group("UI Files\\main"         FILES ${UI_MAIN}) | ||||
| source_group("Header Files\\map"      FILES ${HDR_MAP}) | ||||
| source_group("Source Files\\map"      FILES ${SRC_MAP}) | ||||
| source_group("Header Files\\model"    FILES ${HDR_MODEL}) | ||||
| source_group("Source Files\\model"    FILES ${SRC_MODEL}) | ||||
| source_group("Header Files\\request"  FILES ${HDR_REQUEST}) | ||||
| source_group("Source Files\\request"  FILES ${SRC_REQUEST}) | ||||
| source_group("Header Files\\settings" FILES ${HDR_SETTINGS}) | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include <scwx/qt/manager/radar_product_manager.hpp> | ||||
| #include <scwx/qt/manager/settings_manager.hpp> | ||||
| #include <scwx/qt/map/map_widget.hpp> | ||||
| #include <scwx/qt/model/radar_product_model.hpp> | ||||
| #include <scwx/qt/ui/flow_layout.hpp> | ||||
| #include <scwx/qt/ui/level2_products_widget.hpp> | ||||
| #include <scwx/qt/ui/level2_settings_widget.hpp> | ||||
|  | @ -123,6 +124,24 @@ MainWindow::MainWindow(QWidget* parent) : | |||
|    ui->vcpValueLabel->setVisible(false); | ||||
|    ui->vcpDescriptionLabel->setVisible(false); | ||||
| 
 | ||||
|    // Configure Menu
 | ||||
|    ui->menuView->insertAction(ui->actionRadarToolbox, | ||||
|                               ui->radarToolboxDock->toggleViewAction()); | ||||
|    ui->radarToolboxDock->toggleViewAction()->setText(tr("Radar &Toolbox")); | ||||
|    ui->actionRadarToolbox->setVisible(false); | ||||
| 
 | ||||
|    ui->menuView->insertAction(ui->actionResourceExplorer, | ||||
|                               ui->resourceExplorerDock->toggleViewAction()); | ||||
|    ui->resourceExplorerDock->toggleViewAction()->setText( | ||||
|       tr("&Resource Explorer")); | ||||
|    ui->actionResourceExplorer->setVisible(false); | ||||
| 
 | ||||
|    // Configure Docks
 | ||||
|    ui->resourceExplorerDock->setVisible(false); | ||||
| 
 | ||||
|    ui->resourceTreeView->setModel(new model::RadarProductModel(this)); | ||||
| 
 | ||||
|    // Configure Map
 | ||||
|    p->ConfigureMapLayout(); | ||||
| 
 | ||||
|    // Add Level 2 Products
 | ||||
|  |  | |||
|  | @ -52,13 +52,21 @@ | |||
|     </property> | ||||
|     <addaction name="actionAboutSupercellWx"/> | ||||
|    </widget> | ||||
|    <widget class="QMenu" name="menuView"> | ||||
|     <property name="title"> | ||||
|      <string>&View</string> | ||||
|     </property> | ||||
|     <addaction name="actionRadarToolbox"/> | ||||
|     <addaction name="actionResourceExplorer"/> | ||||
|    </widget> | ||||
|    <addaction name="menuFile"/> | ||||
|    <addaction name="menuView"/> | ||||
|    <addaction name="menuHelp"/> | ||||
|   </widget> | ||||
|   <widget class="QStatusBar" name="statusbar"/> | ||||
|   <widget class="QDockWidget" name="radarToolboxDock"> | ||||
|    <property name="windowTitle"> | ||||
|     <string>Toolbox</string> | ||||
|     <string>Radar Toolbox</string> | ||||
|    </property> | ||||
|    <attribute name="dockWidgetArea"> | ||||
|     <number>1</number> | ||||
|  | @ -217,6 +225,21 @@ | |||
|     </layout> | ||||
|    </widget> | ||||
|   </widget> | ||||
|   <widget class="QDockWidget" name="resourceExplorerDock"> | ||||
|    <property name="windowTitle"> | ||||
|     <string>Resource Explorer</string> | ||||
|    </property> | ||||
|    <attribute name="dockWidgetArea"> | ||||
|     <number>2</number> | ||||
|    </attribute> | ||||
|    <widget class="QWidget" name="dockWidgetContents"> | ||||
|     <layout class="QVBoxLayout" name="verticalLayout_3"> | ||||
|      <item> | ||||
|       <widget class="QTreeView" name="resourceTreeView"/> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </widget> | ||||
|   </widget> | ||||
|   <action name="actionExit"> | ||||
|    <property name="text"> | ||||
|     <string>E&xit</string> | ||||
|  | @ -235,6 +258,16 @@ | |||
|     <string>Ctrl+O</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="actionRadarToolbox"> | ||||
|    <property name="text"> | ||||
|     <string>Radar Toolbox</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="actionResourceExplorer"> | ||||
|    <property name="text"> | ||||
|     <string>&Resource Explorer</string> | ||||
|    </property> | ||||
|   </action> | ||||
|  </widget> | ||||
|  <resources/> | ||||
|  <connections/> | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #include <scwx/qt/manager/radar_product_manager.hpp> | ||||
| #include <scwx/qt/manager/radar_product_manager_notifier.hpp> | ||||
| #include <scwx/common/constants.hpp> | ||||
| #include <scwx/provider/nexrad_data_provider_factory.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
|  | @ -937,15 +938,29 @@ void RadarProductManager::UpdateAvailableProducts() | |||
| std::shared_ptr<RadarProductManager> | ||||
| RadarProductManager::Instance(const std::string& radarSite) | ||||
| { | ||||
|    std::lock_guard<std::mutex> guard(instanceMutex_); | ||||
|    std::shared_ptr<RadarProductManager> instance        = nullptr; | ||||
|    bool                                 instanceCreated = false; | ||||
| 
 | ||||
|    if (!instanceMap_.contains(radarSite)) | ||||
|    { | ||||
|       instanceMap_[radarSite] = | ||||
|          std::make_shared<RadarProductManager>(radarSite); | ||||
|       std::lock_guard<std::mutex> guard(instanceMutex_); | ||||
| 
 | ||||
|       if (!instanceMap_.contains(radarSite)) | ||||
|       { | ||||
|          instanceMap_[radarSite] = | ||||
|             std::make_shared<RadarProductManager>(radarSite); | ||||
|          instanceCreated = true; | ||||
|       } | ||||
| 
 | ||||
|       instance = instanceMap_[radarSite]; | ||||
|    } | ||||
| 
 | ||||
|    return instanceMap_[radarSite]; | ||||
|    if (instanceCreated) | ||||
|    { | ||||
|       emit RadarProductManagerNotifier::Instance().RadarProductManagerCreated( | ||||
|          radarSite); | ||||
|    } | ||||
| 
 | ||||
|    return instance; | ||||
| } | ||||
| 
 | ||||
| } // namespace manager
 | ||||
|  |  | |||
|  | @ -0,0 +1,34 @@ | |||
| #include <scwx/qt/manager/radar_product_manager_notifier.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace manager | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = | ||||
|    "scwx::qt::manager::radar_product_manager_notifier"; | ||||
| 
 | ||||
| class RadarProductManagerNotifierImpl | ||||
| { | ||||
| public: | ||||
|    explicit RadarProductManagerNotifierImpl() {} | ||||
|    ~RadarProductManagerNotifierImpl() {} | ||||
| }; | ||||
| 
 | ||||
| RadarProductManagerNotifier::RadarProductManagerNotifier() : | ||||
|     p(std::make_unique<RadarProductManagerNotifierImpl>()) | ||||
| { | ||||
| } | ||||
| RadarProductManagerNotifier::~RadarProductManagerNotifier() = default; | ||||
| 
 | ||||
| RadarProductManagerNotifier& RadarProductManagerNotifier::Instance() | ||||
| { | ||||
|    static RadarProductManagerNotifier instance_ {}; | ||||
|    return instance_; | ||||
| } | ||||
| 
 | ||||
| } // namespace manager
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -0,0 +1,35 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <QObject> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace manager | ||||
| { | ||||
| 
 | ||||
| class RadarProductManagerNotifierImpl; | ||||
| 
 | ||||
| class RadarProductManagerNotifier : public QObject | ||||
| { | ||||
|    Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|    explicit RadarProductManagerNotifier(); | ||||
|    ~RadarProductManagerNotifier(); | ||||
| 
 | ||||
|    static RadarProductManagerNotifier& Instance(); | ||||
| 
 | ||||
| signals: | ||||
|    void RadarProductManagerCreated(const std::string& radarSite); | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<RadarProductManagerNotifierImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace manager
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										146
									
								
								scwx-qt/source/scwx/qt/model/radar_product_model.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								scwx-qt/source/scwx/qt/model/radar_product_model.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,146 @@ | |||
| #include <scwx/qt/model/radar_product_model.hpp> | ||||
| #include <scwx/qt/manager/radar_product_manager.hpp> | ||||
| #include <scwx/qt/manager/radar_product_manager_notifier.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| #include <scwx/util/time.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace model | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::model::radar_product_model"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| class RadarProductModelImpl : public QObject | ||||
| { | ||||
|    Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|    explicit RadarProductModelImpl(RadarProductModel* self); | ||||
|    ~RadarProductModelImpl() = default; | ||||
| 
 | ||||
|    RadarProductModel*        self_; | ||||
|    std::shared_ptr<TreeItem> rootItem_; | ||||
| }; | ||||
| 
 | ||||
| RadarProductModel::RadarProductModel(QObject* parent) : | ||||
|     TreeModel(parent), p(std::make_unique<RadarProductModelImpl>(this)) | ||||
| { | ||||
| } | ||||
| RadarProductModel::~RadarProductModel() = default; | ||||
| 
 | ||||
| const std::shared_ptr<TreeItem> RadarProductModel::root_item() const | ||||
| { | ||||
|    return p->rootItem_; | ||||
| } | ||||
| 
 | ||||
| RadarProductModelImpl::RadarProductModelImpl(RadarProductModel* self) : | ||||
|     self_ {self}, | ||||
|     rootItem_ {std::make_shared<TreeItem>( | ||||
|        std::vector<QVariant> {QObject::tr("Product")})} | ||||
| { | ||||
|    connect( | ||||
|       &manager::RadarProductManagerNotifier::Instance(), | ||||
|       &manager::RadarProductManagerNotifier::RadarProductManagerCreated, | ||||
|       this, | ||||
|       [=](const std::string& radarSite) | ||||
|       { | ||||
|          logger_->debug("Adding radar site: {}", radarSite); | ||||
| 
 | ||||
|          const QModelIndex rootIndex = | ||||
|             self_->createIndex(rootItem_->row(), 0, rootItem_.get()); | ||||
|          const int rootChildren = rootItem_->child_count(); | ||||
| 
 | ||||
|          self_->beginInsertRows(rootIndex, rootChildren, rootChildren); | ||||
| 
 | ||||
|          TreeItem* radarSiteItem = | ||||
|             new TreeItem({QString::fromStdString(radarSite)}); | ||||
|          rootItem_->AppendChild(radarSiteItem); | ||||
| 
 | ||||
|          self_->endInsertRows(); | ||||
| 
 | ||||
|          connect( | ||||
|             manager::RadarProductManager::Instance(radarSite).get(), | ||||
|             &manager::RadarProductManager::NewDataAvailable, | ||||
|             this, | ||||
|             [=](common::RadarProductGroup             group, | ||||
|                 const std::string&                    product, | ||||
|                 std::chrono::system_clock::time_point latestTime) | ||||
|             { | ||||
|                const QString groupName {QString::fromStdString( | ||||
|                   common::GetRadarProductGroupName(group))}; | ||||
| 
 | ||||
|                // Find existing group item (e.g., Level 2, Level 3)
 | ||||
|                TreeItem* groupItem = radarSiteItem->FindChild(0, groupName); | ||||
| 
 | ||||
|                if (groupItem == nullptr) | ||||
|                { | ||||
|                   // Existing group item was not found, create it
 | ||||
|                   const QModelIndex radarSiteIndex = | ||||
|                      self_->createIndex(radarSiteItem->row(), 0, radarSiteItem); | ||||
|                   const int radarSiteChildren = radarSiteItem->child_count(); | ||||
| 
 | ||||
|                   self_->beginInsertRows( | ||||
|                      radarSiteIndex, radarSiteChildren, radarSiteChildren); | ||||
| 
 | ||||
|                   groupItem = new TreeItem({groupName}); | ||||
|                   radarSiteItem->AppendChild(groupItem); | ||||
| 
 | ||||
|                   self_->endInsertRows(); | ||||
|                } | ||||
| 
 | ||||
|                TreeItem* productItem = nullptr; | ||||
| 
 | ||||
|                if (group == common::RadarProductGroup::Level2) | ||||
|                { | ||||
|                   // Level 2 items are not separated by product
 | ||||
|                   productItem = groupItem; | ||||
|                } | ||||
|                else | ||||
|                { | ||||
|                   // Find existing product item (e.g., N0B, N0Q)
 | ||||
|                   const QString productName {QString::fromStdString(product)}; | ||||
|                   productItem = groupItem->FindChild(0, productName); | ||||
| 
 | ||||
|                   if (productItem == nullptr) | ||||
|                   { | ||||
|                      // Existing product item was not found, create it
 | ||||
|                      const QModelIndex groupItemIndex = | ||||
|                         self_->createIndex(groupItem->row(), 0, groupItem); | ||||
|                      const int groupItemChildren = groupItem->child_count(); | ||||
| 
 | ||||
|                      self_->beginInsertRows( | ||||
|                         groupItemIndex, groupItemChildren, groupItemChildren); | ||||
| 
 | ||||
|                      productItem = new TreeItem({productName}); | ||||
|                      groupItem->AppendChild(productItem); | ||||
| 
 | ||||
|                      self_->endInsertRows(); | ||||
|                   } | ||||
|                } | ||||
| 
 | ||||
|                // Create leaf item for product time
 | ||||
|                const QModelIndex productItemIndex = | ||||
|                   self_->createIndex(productItem->row(), 0, productItem); | ||||
|                const int productItemChildren = productItem->child_count(); | ||||
| 
 | ||||
|                self_->beginInsertRows( | ||||
|                   productItemIndex, productItemChildren, productItemChildren); | ||||
| 
 | ||||
|                productItem->AppendChild(new TreeItem { | ||||
|                   QString::fromStdString(util::TimeString(latestTime))}); | ||||
| 
 | ||||
|                self_->endInsertRows(); | ||||
|             }, | ||||
|             Qt::QueuedConnection); | ||||
|       }); | ||||
| } | ||||
| 
 | ||||
| #include "radar_product_model.moc" | ||||
| 
 | ||||
| } // namespace model
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										31
									
								
								scwx-qt/source/scwx/qt/model/radar_product_model.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								scwx-qt/source/scwx/qt/model/radar_product_model.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/model/tree_model.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace model | ||||
| { | ||||
| 
 | ||||
| class RadarProductModelImpl; | ||||
| 
 | ||||
| class RadarProductModel : public TreeModel | ||||
| { | ||||
| public: | ||||
|    explicit RadarProductModel(QObject* parent = nullptr); | ||||
|    ~RadarProductModel(); | ||||
| 
 | ||||
| protected: | ||||
|    const std::shared_ptr<TreeItem> root_item() const override; | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<RadarProductModelImpl> p; | ||||
| 
 | ||||
|    friend class RadarProductModelImpl; | ||||
| }; | ||||
| 
 | ||||
| } // namespace model
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										138
									
								
								scwx-qt/source/scwx/qt/model/tree_item.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								scwx-qt/source/scwx/qt/model/tree_item.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,138 @@ | |||
| #include <scwx/qt/model/tree_item.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace model | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::model::tree_item"; | ||||
| 
 | ||||
| class TreeItem::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl(const std::vector<QVariant>& data, TreeItem* parent) : | ||||
|        childItems_ {}, itemData_ {data}, parentItem_ {parent} | ||||
|    { | ||||
|    } | ||||
|    ~Impl() { qDeleteAll(childItems_); } | ||||
| 
 | ||||
|    std::vector<TreeItem*> childItems_; | ||||
|    std::vector<QVariant>  itemData_; | ||||
|    TreeItem*              parentItem_; | ||||
| }; | ||||
| 
 | ||||
| TreeItem::TreeItem(const std::vector<QVariant>& data, TreeItem* parent) : | ||||
|     p {std::make_unique<Impl>(data, parent)} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| TreeItem::TreeItem(std::initializer_list<QVariant> data, TreeItem* parent) : | ||||
|     TreeItem(std::vector<QVariant> {data}, parent) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|    if (0 <= row && row < p->childItems_.size()) | ||||
|    { | ||||
|       item = p->childItems_[row]; | ||||
|    } | ||||
| 
 | ||||
|    return item; | ||||
| } | ||||
| 
 | ||||
| TreeItem* TreeItem::child(int row) | ||||
| { | ||||
|    TreeItem* item = nullptr; | ||||
| 
 | ||||
|    if (0 <= row && row < p->childItems_.size()) | ||||
|    { | ||||
|       item = p->childItems_[row]; | ||||
|    } | ||||
| 
 | ||||
|    return item; | ||||
| } | ||||
| 
 | ||||
| std::vector<TreeItem*> TreeItem::children() | ||||
| { | ||||
|    return p->childItems_; | ||||
| } | ||||
| 
 | ||||
| int TreeItem::child_count() const | ||||
| { | ||||
|    return static_cast<int>(p->childItems_.size()); | ||||
| } | ||||
| 
 | ||||
| int TreeItem::column_count() const | ||||
| { | ||||
|    return static_cast<int>(p->itemData_.size()); | ||||
| } | ||||
| 
 | ||||
| QVariant TreeItem::data(int column) const | ||||
| { | ||||
|    if (0 <= column && column < p->itemData_.size()) | ||||
|    { | ||||
|       return p->itemData_[column]; | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       return QVariant(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| int TreeItem::row() const | ||||
| { | ||||
|    int row = 0; | ||||
| 
 | ||||
|    if (p->parentItem_ != nullptr) | ||||
|    { | ||||
|       const auto& childItems = p->parentItem_->p->childItems_; | ||||
|       row = | ||||
|          std::distance(childItems.cbegin(), | ||||
|                        std::find(childItems.cbegin(), childItems.cend(), this)); | ||||
|    } | ||||
| 
 | ||||
|    return row; | ||||
| } | ||||
| 
 | ||||
| const TreeItem* TreeItem::parent_item() const | ||||
| { | ||||
|    return p->parentItem_; | ||||
| } | ||||
| 
 | ||||
| } // namespace model
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										49
									
								
								scwx-qt/source/scwx/qt/model/tree_item.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								scwx-qt/source/scwx/qt/model/tree_item.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include <QVariant> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace model | ||||
| { | ||||
| 
 | ||||
| class TreeItem | ||||
| { | ||||
| public: | ||||
|    explicit TreeItem(const std::vector<QVariant>& data, | ||||
|                      TreeItem*                    parent = nullptr); | ||||
|    explicit TreeItem(std::initializer_list<QVariant> data, | ||||
|                      TreeItem*                       parent = nullptr); | ||||
|    virtual ~TreeItem(); | ||||
| 
 | ||||
|    TreeItem(const TreeItem&)            = delete; | ||||
|    TreeItem& operator=(const TreeItem&) = delete; | ||||
| 
 | ||||
|    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<TreeItem*> children(); | ||||
|    int                    child_count() const; | ||||
|    int                    column_count() const; | ||||
|    QVariant               data(int column) const; | ||||
|    int                    row() const; | ||||
|    const TreeItem*        parent_item() const; | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace model
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										145
									
								
								scwx-qt/source/scwx/qt/model/tree_model.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								scwx-qt/source/scwx/qt/model/tree_model.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,145 @@ | |||
| #include <scwx/qt/model/tree_model.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace model | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::model::tree_model"; | ||||
| 
 | ||||
| class TreeModelImpl | ||||
| { | ||||
| public: | ||||
|    explicit TreeModelImpl() = default; | ||||
|    ~TreeModelImpl()         = default; | ||||
| }; | ||||
| 
 | ||||
| TreeModel::TreeModel(QObject* parent) : | ||||
|     QAbstractItemModel(parent), p(std::make_unique<TreeModelImpl>()) | ||||
| { | ||||
| } | ||||
| TreeModel::~TreeModel() = default; | ||||
| 
 | ||||
| int TreeModel::rowCount(const QModelIndex& parent) const | ||||
| { | ||||
|    const TreeItem* parentItem; | ||||
| 
 | ||||
|    if (parent.isValid()) | ||||
|    { | ||||
|       parentItem = static_cast<const TreeItem*>(parent.constInternalPointer()); | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       parentItem = root_item().get(); | ||||
|    } | ||||
| 
 | ||||
|    return parentItem->child_count(); | ||||
| } | ||||
| 
 | ||||
| int TreeModel::columnCount(const QModelIndex& parent) const | ||||
| { | ||||
|    const TreeItem* parentItem; | ||||
| 
 | ||||
|    if (parent.isValid()) | ||||
|    { | ||||
|       parentItem = static_cast<const TreeItem*>(parent.constInternalPointer()); | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       parentItem = root_item().get(); | ||||
|    } | ||||
| 
 | ||||
|    return parentItem->column_count(); | ||||
| } | ||||
| 
 | ||||
| QVariant TreeModel::data(const QModelIndex& index, int role) const | ||||
| { | ||||
|    if (!index.isValid() || role != Qt::DisplayRole) | ||||
|    { | ||||
|       return QVariant(); | ||||
|    } | ||||
| 
 | ||||
|    const TreeItem* item = static_cast<const TreeItem*>(index.internalPointer()); | ||||
| 
 | ||||
|    return item->data(index.column()); | ||||
| } | ||||
| 
 | ||||
| Qt::ItemFlags TreeModel::flags(const QModelIndex& index) const | ||||
| { | ||||
|    Qt::ItemFlags flags; | ||||
| 
 | ||||
|    if (!index.isValid()) | ||||
|    { | ||||
|       flags = Qt::NoItemFlags; | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       flags = QAbstractItemModel::flags(index); | ||||
|    } | ||||
| 
 | ||||
|    return flags; | ||||
| } | ||||
| 
 | ||||
| QVariant | ||||
| TreeModel::headerData(int section, Qt::Orientation orientation, int role) const | ||||
| { | ||||
|    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) | ||||
|    { | ||||
|       return root_item()->data(section); | ||||
|    } | ||||
| 
 | ||||
|    return QVariant(); | ||||
| } | ||||
| 
 | ||||
| QModelIndex | ||||
| TreeModel::index(int row, int column, const QModelIndex& parent) const | ||||
| { | ||||
|    if (!hasIndex(row, column, parent)) | ||||
|    { | ||||
|       return QModelIndex(); | ||||
|    } | ||||
| 
 | ||||
|    const TreeItem* parentItem; | ||||
| 
 | ||||
|    if (!parent.isValid()) | ||||
|    { | ||||
|       parentItem = root_item().get(); | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       parentItem = static_cast<const TreeItem*>(parent.constInternalPointer()); | ||||
|    } | ||||
| 
 | ||||
|    const TreeItem* childItem = parentItem->child(row); | ||||
|    if (childItem) | ||||
|    { | ||||
|       return createIndex(row, column, childItem); | ||||
|    } | ||||
| 
 | ||||
|    return QModelIndex(); | ||||
| } | ||||
| 
 | ||||
| QModelIndex TreeModel::parent(const QModelIndex& index) const | ||||
| { | ||||
|    if (!index.isValid()) | ||||
|    { | ||||
|       return QModelIndex(); | ||||
|    } | ||||
| 
 | ||||
|    const TreeItem* childItem = | ||||
|       static_cast<const TreeItem*>(index.constInternalPointer()); | ||||
|    const TreeItem* parentItem = childItem->parent_item(); | ||||
| 
 | ||||
|    if (parentItem == root_item().get() || parentItem == nullptr) | ||||
|    { | ||||
|       return QModelIndex(); | ||||
|    } | ||||
| 
 | ||||
|    return createIndex(parentItem->row(), 0, parentItem); | ||||
| } | ||||
| 
 | ||||
| } // namespace model
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										45
									
								
								scwx-qt/source/scwx/qt/model/tree_model.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								scwx-qt/source/scwx/qt/model/tree_model.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/model/tree_item.hpp> | ||||
| 
 | ||||
| #include <QAbstractItemModel> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace model | ||||
| { | ||||
| 
 | ||||
| class TreeModelImpl; | ||||
| 
 | ||||
| class TreeModel : public QAbstractItemModel | ||||
| { | ||||
| public: | ||||
|    explicit TreeModel(QObject* parent = nullptr); | ||||
|    virtual ~TreeModel(); | ||||
| 
 | ||||
|    int rowCount(const QModelIndex& parent = QModelIndex()) const override; | ||||
|    int columnCount(const QModelIndex& parent = QModelIndex()) const override; | ||||
| 
 | ||||
|    QVariant      data(const QModelIndex& index, | ||||
|                       int                role = Qt::DisplayRole) const override; | ||||
|    Qt::ItemFlags flags(const QModelIndex& index) const override; | ||||
|    QVariant      headerData(int             section, | ||||
|                             Qt::Orientation orientation, | ||||
|                             int             role = Qt::DisplayRole) const override; | ||||
|    QModelIndex   index(int                row, | ||||
|                        int                column, | ||||
|                        const QModelIndex& parent = QModelIndex()) const override; | ||||
|    QModelIndex   parent(const QModelIndex& index) const override; | ||||
| 
 | ||||
| protected: | ||||
|    virtual const std::shared_ptr<TreeItem> root_item() const = 0; | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<TreeModelImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace model
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat