mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 16:20:05 +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 | set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp | ||||||
|                 source/scwx/qt/gl/draw/rectangle.cpp) |                 source/scwx/qt/gl/draw/rectangle.cpp) | ||||||
| set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp | 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/resource_manager.hpp | ||||||
|                 source/scwx/qt/manager/settings_manager.hpp) |                 source/scwx/qt/manager/settings_manager.hpp) | ||||||
| set(SRC_MANAGER source/scwx/qt/manager/radar_product_manager.cpp | 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/resource_manager.cpp | ||||||
|                 source/scwx/qt/manager/settings_manager.cpp) |                 source/scwx/qt/manager/settings_manager.cpp) | ||||||
| set(HDR_MAP source/scwx/qt/map/color_table_layer.hpp | 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/overlay_layer.cpp | ||||||
|             source/scwx/qt/map/radar_product_layer.cpp |             source/scwx/qt/map/radar_product_layer.cpp | ||||||
|             source/scwx/qt/map/radar_range_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(HDR_REQUEST source/scwx/qt/request/nexrad_file_request.hpp) | ||||||
| set(SRC_REQUEST source/scwx/qt/request/nexrad_file_request.cpp) | set(SRC_REQUEST source/scwx/qt/request/nexrad_file_request.cpp) | ||||||
| set(HDR_SETTINGS source/scwx/qt/settings/general_settings.hpp | set(HDR_SETTINGS source/scwx/qt/settings/general_settings.hpp | ||||||
|  | @ -140,6 +148,8 @@ set(PROJECT_SOURCES ${HDR_MAIN} | ||||||
|                     ${UI_MAIN} |                     ${UI_MAIN} | ||||||
|                     ${HDR_MAP} |                     ${HDR_MAP} | ||||||
|                     ${SRC_MAP} |                     ${SRC_MAP} | ||||||
|  |                     ${HDR_MODEL} | ||||||
|  |                     ${SRC_MODEL} | ||||||
|                     ${HDR_REQUEST} |                     ${HDR_REQUEST} | ||||||
|                     ${SRC_REQUEST} |                     ${SRC_REQUEST} | ||||||
|                     ${HDR_SETTINGS} |                     ${HDR_SETTINGS} | ||||||
|  | @ -172,6 +182,8 @@ source_group("Source Files\\manager"  FILES ${SRC_MANAGER}) | ||||||
| source_group("UI Files\\main"         FILES ${UI_MAIN}) | source_group("UI Files\\main"         FILES ${UI_MAIN}) | ||||||
| source_group("Header Files\\map"      FILES ${HDR_MAP}) | source_group("Header Files\\map"      FILES ${HDR_MAP}) | ||||||
| source_group("Source Files\\map"      FILES ${SRC_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("Header Files\\request"  FILES ${HDR_REQUEST}) | ||||||
| source_group("Source Files\\request"  FILES ${SRC_REQUEST}) | source_group("Source Files\\request"  FILES ${SRC_REQUEST}) | ||||||
| source_group("Header Files\\settings" FILES ${HDR_SETTINGS}) | source_group("Header Files\\settings" FILES ${HDR_SETTINGS}) | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| #include <scwx/qt/manager/radar_product_manager.hpp> | #include <scwx/qt/manager/radar_product_manager.hpp> | ||||||
| #include <scwx/qt/manager/settings_manager.hpp> | #include <scwx/qt/manager/settings_manager.hpp> | ||||||
| #include <scwx/qt/map/map_widget.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/flow_layout.hpp> | ||||||
| #include <scwx/qt/ui/level2_products_widget.hpp> | #include <scwx/qt/ui/level2_products_widget.hpp> | ||||||
| #include <scwx/qt/ui/level2_settings_widget.hpp> | #include <scwx/qt/ui/level2_settings_widget.hpp> | ||||||
|  | @ -123,6 +124,24 @@ MainWindow::MainWindow(QWidget* parent) : | ||||||
|    ui->vcpValueLabel->setVisible(false); |    ui->vcpValueLabel->setVisible(false); | ||||||
|    ui->vcpDescriptionLabel->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(); |    p->ConfigureMapLayout(); | ||||||
| 
 | 
 | ||||||
|    // Add Level 2 Products
 |    // Add Level 2 Products
 | ||||||
|  |  | ||||||
|  | @ -52,13 +52,21 @@ | ||||||
|     </property> |     </property> | ||||||
|     <addaction name="actionAboutSupercellWx"/> |     <addaction name="actionAboutSupercellWx"/> | ||||||
|    </widget> |    </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="menuFile"/> | ||||||
|  |    <addaction name="menuView"/> | ||||||
|    <addaction name="menuHelp"/> |    <addaction name="menuHelp"/> | ||||||
|   </widget> |   </widget> | ||||||
|   <widget class="QStatusBar" name="statusbar"/> |   <widget class="QStatusBar" name="statusbar"/> | ||||||
|   <widget class="QDockWidget" name="radarToolboxDock"> |   <widget class="QDockWidget" name="radarToolboxDock"> | ||||||
|    <property name="windowTitle"> |    <property name="windowTitle"> | ||||||
|     <string>Toolbox</string> |     <string>Radar Toolbox</string> | ||||||
|    </property> |    </property> | ||||||
|    <attribute name="dockWidgetArea"> |    <attribute name="dockWidgetArea"> | ||||||
|     <number>1</number> |     <number>1</number> | ||||||
|  | @ -217,6 +225,21 @@ | ||||||
|     </layout> |     </layout> | ||||||
|    </widget> |    </widget> | ||||||
|   </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"> |   <action name="actionExit"> | ||||||
|    <property name="text"> |    <property name="text"> | ||||||
|     <string>E&xit</string> |     <string>E&xit</string> | ||||||
|  | @ -235,6 +258,16 @@ | ||||||
|     <string>Ctrl+O</string> |     <string>Ctrl+O</string> | ||||||
|    </property> |    </property> | ||||||
|   </action> |   </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> |  </widget> | ||||||
|  <resources/> |  <resources/> | ||||||
|  <connections/> |  <connections/> | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| #include <scwx/qt/manager/radar_product_manager.hpp> | #include <scwx/qt/manager/radar_product_manager.hpp> | ||||||
|  | #include <scwx/qt/manager/radar_product_manager_notifier.hpp> | ||||||
| #include <scwx/common/constants.hpp> | #include <scwx/common/constants.hpp> | ||||||
| #include <scwx/provider/nexrad_data_provider_factory.hpp> | #include <scwx/provider/nexrad_data_provider_factory.hpp> | ||||||
| #include <scwx/util/logger.hpp> | #include <scwx/util/logger.hpp> | ||||||
|  | @ -936,6 +937,10 @@ void RadarProductManager::UpdateAvailableProducts() | ||||||
| 
 | 
 | ||||||
| std::shared_ptr<RadarProductManager> | std::shared_ptr<RadarProductManager> | ||||||
| RadarProductManager::Instance(const std::string& radarSite) | RadarProductManager::Instance(const std::string& radarSite) | ||||||
|  | { | ||||||
|  |    std::shared_ptr<RadarProductManager> instance        = nullptr; | ||||||
|  |    bool                                 instanceCreated = false; | ||||||
|  | 
 | ||||||
|    { |    { | ||||||
|       std::lock_guard<std::mutex> guard(instanceMutex_); |       std::lock_guard<std::mutex> guard(instanceMutex_); | ||||||
| 
 | 
 | ||||||
|  | @ -943,9 +948,19 @@ RadarProductManager::Instance(const std::string& radarSite) | ||||||
|       { |       { | ||||||
|          instanceMap_[radarSite] = |          instanceMap_[radarSite] = | ||||||
|             std::make_shared<RadarProductManager>(radarSite); |             std::make_shared<RadarProductManager>(radarSite); | ||||||
|  |          instanceCreated = true; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|    return instanceMap_[radarSite]; |       instance = instanceMap_[radarSite]; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    if (instanceCreated) | ||||||
|  |    { | ||||||
|  |       emit RadarProductManagerNotifier::Instance().RadarProductManagerCreated( | ||||||
|  |          radarSite); | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace manager
 | } // 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