mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 16:30:05 +00:00 
			
		
		
		
	Merge pull request #62 from dpaulat/feature/timeline-part-3
Complete Timeline Animation
This commit is contained in:
		
						commit
						effe78e1be
					
				
					 10 changed files with 730 additions and 525 deletions
				
			
		|  | @ -211,6 +211,7 @@ MainWindow::MainWindow(QWidget* parent) : | ||||||
|    ui->resourceExplorerDock->toggleViewAction()->setText( |    ui->resourceExplorerDock->toggleViewAction()->setText( | ||||||
|       tr("&Resource Explorer")); |       tr("&Resource Explorer")); | ||||||
|    ui->actionResourceExplorer->setVisible(false); |    ui->actionResourceExplorer->setVisible(false); | ||||||
|  |    ui->resourceExplorerDock->toggleViewAction()->setVisible(false); | ||||||
| 
 | 
 | ||||||
|    ui->menuView->insertAction(ui->actionAlerts, |    ui->menuView->insertAction(ui->actionAlerts, | ||||||
|                               p->alertDockWidget_->toggleViewAction()); |                               p->alertDockWidget_->toggleViewAction()); | ||||||
|  | @ -711,7 +712,10 @@ void MainWindowImpl::ConnectAnimationSignals() | ||||||
|            &manager::TimelineManager::AnimationStateUpdated, |            &manager::TimelineManager::AnimationStateUpdated, | ||||||
|            animationDockWidget_, |            animationDockWidget_, | ||||||
|            &ui::AnimationDockWidget::UpdateAnimationState); |            &ui::AnimationDockWidget::UpdateAnimationState); | ||||||
| 
 |    connect(timelineManager_.get(), | ||||||
|  |            &manager::TimelineManager::ViewTypeUpdated, | ||||||
|  |            animationDockWidget_, | ||||||
|  |            &ui::AnimationDockWidget::UpdateViewType); | ||||||
|    connect(timelineManager_.get(), |    connect(timelineManager_.get(), | ||||||
|            &manager::TimelineManager::LiveStateUpdated, |            &manager::TimelineManager::LiveStateUpdated, | ||||||
|            animationDockWidget_, |            animationDockWidget_, | ||||||
|  | @ -790,6 +794,8 @@ void MainWindowImpl::ConnectOtherSignals() | ||||||
|          { |          { | ||||||
|             map->SetMapLocation(latitude, longitude, true); |             map->SetMapLocation(latitude, longitude, true); | ||||||
|          } |          } | ||||||
|  | 
 | ||||||
|  |          UpdateRadarSite(); | ||||||
|       }, |       }, | ||||||
|       Qt::QueuedConnection); |       Qt::QueuedConnection); | ||||||
|    connect(mainWindow_, |    connect(mainWindow_, | ||||||
|  | @ -807,6 +813,8 @@ void MainWindowImpl::ConnectOtherSignals() | ||||||
|               { |               { | ||||||
|                  map->SelectRadarSite(selectedRadarSite); |                  map->SelectRadarSite(selectedRadarSite); | ||||||
|               } |               } | ||||||
|  | 
 | ||||||
|  |               UpdateRadarSite(); | ||||||
|            }); |            }); | ||||||
|    connect(updateManager_.get(), |    connect(updateManager_.get(), | ||||||
|            &manager::UpdateManager::UpdateAvailable, |            &manager::UpdateManager::UpdateAvailable, | ||||||
|  |  | ||||||
|  | @ -116,128 +116,181 @@ | ||||||
|       <number>2</number> |       <number>2</number> | ||||||
|      </property> |      </property> | ||||||
|      <item> |      <item> | ||||||
|       <widget class="QFrame" name="radarInfoFrame"> |       <widget class="QScrollArea" name="radarToolboxScrollArea"> | ||||||
|        <property name="frameShape"> |        <property name="frameShape"> | ||||||
|         <enum>QFrame::StyledPanel</enum> |         <enum>QFrame::NoFrame</enum> | ||||||
|        </property> |        </property> | ||||||
|        <property name="frameShadow"> |        <property name="horizontalScrollBarPolicy"> | ||||||
|         <enum>QFrame::Raised</enum> |         <enum>Qt::ScrollBarAlwaysOff</enum> | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0"> |        <property name="sizeAdjustPolicy"> | ||||||
|         <item row="0" column="2"> |         <enum>QAbstractScrollArea::AdjustToContents</enum> | ||||||
|          <widget class="QToolButton" name="radarSiteSelectButton"> |  | ||||||
|           <property name="maximumSize"> |  | ||||||
|            <size> |  | ||||||
|             <width>16777215</width> |  | ||||||
|             <height>13</height> |  | ||||||
|            </size> |  | ||||||
|           </property> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>...</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="1" column="1" colspan="2"> |  | ||||||
|          <widget class="QLabel" name="radarLocationLabel"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string notr="true">St. Louis, MO</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="2" column="0"> |  | ||||||
|          <widget class="QLabel" name="vcpLabel"> |  | ||||||
|           <property name="toolTip"> |  | ||||||
|            <string>Volume Coverage Pattern</string> |  | ||||||
|           </property> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>VCP</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="0" column="1"> |  | ||||||
|          <widget class="QLabel" name="radarSiteValueLabel"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string notr="true">KLSX</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="0" column="0"> |  | ||||||
|          <widget class="QLabel" name="radarSiteLabel"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>Radar Site</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="3" column="1" colspan="2"> |  | ||||||
|          <widget class="QLabel" name="vcpDescriptionLabel"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>Clear Air Mode</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="2" column="1" colspan="2"> |  | ||||||
|          <widget class="QLabel" name="vcpValueLabel"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string notr="true">35</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|        </layout> |  | ||||||
|       </widget> |  | ||||||
|      </item> |  | ||||||
|      <item> |  | ||||||
|       <widget class="QGroupBox" name="mapSettingsGroupBox"> |  | ||||||
|        <property name="title"> |  | ||||||
|         <string>Map Settings</string> |  | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QVBoxLayout" name="verticalLayout_5"> |        <property name="widgetResizable"> | ||||||
|         <item> |         <bool>true</bool> | ||||||
|          <widget class="QLabel" name="mapStyleLabel"> |  | ||||||
|           <property name="text"> |  | ||||||
|            <string>Map Style</string> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item> |  | ||||||
|          <widget class="QComboBox" name="mapStyleComboBox"/> |  | ||||||
|         </item> |  | ||||||
|        </layout> |  | ||||||
|       </widget> |  | ||||||
|      </item> |  | ||||||
|      <item> |  | ||||||
|       <widget class="QGroupBox" name="radarProductGroupBox"> |  | ||||||
|        <property name="title"> |  | ||||||
|         <string>Radar Products</string> |  | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QVBoxLayout" name="verticalLayout"> |        <widget class="QWidget" name="radarToolboxScrollAreaContents"> | ||||||
|         <item> |         <property name="geometry"> | ||||||
|          <widget class="QLabel" name="level2Label"> |          <rect> | ||||||
|           <property name="text"> |           <x>0</x> | ||||||
|            <string>Level 2</string> |           <y>0</y> | ||||||
|           </property> |           <width>175</width> | ||||||
|          </widget> |           <height>696</height> | ||||||
|         </item> |          </rect> | ||||||
|         <item> |         </property> | ||||||
|          <widget class="QWidget" name="level2ProductFrame" native="true"/> |         <layout class="QVBoxLayout" name="verticalLayout_6"> | ||||||
|         </item> |          <property name="leftMargin"> | ||||||
|         <item> |           <number>0</number> | ||||||
|          <widget class="Line" name="level2Separator"> |          </property> | ||||||
|           <property name="orientation"> |          <property name="topMargin"> | ||||||
|            <enum>Qt::Horizontal</enum> |           <number>0</number> | ||||||
|           </property> |          </property> | ||||||
|          </widget> |          <property name="rightMargin"> | ||||||
|         </item> |           <number>0</number> | ||||||
|         <item> |          </property> | ||||||
|          <widget class="QLabel" name="level3Label"> |          <property name="bottomMargin"> | ||||||
|           <property name="text"> |           <number>0</number> | ||||||
|            <string>Level 3</string> |          </property> | ||||||
|           </property> |          <item> | ||||||
|          </widget> |           <widget class="QFrame" name="radarInfoFrame"> | ||||||
|         </item> |            <property name="frameShape"> | ||||||
|         <item> |             <enum>QFrame::StyledPanel</enum> | ||||||
|          <widget class="QWidget" name="level3ProductFrame" native="true"/> |            </property> | ||||||
|         </item> |            <property name="frameShadow"> | ||||||
|        </layout> |             <enum>QFrame::Raised</enum> | ||||||
|  |            </property> | ||||||
|  |            <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0"> | ||||||
|  |             <item row="0" column="2"> | ||||||
|  |              <widget class="QToolButton" name="radarSiteSelectButton"> | ||||||
|  |               <property name="maximumSize"> | ||||||
|  |                <size> | ||||||
|  |                 <width>16777215</width> | ||||||
|  |                 <height>13</height> | ||||||
|  |                </size> | ||||||
|  |               </property> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string>...</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item row="1" column="1" colspan="2"> | ||||||
|  |              <widget class="QLabel" name="radarLocationLabel"> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string notr="true">St. Louis, MO</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item row="2" column="0"> | ||||||
|  |              <widget class="QLabel" name="vcpLabel"> | ||||||
|  |               <property name="toolTip"> | ||||||
|  |                <string>Volume Coverage Pattern</string> | ||||||
|  |               </property> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string>VCP</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item row="0" column="1"> | ||||||
|  |              <widget class="QLabel" name="radarSiteValueLabel"> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string notr="true">KLSX</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item row="0" column="0"> | ||||||
|  |              <widget class="QLabel" name="radarSiteLabel"> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string>Radar Site</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item row="3" column="1" colspan="2"> | ||||||
|  |              <widget class="QLabel" name="vcpDescriptionLabel"> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string>Clear Air Mode</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item row="2" column="1" colspan="2"> | ||||||
|  |              <widget class="QLabel" name="vcpValueLabel"> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string notr="true">35</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |            </layout> | ||||||
|  |           </widget> | ||||||
|  |          </item> | ||||||
|  |          <item> | ||||||
|  |           <widget class="QGroupBox" name="mapSettingsGroupBox"> | ||||||
|  |            <property name="title"> | ||||||
|  |             <string>Map Settings</string> | ||||||
|  |            </property> | ||||||
|  |            <layout class="QVBoxLayout" name="verticalLayout_5"> | ||||||
|  |             <item> | ||||||
|  |              <widget class="QLabel" name="mapStyleLabel"> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string>Map Style</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item> | ||||||
|  |              <widget class="QComboBox" name="mapStyleComboBox"/> | ||||||
|  |             </item> | ||||||
|  |            </layout> | ||||||
|  |           </widget> | ||||||
|  |          </item> | ||||||
|  |          <item> | ||||||
|  |           <widget class="QGroupBox" name="radarProductGroupBox"> | ||||||
|  |            <property name="title"> | ||||||
|  |             <string>Radar Products</string> | ||||||
|  |            </property> | ||||||
|  |            <layout class="QVBoxLayout" name="verticalLayout"> | ||||||
|  |             <item> | ||||||
|  |              <widget class="QLabel" name="level2Label"> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string>Level 2</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item> | ||||||
|  |              <widget class="QWidget" name="level2ProductFrame" native="true"/> | ||||||
|  |             </item> | ||||||
|  |             <item> | ||||||
|  |              <widget class="Line" name="level2Separator"> | ||||||
|  |               <property name="orientation"> | ||||||
|  |                <enum>Qt::Horizontal</enum> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item> | ||||||
|  |              <widget class="QLabel" name="level3Label"> | ||||||
|  |               <property name="text"> | ||||||
|  |                <string>Level 3</string> | ||||||
|  |               </property> | ||||||
|  |              </widget> | ||||||
|  |             </item> | ||||||
|  |             <item> | ||||||
|  |              <widget class="QWidget" name="level3ProductFrame" native="true"/> | ||||||
|  |             </item> | ||||||
|  |            </layout> | ||||||
|  |           </widget> | ||||||
|  |          </item> | ||||||
|  |          <item> | ||||||
|  |           <spacer name="radarToolboxSpacer"> | ||||||
|  |            <property name="orientation"> | ||||||
|  |             <enum>Qt::Vertical</enum> | ||||||
|  |            </property> | ||||||
|  |            <property name="sizeHint" stdset="0"> | ||||||
|  |             <size> | ||||||
|  |              <width>20</width> | ||||||
|  |              <height>0</height> | ||||||
|  |             </size> | ||||||
|  |            </property> | ||||||
|  |           </spacer> | ||||||
|  |          </item> | ||||||
|  |         </layout> | ||||||
|  |        </widget> | ||||||
|       </widget> |       </widget> | ||||||
|      </item> |      </item> | ||||||
|      <item> |      <item> | ||||||
|  | @ -258,19 +311,6 @@ | ||||||
|        </layout> |        </layout> | ||||||
|       </widget> |       </widget> | ||||||
|      </item> |      </item> | ||||||
|      <item> |  | ||||||
|       <spacer name="radarToolboxSpacer"> |  | ||||||
|        <property name="orientation"> |  | ||||||
|         <enum>Qt::Vertical</enum> |  | ||||||
|        </property> |  | ||||||
|        <property name="sizeHint" stdset="0"> |  | ||||||
|         <size> |  | ||||||
|          <width>20</width> |  | ||||||
|          <height>0</height> |  | ||||||
|         </size> |  | ||||||
|        </property> |  | ||||||
|       </spacer> |  | ||||||
|      </item> |  | ||||||
|     </layout> |     </layout> | ||||||
|    </widget> |    </widget> | ||||||
|   </widget> |   </widget> | ||||||
|  |  | ||||||
|  | @ -19,7 +19,9 @@ | ||||||
| #   pragma warning(push, 0) | #   pragma warning(push, 0) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #include <boost/asio/post.hpp> | ||||||
| #include <boost/asio/steady_timer.hpp> | #include <boost/asio/steady_timer.hpp> | ||||||
|  | #include <boost/asio/thread_pool.hpp> | ||||||
| #include <boost/container_hash/hash.hpp> | #include <boost/container_hash/hash.hpp> | ||||||
| #include <boost/range/irange.hpp> | #include <boost/range/irange.hpp> | ||||||
| #include <boost/timer/timer.hpp> | #include <boost/timer/timer.hpp> | ||||||
|  | @ -91,7 +93,7 @@ public: | ||||||
|        group_ {group}, |        group_ {group}, | ||||||
|        product_ {product}, |        product_ {product}, | ||||||
|        refreshEnabled_ {false}, |        refreshEnabled_ {false}, | ||||||
|        refreshTimer_ {scwx::util::io_context()}, |        refreshTimer_ {threadPool_}, | ||||||
|        refreshTimerMutex_ {}, |        refreshTimerMutex_ {}, | ||||||
|        provider_ {nullptr} |        provider_ {nullptr} | ||||||
|    { |    { | ||||||
|  | @ -106,6 +108,8 @@ public: | ||||||
| 
 | 
 | ||||||
|    void Disable(); |    void Disable(); | ||||||
| 
 | 
 | ||||||
|  |    boost::asio::thread_pool threadPool_ {1u}; | ||||||
|  | 
 | ||||||
|    const std::string                             radarId_; |    const std::string                             radarId_; | ||||||
|    const common::RadarProductGroup               group_; |    const common::RadarProductGroup               group_; | ||||||
|    const std::string                             product_; |    const std::string                             product_; | ||||||
|  | @ -179,6 +183,8 @@ public: | ||||||
| 
 | 
 | ||||||
|    RadarProductManager* self_; |    RadarProductManager* self_; | ||||||
| 
 | 
 | ||||||
|  |    boost::asio::thread_pool threadPool_ {4u}; | ||||||
|  | 
 | ||||||
|    std::shared_ptr<ProviderManager> |    std::shared_ptr<ProviderManager> | ||||||
|    GetLevel3ProviderManager(const std::string& product); |    GetLevel3ProviderManager(const std::string& product); | ||||||
| 
 | 
 | ||||||
|  | @ -199,6 +205,10 @@ public: | ||||||
|    void UpdateRecentRecords(RadarProductRecordList& recentList, |    void UpdateRecentRecords(RadarProductRecordList& recentList, | ||||||
|                             std::shared_ptr<types::RadarProductRecord> record); |                             std::shared_ptr<types::RadarProductRecord> record); | ||||||
| 
 | 
 | ||||||
|  |    void LoadNexradFileAsync(CreateNexradFileFunction                    load, | ||||||
|  |                             std::shared_ptr<request::NexradFileRequest> request, | ||||||
|  |                             std::mutex&                                 mutex, | ||||||
|  |                             std::chrono::system_clock::time_point       time); | ||||||
|    void LoadProviderData(std::chrono::system_clock::time_point time, |    void LoadProviderData(std::chrono::system_clock::time_point time, | ||||||
|                          std::shared_ptr<ProviderManager>      providerManager, |                          std::shared_ptr<ProviderManager>      providerManager, | ||||||
|                          RadarProductRecordMap&                recordMap, |                          RadarProductRecordMap&                recordMap, | ||||||
|  | @ -206,6 +216,14 @@ public: | ||||||
|                          std::mutex&                           loadDataMutex, |                          std::mutex&                           loadDataMutex, | ||||||
|                          std::shared_ptr<request::NexradFileRequest> request); |                          std::shared_ptr<request::NexradFileRequest> request); | ||||||
|    void PopulateLevel2ProductTimes(std::chrono::system_clock::time_point time); |    void PopulateLevel2ProductTimes(std::chrono::system_clock::time_point time); | ||||||
|  |    void PopulateLevel3ProductTimes(const std::string& product, | ||||||
|  |                                    std::chrono::system_clock::time_point time); | ||||||
|  | 
 | ||||||
|  |    static void | ||||||
|  |    PopulateProductTimes(std::shared_ptr<ProviderManager> providerManager, | ||||||
|  |                         RadarProductRecordMap&           productRecordMap, | ||||||
|  |                         std::shared_mutex&               productRecordMutex, | ||||||
|  |                         std::chrono::system_clock::time_point time); | ||||||
| 
 | 
 | ||||||
|    static void |    static void | ||||||
|    LoadNexradFile(CreateNexradFileFunction                    load, |    LoadNexradFile(CreateNexradFileFunction                    load, | ||||||
|  | @ -515,7 +533,8 @@ void RadarProductManager::EnableRefresh(common::RadarProductGroup group, | ||||||
|          p->GetLevel3ProviderManager(product); |          p->GetLevel3ProviderManager(product); | ||||||
| 
 | 
 | ||||||
|       // Only enable refresh on available products
 |       // Only enable refresh on available products
 | ||||||
|       scwx::util::async( |       boost::asio::post( | ||||||
|  |          p->threadPool_, | ||||||
|          [=, this]() |          [=, this]() | ||||||
|          { |          { | ||||||
|             providerManager->provider_->RequestAvailableProducts(); |             providerManager->provider_->RequestAvailableProducts(); | ||||||
|  | @ -606,7 +625,8 @@ void RadarProductManagerImpl::RefreshData( | ||||||
|       providerManager->refreshTimer_.cancel(); |       providerManager->refreshTimer_.cancel(); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    scwx::util::async( |    boost::asio::post( | ||||||
|  |       threadPool_, | ||||||
|       [=, this]() |       [=, this]() | ||||||
|       { |       { | ||||||
|          auto [newObjects, totalObjects] = |          auto [newObjects, totalObjects] = | ||||||
|  | @ -766,9 +786,8 @@ void RadarProductManagerImpl::LoadProviderData( | ||||||
|                   providerManager->name(), |                   providerManager->name(), | ||||||
|                   scwx::util::TimeString(time)); |                   scwx::util::TimeString(time)); | ||||||
| 
 | 
 | ||||||
|    RadarProductManagerImpl::LoadNexradFile( |    LoadNexradFileAsync( | ||||||
|       [=, &recordMap, &recordMutex, &loadDataMutex]() |       [=, &recordMap, &recordMutex]() -> std::shared_ptr<wsr88d::NexradFile> | ||||||
|          -> std::shared_ptr<wsr88d::NexradFile> |  | ||||||
|       { |       { | ||||||
|          std::shared_ptr<types::RadarProductRecord> existingRecord = nullptr; |          std::shared_ptr<types::RadarProductRecord> existingRecord = nullptr; | ||||||
|          std::shared_ptr<wsr88d::NexradFile>        nexradFile     = nullptr; |          std::shared_ptr<wsr88d::NexradFile>        nexradFile     = nullptr; | ||||||
|  | @ -792,7 +811,16 @@ void RadarProductManagerImpl::LoadProviderData( | ||||||
|          if (existingRecord == nullptr) |          if (existingRecord == nullptr) | ||||||
|          { |          { | ||||||
|             std::string key = providerManager->provider_->FindKey(time); |             std::string key = providerManager->provider_->FindKey(time); | ||||||
|             nexradFile      = providerManager->provider_->LoadObjectByKey(key); | 
 | ||||||
|  |             if (!key.empty()) | ||||||
|  |             { | ||||||
|  |                nexradFile = providerManager->provider_->LoadObjectByKey(key); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                logger_->warn("Attempting to load object without key: {}", | ||||||
|  |                              scwx::util::TimeString(time)); | ||||||
|  |             } | ||||||
|          } |          } | ||||||
|          else |          else | ||||||
|          { |          { | ||||||
|  | @ -857,11 +885,15 @@ void RadarProductManager::LoadData( | ||||||
| { | { | ||||||
|    logger_->debug("LoadData()"); |    logger_->debug("LoadData()"); | ||||||
| 
 | 
 | ||||||
|    RadarProductManagerImpl::LoadNexradFile( |    scwx::util::async( | ||||||
|       [=, &is]() -> std::shared_ptr<wsr88d::NexradFile> |       [=, &is]() | ||||||
|       { return wsr88d::NexradFileFactory::Create(is); }, |       { | ||||||
|       request, |          RadarProductManagerImpl::LoadNexradFile( | ||||||
|       fileLoadMutex_); |             [=, &is]() -> std::shared_ptr<wsr88d::NexradFile> | ||||||
|  |             { return wsr88d::NexradFileFactory::Create(is); }, | ||||||
|  |             request, | ||||||
|  |             fileLoadMutex_); | ||||||
|  |       }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RadarProductManager::LoadFile( | void RadarProductManager::LoadFile( | ||||||
|  | @ -898,11 +930,15 @@ void RadarProductManager::LoadFile( | ||||||
|                           } |                           } | ||||||
|                        }); |                        }); | ||||||
| 
 | 
 | ||||||
|       RadarProductManagerImpl::LoadNexradFile( |       scwx::util::async( | ||||||
|          [=]() -> std::shared_ptr<wsr88d::NexradFile> |          [=]() | ||||||
|          { return wsr88d::NexradFileFactory::Create(filename); }, |          { | ||||||
|          request, |             RadarProductManagerImpl::LoadNexradFile( | ||||||
|          fileLoadMutex_); |                [=]() -> std::shared_ptr<wsr88d::NexradFile> | ||||||
|  |                { return wsr88d::NexradFileFactory::Create(filename); }, | ||||||
|  |                request, | ||||||
|  |                fileLoadMutex_); | ||||||
|  |          }); | ||||||
|    } |    } | ||||||
|    else if (request != nullptr) |    else if (request != nullptr) | ||||||
|    { |    { | ||||||
|  | @ -911,55 +947,91 @@ void RadarProductManager::LoadFile( | ||||||
|    } |    } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void RadarProductManagerImpl::LoadNexradFileAsync( | ||||||
|  |    CreateNexradFileFunction                    load, | ||||||
|  |    std::shared_ptr<request::NexradFileRequest> request, | ||||||
|  |    std::mutex&                                 mutex, | ||||||
|  |    std::chrono::system_clock::time_point       time) | ||||||
|  | { | ||||||
|  |    boost::asio::post(threadPool_, | ||||||
|  |                      [=, &mutex]() | ||||||
|  |                      { LoadNexradFile(load, request, mutex, time); }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void RadarProductManagerImpl::LoadNexradFile( | void RadarProductManagerImpl::LoadNexradFile( | ||||||
|    CreateNexradFileFunction                    load, |    CreateNexradFileFunction                    load, | ||||||
|    std::shared_ptr<request::NexradFileRequest> request, |    std::shared_ptr<request::NexradFileRequest> request, | ||||||
|    std::mutex&                                 mutex, |    std::mutex&                                 mutex, | ||||||
|    std::chrono::system_clock::time_point       time) |    std::chrono::system_clock::time_point       time) | ||||||
| { | { | ||||||
|    scwx::util::async( |    std::unique_lock lock {mutex}; | ||||||
|       [=, &mutex]() | 
 | ||||||
|  |    std::shared_ptr<wsr88d::NexradFile> nexradFile = load(); | ||||||
|  | 
 | ||||||
|  |    std::shared_ptr<types::RadarProductRecord> record = nullptr; | ||||||
|  | 
 | ||||||
|  |    bool fileValid = (nexradFile != nullptr); | ||||||
|  | 
 | ||||||
|  |    if (fileValid) | ||||||
|  |    { | ||||||
|  |       record = types::RadarProductRecord::Create(nexradFile); | ||||||
|  | 
 | ||||||
|  |       // If the time is already determined, override the time in the file.
 | ||||||
|  |       // Sometimes, level 2 data has been seen to be a few seconds off
 | ||||||
|  |       // between filename and file data. Overriding this can help prevent
 | ||||||
|  |       // issues with locating and storing the correct records.
 | ||||||
|  |       if (time != std::chrono::system_clock::time_point {}) | ||||||
|       { |       { | ||||||
|          std::unique_lock lock {mutex}; |          record->set_time(time); | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|          std::shared_ptr<wsr88d::NexradFile> nexradFile = load(); |       std::shared_ptr<RadarProductManager> manager = | ||||||
|  |          RadarProductManager::Instance(record->radar_id()); | ||||||
| 
 | 
 | ||||||
|          std::shared_ptr<types::RadarProductRecord> record = nullptr; |       manager->Initialize(); | ||||||
|  |       record = manager->p->StoreRadarProductRecord(record); | ||||||
|  |    } | ||||||
| 
 | 
 | ||||||
|          bool fileValid = (nexradFile != nullptr); |    lock.unlock(); | ||||||
| 
 | 
 | ||||||
|          if (fileValid) |    if (request != nullptr) | ||||||
|          { |    { | ||||||
|             record = types::RadarProductRecord::Create(nexradFile); |       request->set_radar_product_record(record); | ||||||
| 
 |       Q_EMIT request->RequestComplete(request); | ||||||
|             // If the time is already determined, override the time in the file.
 |    } | ||||||
|             // Sometimes, level 2 data has been seen to be a few seconds off
 |  | ||||||
|             // between filename and file data. Overriding this can help prevent
 |  | ||||||
|             // issues with locating and storing the correct records.
 |  | ||||||
|             if (time != std::chrono::system_clock::time_point {}) |  | ||||||
|             { |  | ||||||
|                record->set_time(time); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             std::shared_ptr<RadarProductManager> manager = |  | ||||||
|                RadarProductManager::Instance(record->radar_id()); |  | ||||||
| 
 |  | ||||||
|             manager->Initialize(); |  | ||||||
|             record = manager->p->StoreRadarProductRecord(record); |  | ||||||
|          } |  | ||||||
| 
 |  | ||||||
|          lock.unlock(); |  | ||||||
| 
 |  | ||||||
|          if (request != nullptr) |  | ||||||
|          { |  | ||||||
|             request->set_radar_product_record(record); |  | ||||||
|             Q_EMIT request->RequestComplete(request); |  | ||||||
|          } |  | ||||||
|       }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RadarProductManagerImpl::PopulateLevel2ProductTimes( | void RadarProductManagerImpl::PopulateLevel2ProductTimes( | ||||||
|    std::chrono::system_clock::time_point time) |    std::chrono::system_clock::time_point time) | ||||||
|  | { | ||||||
|  |    PopulateProductTimes(level2ProviderManager_, | ||||||
|  |                         level2ProductRecords_, | ||||||
|  |                         level2ProductRecordMutex_, | ||||||
|  |                         time); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RadarProductManagerImpl::PopulateLevel3ProductTimes( | ||||||
|  |    const std::string& product, std::chrono::system_clock::time_point time) | ||||||
|  | { | ||||||
|  |    // Get provider manager
 | ||||||
|  |    auto level3ProviderManager = GetLevel3ProviderManager(product); | ||||||
|  | 
 | ||||||
|  |    // Get product records
 | ||||||
|  |    std::unique_lock level3ProductRecordLock {level3ProductRecordMutex_}; | ||||||
|  |    auto&            level3ProductRecords = level3ProductRecordsMap_[product]; | ||||||
|  |    level3ProductRecordLock.unlock(); | ||||||
|  | 
 | ||||||
|  |    PopulateProductTimes(level3ProviderManager, | ||||||
|  |                         level3ProductRecords, | ||||||
|  |                         level3ProductRecordMutex_, | ||||||
|  |                         time); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RadarProductManagerImpl::PopulateProductTimes( | ||||||
|  |    std::shared_ptr<ProviderManager>      providerManager, | ||||||
|  |    RadarProductRecordMap&                productRecordMap, | ||||||
|  |    std::shared_mutex&                    productRecordMutex, | ||||||
|  |    std::chrono::system_clock::time_point time) | ||||||
| { | { | ||||||
|    const auto today     = std::chrono::floor<std::chrono::days>(time); |    const auto today     = std::chrono::floor<std::chrono::days>(time); | ||||||
|    const auto yesterday = today - std::chrono::days {1}; |    const auto yesterday = today - std::chrono::days {1}; | ||||||
|  | @ -973,7 +1045,7 @@ void RadarProductManagerImpl::PopulateLevel2ProductTimes( | ||||||
|    std::for_each(std::execution::par_unseq, |    std::for_each(std::execution::par_unseq, | ||||||
|                  dates.begin(), |                  dates.begin(), | ||||||
|                  dates.end(), |                  dates.end(), | ||||||
|                  [&, this](const auto& date) |                  [&](const auto& date) | ||||||
|                  { |                  { | ||||||
|                     // Don't query for a time point in the future
 |                     // Don't query for a time point in the future
 | ||||||
|                     if (date > std::chrono::system_clock::now()) |                     if (date > std::chrono::system_clock::now()) | ||||||
|  | @ -983,8 +1055,7 @@ void RadarProductManagerImpl::PopulateLevel2ProductTimes( | ||||||
| 
 | 
 | ||||||
|                     // Query the provider for volume time points
 |                     // Query the provider for volume time points
 | ||||||
|                     auto timePoints = |                     auto timePoints = | ||||||
|                        level2ProviderManager_->provider_->GetTimePointsByDate( |                        providerManager->provider_->GetTimePointsByDate(date); | ||||||
|                           date); |  | ||||||
| 
 | 
 | ||||||
|                     // Lock the merged volume time list
 |                     // Lock the merged volume time list
 | ||||||
|                     std::unique_lock volumeTimesLock {volumeTimesMutex}; |                     std::unique_lock volumeTimesLock {volumeTimesMutex}; | ||||||
|  | @ -995,20 +1066,19 @@ void RadarProductManagerImpl::PopulateLevel2ProductTimes( | ||||||
|                               std::inserter(volumeTimes, volumeTimes.end())); |                               std::inserter(volumeTimes, volumeTimes.end())); | ||||||
|                  }); |                  }); | ||||||
| 
 | 
 | ||||||
|    // Lock the level 2 product record map
 |    // Lock the product record map
 | ||||||
|    std::unique_lock lock {level2ProductRecordMutex_}; |    std::unique_lock lock {productRecordMutex}; | ||||||
| 
 | 
 | ||||||
|    // Merge volume times into map
 |    // Merge volume times into map
 | ||||||
|    std::transform( |    std::transform(volumeTimes.cbegin(), | ||||||
|       volumeTimes.cbegin(), |                   volumeTimes.cend(), | ||||||
|       volumeTimes.cend(), |                   std::inserter(productRecordMap, productRecordMap.begin()), | ||||||
|       std::inserter(level2ProductRecords_, level2ProductRecords_.begin()), |                   [](const std::chrono::system_clock::time_point& time) | ||||||
|       [](const std::chrono::system_clock::time_point& time) |                   { | ||||||
|       { |                      return std::pair<std::chrono::system_clock::time_point, | ||||||
|          return std::pair<std::chrono::system_clock::time_point, |                                       std::weak_ptr<types::RadarProductRecord>>( | ||||||
|                           std::weak_ptr<types::RadarProductRecord>>( |                         time, std::weak_ptr<types::RadarProductRecord> {}); | ||||||
|             time, std::weak_ptr<types::RadarProductRecord> {}); |                   }); | ||||||
|       }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::tuple<std::shared_ptr<types::RadarProductRecord>, | std::tuple<std::shared_ptr<types::RadarProductRecord>, | ||||||
|  | @ -1042,7 +1112,7 @@ RadarProductManagerImpl::GetLevel2ProductRecord( | ||||||
|       record     = recordPtr->second.lock(); |       record     = recordPtr->second.lock(); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    if (record == nullptr && |    if (recordPtr != nullptr && record == nullptr && | ||||||
|        recordTime != std::chrono::system_clock::time_point {}) |        recordTime != std::chrono::system_clock::time_point {}) | ||||||
|    { |    { | ||||||
|       // Product is expired, reload it
 |       // Product is expired, reload it
 | ||||||
|  | @ -1076,6 +1146,9 @@ RadarProductManagerImpl::GetLevel3ProductRecord( | ||||||
|    RadarProductRecordMap::const_pointer       recordPtr {nullptr}; |    RadarProductRecordMap::const_pointer       recordPtr {nullptr}; | ||||||
|    std::chrono::system_clock::time_point      recordTime {time}; |    std::chrono::system_clock::time_point      recordTime {time}; | ||||||
| 
 | 
 | ||||||
|  |    // Ensure Level 3 product records are updated
 | ||||||
|  |    PopulateLevel3ProductTimes(product, time); | ||||||
|  | 
 | ||||||
|    std::unique_lock lock {level3ProductRecordMutex_}; |    std::unique_lock lock {level3ProductRecordMutex_}; | ||||||
| 
 | 
 | ||||||
|    auto it = level3ProductRecordsMap_.find(product); |    auto it = level3ProductRecordsMap_.find(product); | ||||||
|  | @ -1099,15 +1172,12 @@ RadarProductManagerImpl::GetLevel3ProductRecord( | ||||||
| 
 | 
 | ||||||
|    if (recordPtr != nullptr) |    if (recordPtr != nullptr) | ||||||
|    { |    { | ||||||
|       if (time == std::chrono::system_clock::time_point {} || |       // Don't check for an exact time match for level 3 products
 | ||||||
|           time == recordPtr->first) |       recordTime = recordPtr->first; | ||||||
|       { |       record     = recordPtr->second.lock(); | ||||||
|          recordTime = recordPtr->first; |  | ||||||
|          record     = recordPtr->second.lock(); |  | ||||||
|       } |  | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    if (record == nullptr && |    if (recordPtr != nullptr && record == nullptr && | ||||||
|        recordTime != std::chrono::system_clock::time_point {}) |        recordTime != std::chrono::system_clock::time_point {}) | ||||||
|    { |    { | ||||||
|       // Product is expired, reload it
 |       // Product is expired, reload it
 | ||||||
|  | @ -1305,7 +1375,8 @@ void RadarProductManager::UpdateAvailableProducts() | ||||||
| 
 | 
 | ||||||
|    logger_->debug("UpdateAvailableProducts()"); |    logger_->debug("UpdateAvailableProducts()"); | ||||||
| 
 | 
 | ||||||
|    scwx::util::async( |    boost::asio::post( | ||||||
|  |       p->threadPool_, | ||||||
|       [this]() |       [this]() | ||||||
|       { |       { | ||||||
|          auto level3ProviderManager = |          auto level3ProviderManager = | ||||||
|  |  | ||||||
|  | @ -1,3 +1,5 @@ | ||||||
|  | #define NOMINMAX | ||||||
|  | 
 | ||||||
| #include <scwx/qt/manager/timeline_manager.hpp> | #include <scwx/qt/manager/timeline_manager.hpp> | ||||||
| #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> | ||||||
|  | @ -166,6 +168,8 @@ void TimelineManager::SetViewType(types::MapTime viewType) | ||||||
|       // If the selected view type is archive, select using the pinned time
 |       // If the selected view type is archive, select using the pinned time
 | ||||||
|       p->SelectTimeAsync(p->pinnedTime_); |       p->SelectTimeAsync(p->pinnedTime_); | ||||||
|    } |    } | ||||||
|  | 
 | ||||||
|  |    Q_EMIT ViewTypeUpdated(viewType); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TimelineManager::SetLoopTime(std::chrono::minutes loopTime) | void TimelineManager::SetLoopTime(std::chrono::minutes loopTime) | ||||||
|  | @ -390,9 +394,10 @@ void TimelineManager::Impl::UpdateCacheLimit( | ||||||
|    auto endIter   = util::GetBoundedElementIterator(volumeTimes, endTime); |    auto endIter   = util::GetBoundedElementIterator(volumeTimes, endTime); | ||||||
|    std::size_t numVolumeScans = std::distance(startIter, endIter) + 1; |    std::size_t numVolumeScans = std::distance(startIter, endIter) + 1; | ||||||
| 
 | 
 | ||||||
|    // Dynamically update maximum cached volume scans to 1.5x the loop length
 |    // Dynamically update maximum cached volume scans to the lesser of
 | ||||||
|    radarProductManager->SetCacheLimit( |    // either 1.5x the loop length or 5 greater than the loop length
 | ||||||
|       static_cast<std::size_t>(numVolumeScans * 1.5)); |    radarProductManager->SetCacheLimit(std::min( | ||||||
|  |       static_cast<std::size_t>(numVolumeScans * 1.5), numVolumeScans + 5u)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TimelineManager::Impl::Play() | void TimelineManager::Impl::Play() | ||||||
|  |  | ||||||
|  | @ -359,7 +359,8 @@ void MapWidget::SelectElevation(float elevation) | ||||||
| void MapWidget::SelectRadarProduct(common::RadarProductGroup group, | void MapWidget::SelectRadarProduct(common::RadarProductGroup group, | ||||||
|                                    const std::string&        product, |                                    const std::string&        product, | ||||||
|                                    std::int16_t              productCode, |                                    std::int16_t              productCode, | ||||||
|                                    std::chrono::system_clock::time_point time) |                                    std::chrono::system_clock::time_point time, | ||||||
|  |                                    bool                                  update) | ||||||
| { | { | ||||||
|    bool radarProductViewCreated = false; |    bool radarProductViewCreated = false; | ||||||
| 
 | 
 | ||||||
|  | @ -420,7 +421,7 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group, | ||||||
|                common::GetLevel3Palette(productCode); |                common::GetLevel3Palette(productCode); | ||||||
|          p->InitializeNewRadarProductView(palette); |          p->InitializeNewRadarProductView(palette); | ||||||
|       } |       } | ||||||
|       else |       else if (update) | ||||||
|       { |       { | ||||||
|          radarProductView->Update(); |          radarProductView->Update(); | ||||||
|       } |       } | ||||||
|  | @ -486,7 +487,9 @@ void MapWidget::SelectRadarSite(std::shared_ptr<config::RadarSite> radarSite, | ||||||
|          radarProductView->set_radar_product_manager(p->radarProductManager_); |          radarProductView->set_radar_product_manager(p->radarProductManager_); | ||||||
|          SelectRadarProduct(radarProductView->GetRadarProductGroup(), |          SelectRadarProduct(radarProductView->GetRadarProductGroup(), | ||||||
|                             radarProductView->GetRadarProductName(), |                             radarProductView->GetRadarProductName(), | ||||||
|                             0); |                             0, | ||||||
|  |                             radarProductView->selected_time(), | ||||||
|  |                             false); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       AddLayers(); |       AddLayers(); | ||||||
|  | @ -1053,9 +1056,6 @@ void MapWidgetImpl::SetRadarSite(const std::string& radarSite) | ||||||
|       // Set new RadarProductManager
 |       // Set new RadarProductManager
 | ||||||
|       radarProductManager_ = manager::RadarProductManager::Instance(radarSite); |       radarProductManager_ = manager::RadarProductManager::Instance(radarSite); | ||||||
| 
 | 
 | ||||||
|       // Re-enable auto-update
 |  | ||||||
|       autoUpdateEnabled_ = true; |  | ||||||
| 
 |  | ||||||
|       // Connect signals to new RadarProductManager
 |       // Connect signals to new RadarProductManager
 | ||||||
|       RadarProductManagerConnect(); |       RadarProductManagerConnect(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -54,12 +54,14 @@ public: | ||||||
|     * @param [in] group Radar product group |     * @param [in] group Radar product group | ||||||
|     * @param [in] product Radar product name |     * @param [in] product Radar product name | ||||||
|     * @param [in] productCode Radar product code (optional) |     * @param [in] productCode Radar product code (optional) | ||||||
|     * @paran [in] time Product time. Default is the latest available. |     * @param [in] time Product time. Default is the latest available. | ||||||
|  |     * @param [in] update Whether to update the radar product view on selection | ||||||
|     */ |     */ | ||||||
|    void SelectRadarProduct(common::RadarProductGroup group, |    void SelectRadarProduct(common::RadarProductGroup group, | ||||||
|                            const std::string&        product, |                            const std::string&        product, | ||||||
|                            std::int16_t              productCode      = 0, |                            std::int16_t              productCode        = 0, | ||||||
|                            std::chrono::system_clock::time_point time = {}); |                            std::chrono::system_clock::time_point time   = {}, | ||||||
|  |                            bool                                  update = true); | ||||||
| 
 | 
 | ||||||
|    void SelectRadarProduct(std::shared_ptr<types::RadarProductRecord> record); |    void SelectRadarProduct(std::shared_ptr<types::RadarProductRecord> record); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,20 +20,34 @@ static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||||
| class AnimationDockWidgetImpl | class AnimationDockWidgetImpl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit AnimationDockWidgetImpl(AnimationDockWidget* self) : self_ {self} {} |    explicit AnimationDockWidgetImpl(AnimationDockWidget* self) : self_ {self} | ||||||
|  |    { | ||||||
|  |       static const QString prefix   = QObject::tr("Auto Update"); | ||||||
|  |       static const QString disabled = QObject::tr("Disabled"); | ||||||
|  |       static const QString enabled  = QObject::tr("Enabled"); | ||||||
|  | 
 | ||||||
|  |       enabledString_  = QString("%1: %2").arg(prefix).arg(enabled); | ||||||
|  |       disabledString_ = QString("%1: %2").arg(prefix).arg(disabled); | ||||||
|  |    } | ||||||
|    ~AnimationDockWidgetImpl() = default; |    ~AnimationDockWidgetImpl() = default; | ||||||
| 
 | 
 | ||||||
|    const QIcon kPauseIcon_ {":/res/icons/font-awesome-6/pause-solid.svg"}; |    const QIcon kPauseIcon_ {":/res/icons/font-awesome-6/pause-solid.svg"}; | ||||||
|    const QIcon kPlayIcon_ {":/res/icons/font-awesome-6/play-solid.svg"}; |    const QIcon kPlayIcon_ {":/res/icons/font-awesome-6/play-solid.svg"}; | ||||||
| 
 | 
 | ||||||
|  |    QString enabledString_; | ||||||
|  |    QString disabledString_; | ||||||
|  | 
 | ||||||
|    AnimationDockWidget* self_; |    AnimationDockWidget* self_; | ||||||
| 
 | 
 | ||||||
|    types::AnimationState animationState_ {types::AnimationState::Pause}; |    types::AnimationState animationState_ {types::AnimationState::Pause}; | ||||||
|  |    types::MapTime        viewType_ {types::MapTime::Live}; | ||||||
|  |    bool                  isLive_ {true}; | ||||||
| 
 | 
 | ||||||
|    std::chrono::sys_days selectedDate_ {}; |    std::chrono::sys_days selectedDate_ {}; | ||||||
|    std::chrono::seconds  selectedTime_ {}; |    std::chrono::seconds  selectedTime_ {}; | ||||||
| 
 | 
 | ||||||
|    void ConnectSignals(); |    void ConnectSignals(); | ||||||
|  |    void UpdateAutoUpdateLabel(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| AnimationDockWidget::AnimationDockWidget(QWidget* parent) : | AnimationDockWidget::AnimationDockWidget(QWidget* parent) : | ||||||
|  | @ -211,32 +225,56 @@ void AnimationDockWidgetImpl::ConnectSignals() | ||||||
| 
 | 
 | ||||||
| void AnimationDockWidget::UpdateAnimationState(types::AnimationState state) | void AnimationDockWidget::UpdateAnimationState(types::AnimationState state) | ||||||
| { | { | ||||||
|    // Update icon to opposite of state
 |    if (p->animationState_ != state) | ||||||
|    switch (state) |  | ||||||
|    { |    { | ||||||
|    case types::AnimationState::Pause: |       // Update icon to opposite of state
 | ||||||
|       ui->playButton->setIcon(p->kPlayIcon_); |       switch (state) | ||||||
|       break; |       { | ||||||
|  |       case types::AnimationState::Pause: | ||||||
|  |          ui->playButton->setIcon(p->kPlayIcon_); | ||||||
|  |          break; | ||||||
| 
 | 
 | ||||||
|    case types::AnimationState::Play: |       case types::AnimationState::Play: | ||||||
|       ui->playButton->setIcon(p->kPauseIcon_); |          ui->playButton->setIcon(p->kPauseIcon_); | ||||||
|       break; |          break; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       p->animationState_ = state; | ||||||
|  |       p->UpdateAutoUpdateLabel(); | ||||||
|    } |    } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AnimationDockWidget::UpdateLiveState(bool isLive) | void AnimationDockWidget::UpdateLiveState(bool isLive) | ||||||
| { | { | ||||||
|    static const QString prefix   = tr("Auto Update"); |    if (p->isLive_ != isLive) | ||||||
|    static const QString disabled = tr("Disabled"); |  | ||||||
|    static const QString enabled  = tr("Enabled"); |  | ||||||
| 
 |  | ||||||
|    if (isLive) |  | ||||||
|    { |    { | ||||||
|       ui->autoUpdateLabel->setText(QString("%1: %2").arg(prefix).arg(enabled)); |       p->isLive_ = isLive; | ||||||
|  |       p->UpdateAutoUpdateLabel(); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationDockWidget::UpdateViewType(types::MapTime viewType) | ||||||
|  | { | ||||||
|  |    if (p->viewType_ != viewType) | ||||||
|  |    { | ||||||
|  |       p->viewType_ = viewType; | ||||||
|  |       p->UpdateAutoUpdateLabel(); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AnimationDockWidgetImpl::UpdateAutoUpdateLabel() | ||||||
|  | { | ||||||
|  |    // Display "Auto Update: Enabled" if:
 | ||||||
|  |    // - The map is live, and auto-updating (map widget update)
 | ||||||
|  |    // - "Live" is selected, and the map is playing (timeline manager update)
 | ||||||
|  |    if (isLive_ || (viewType_ == types::MapTime::Live && | ||||||
|  |                    animationState_ == types::AnimationState::Play)) | ||||||
|  |    { | ||||||
|  |       self_->ui->autoUpdateLabel->setText(enabledString_); | ||||||
|    } |    } | ||||||
|    else |    else | ||||||
|    { |    { | ||||||
|       ui->autoUpdateLabel->setText(QString("%1: %2").arg(prefix).arg(disabled)); |       self_->ui->autoUpdateLabel->setText(disabledString_); | ||||||
|    } |    } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ public: | ||||||
| public slots: | public slots: | ||||||
|    void UpdateAnimationState(types::AnimationState state); |    void UpdateAnimationState(types::AnimationState state); | ||||||
|    void UpdateLiveState(bool isLive); |    void UpdateLiveState(bool isLive); | ||||||
|  |    void UpdateViewType(types::MapTime viewType); | ||||||
| 
 | 
 | ||||||
| signals: | signals: | ||||||
|    void ViewTypeChanged(types::MapTime viewType); |    void ViewTypeChanged(types::MapTime viewType); | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ | ||||||
|     <x>0</x> |     <x>0</x> | ||||||
|     <y>0</y> |     <y>0</y> | ||||||
|     <width>200</width> |     <width>200</width> | ||||||
|     <height>348</height> |     <height>543</height> | ||||||
|    </rect> |    </rect> | ||||||
|   </property> |   </property> | ||||||
|   <property name="windowTitle"> |   <property name="windowTitle"> | ||||||
|  | @ -16,296 +16,336 @@ | ||||||
|   <widget class="QWidget" name="dockWidgetContents"> |   <widget class="QWidget" name="dockWidgetContents"> | ||||||
|    <layout class="QVBoxLayout" name="verticalLayout"> |    <layout class="QVBoxLayout" name="verticalLayout"> | ||||||
|     <item> |     <item> | ||||||
|      <widget class="QGroupBox" name="timelineGroupBox"> |      <widget class="QScrollArea" name="scrollArea"> | ||||||
|       <property name="title"> |       <property name="frameShape"> | ||||||
|        <string>Timeline</string> |        <enum>QFrame::NoFrame</enum> | ||||||
|       </property> |       </property> | ||||||
|       <layout class="QVBoxLayout" name="verticalLayout_6"> |       <property name="lineWidth"> | ||||||
|        <item> |        <number>0</number> | ||||||
|         <widget class="QLabel" name="autoUpdateLabel"> |       </property> | ||||||
|          <property name="text"> |       <property name="horizontalScrollBarPolicy"> | ||||||
|           <string>Auto Update: Enabled</string> |        <enum>Qt::ScrollBarAlwaysOff</enum> | ||||||
|          </property> |       </property> | ||||||
|         </widget> |       <property name="widgetResizable"> | ||||||
|        </item> |        <bool>true</bool> | ||||||
|        <item> |       </property> | ||||||
|         <widget class="QRadioButton" name="liveViewRadioButton"> |       <widget class="QWidget" name="scrollAreaContents"> | ||||||
|          <property name="text"> |        <property name="geometry"> | ||||||
|           <string>Live View</string> |         <rect> | ||||||
|          </property> |          <x>0</x> | ||||||
|          <property name="checked"> |          <y>0</y> | ||||||
|           <bool>true</bool> |          <width>182</width> | ||||||
|          </property> |          <height>506</height> | ||||||
|         </widget> |         </rect> | ||||||
|        </item> |        </property> | ||||||
|        <item> |        <layout class="QVBoxLayout" name="verticalLayout_2"> | ||||||
|         <widget class="QRadioButton" name="archiveViewRadioButton"> |         <property name="leftMargin"> | ||||||
|          <property name="text"> |          <number>0</number> | ||||||
|           <string>Archive View</string> |         </property> | ||||||
|          </property> |         <property name="topMargin"> | ||||||
|         </widget> |          <number>0</number> | ||||||
|        </item> |         </property> | ||||||
|        <item> |         <property name="rightMargin"> | ||||||
|         <widget class="QDateEdit" name="dateEdit"> |          <number>0</number> | ||||||
|          <property name="correctionMode"> |         </property> | ||||||
|           <enum>QAbstractSpinBox::CorrectToNearestValue</enum> |         <property name="bottomMargin"> | ||||||
|          </property> |          <number>0</number> | ||||||
|          <property name="minimumDateTime"> |         </property> | ||||||
|           <datetime> |         <item> | ||||||
|            <hour>0</hour> |          <widget class="QGroupBox" name="timelineGroupBox"> | ||||||
|            <minute>0</minute> |           <property name="title"> | ||||||
|            <second>0</second> |            <string>Timeline</string> | ||||||
|            <year>1991</year> |  | ||||||
|            <month>6</month> |  | ||||||
|            <day>1</day> |  | ||||||
|           </datetime> |  | ||||||
|          </property> |  | ||||||
|          <property name="displayFormat"> |  | ||||||
|           <string>yyyy-MM-dd</string> |  | ||||||
|          </property> |  | ||||||
|          <property name="calendarPopup"> |  | ||||||
|           <bool>true</bool> |  | ||||||
|          </property> |  | ||||||
|         </widget> |  | ||||||
|        </item> |  | ||||||
|        <item> |  | ||||||
|         <widget class="QFrame" name="frame"> |  | ||||||
|          <property name="frameShape"> |  | ||||||
|           <enum>QFrame::StyledPanel</enum> |  | ||||||
|          </property> |  | ||||||
|          <property name="frameShadow"> |  | ||||||
|           <enum>QFrame::Raised</enum> |  | ||||||
|          </property> |  | ||||||
|          <layout class="QHBoxLayout" name="horizontalLayout"> |  | ||||||
|           <property name="leftMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |           </property> | ||||||
|           <property name="topMargin"> |           <layout class="QVBoxLayout" name="verticalLayout_6"> | ||||||
|            <number>0</number> |            <item> | ||||||
|  |             <widget class="QLabel" name="autoUpdateLabel"> | ||||||
|  |              <property name="text"> | ||||||
|  |               <string>Auto Update: Enabled</string> | ||||||
|  |              </property> | ||||||
|  |             </widget> | ||||||
|  |            </item> | ||||||
|  |            <item> | ||||||
|  |             <widget class="QRadioButton" name="liveViewRadioButton"> | ||||||
|  |              <property name="text"> | ||||||
|  |               <string>Live View</string> | ||||||
|  |              </property> | ||||||
|  |              <property name="checked"> | ||||||
|  |               <bool>true</bool> | ||||||
|  |              </property> | ||||||
|  |             </widget> | ||||||
|  |            </item> | ||||||
|  |            <item> | ||||||
|  |             <widget class="QRadioButton" name="archiveViewRadioButton"> | ||||||
|  |              <property name="text"> | ||||||
|  |               <string>Archive View</string> | ||||||
|  |              </property> | ||||||
|  |             </widget> | ||||||
|  |            </item> | ||||||
|  |            <item> | ||||||
|  |             <widget class="QDateEdit" name="dateEdit"> | ||||||
|  |              <property name="correctionMode"> | ||||||
|  |               <enum>QAbstractSpinBox::CorrectToNearestValue</enum> | ||||||
|  |              </property> | ||||||
|  |              <property name="minimumDateTime"> | ||||||
|  |               <datetime> | ||||||
|  |                <hour>0</hour> | ||||||
|  |                <minute>0</minute> | ||||||
|  |                <second>0</second> | ||||||
|  |                <year>1991</year> | ||||||
|  |                <month>6</month> | ||||||
|  |                <day>1</day> | ||||||
|  |               </datetime> | ||||||
|  |              </property> | ||||||
|  |              <property name="displayFormat"> | ||||||
|  |               <string>yyyy-MM-dd</string> | ||||||
|  |              </property> | ||||||
|  |              <property name="calendarPopup"> | ||||||
|  |               <bool>true</bool> | ||||||
|  |              </property> | ||||||
|  |             </widget> | ||||||
|  |            </item> | ||||||
|  |            <item> | ||||||
|  |             <widget class="QFrame" name="frame"> | ||||||
|  |              <property name="frameShape"> | ||||||
|  |               <enum>QFrame::StyledPanel</enum> | ||||||
|  |              </property> | ||||||
|  |              <property name="frameShadow"> | ||||||
|  |               <enum>QFrame::Raised</enum> | ||||||
|  |              </property> | ||||||
|  |              <layout class="QHBoxLayout" name="horizontalLayout"> | ||||||
|  |               <property name="leftMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="topMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="rightMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="bottomMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <item> | ||||||
|  |                <widget class="QTimeEdit" name="timeEdit"> | ||||||
|  |                 <property name="correctionMode"> | ||||||
|  |                  <enum>QAbstractSpinBox::CorrectToNearestValue</enum> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="displayFormat"> | ||||||
|  |                  <string>HH:mm</string> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item> | ||||||
|  |                <widget class="QLabel" name="label"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>UTC</string> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |              </layout> | ||||||
|  |             </widget> | ||||||
|  |            </item> | ||||||
|  |            <item> | ||||||
|  |             <widget class="QFrame" name="frame_3"> | ||||||
|  |              <property name="frameShape"> | ||||||
|  |               <enum>QFrame::StyledPanel</enum> | ||||||
|  |              </property> | ||||||
|  |              <property name="frameShadow"> | ||||||
|  |               <enum>QFrame::Raised</enum> | ||||||
|  |              </property> | ||||||
|  |              <layout class="QGridLayout" name="gridLayout"> | ||||||
|  |               <property name="leftMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="topMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="rightMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="bottomMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <item row="0" column="1"> | ||||||
|  |                <widget class="QSpinBox" name="loopTimeSpinBox"> | ||||||
|  |                 <property name="correctionMode"> | ||||||
|  |                  <enum>QAbstractSpinBox::CorrectToNearestValue</enum> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="suffix"> | ||||||
|  |                  <string> min</string> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="minimum"> | ||||||
|  |                  <number>1</number> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="maximum"> | ||||||
|  |                  <number>1440</number> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="value"> | ||||||
|  |                  <number>30</number> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item row="0" column="0"> | ||||||
|  |                <widget class="QLabel" name="loopTimeLabel"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>Loop Time</string> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item row="1" column="0"> | ||||||
|  |                <widget class="QLabel" name="loopSpeedLabel"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>Loop Speed</string> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item row="1" column="1"> | ||||||
|  |                <widget class="QDoubleSpinBox" name="loopSpeedSpinBox"> | ||||||
|  |                 <property name="correctionMode"> | ||||||
|  |                  <enum>QAbstractSpinBox::CorrectToNearestValue</enum> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="suffix"> | ||||||
|  |                  <string>x</string> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="minimum"> | ||||||
|  |                  <double>1.000000000000000</double> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="value"> | ||||||
|  |                  <double>1.000000000000000</double> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item row="2" column="0"> | ||||||
|  |                <widget class="QLabel" name="loopDelayLabel"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>Loop Delay</string> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item row="2" column="1"> | ||||||
|  |                <widget class="QDoubleSpinBox" name="loopDelaySpinBox"> | ||||||
|  |                 <property name="suffix"> | ||||||
|  |                  <string> sec</string> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="decimals"> | ||||||
|  |                  <number>1</number> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="maximum"> | ||||||
|  |                  <double>15.000000000000000</double> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="singleStep"> | ||||||
|  |                  <double>0.100000000000000</double> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="value"> | ||||||
|  |                  <double>2.500000000000000</double> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |              </layout> | ||||||
|  |             </widget> | ||||||
|  |            </item> | ||||||
|  |            <item> | ||||||
|  |             <widget class="QFrame" name="frame_2"> | ||||||
|  |              <property name="frameShape"> | ||||||
|  |               <enum>QFrame::StyledPanel</enum> | ||||||
|  |              </property> | ||||||
|  |              <property name="frameShadow"> | ||||||
|  |               <enum>QFrame::Raised</enum> | ||||||
|  |              </property> | ||||||
|  |              <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||||||
|  |               <property name="spacing"> | ||||||
|  |                <number>1</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="leftMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="topMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="rightMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <property name="bottomMargin"> | ||||||
|  |                <number>0</number> | ||||||
|  |               </property> | ||||||
|  |               <item> | ||||||
|  |                <widget class="QToolButton" name="beginButton"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>...</string> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="icon"> | ||||||
|  |                  <iconset resource="../../../../scwx-qt.qrc"> | ||||||
|  |                   <normaloff>:/res/icons/font-awesome-6/backward-step-solid.svg</normaloff>:/res/icons/font-awesome-6/backward-step-solid.svg</iconset> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item> | ||||||
|  |                <widget class="QToolButton" name="stepBackButton"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>...</string> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="icon"> | ||||||
|  |                  <iconset resource="../../../../scwx-qt.qrc"> | ||||||
|  |                   <normaloff>:/res/icons/font-awesome-6/angle-left-solid.svg</normaloff>:/res/icons/font-awesome-6/angle-left-solid.svg</iconset> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item> | ||||||
|  |                <widget class="QToolButton" name="playButton"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>...</string> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="icon"> | ||||||
|  |                  <iconset resource="../../../../scwx-qt.qrc"> | ||||||
|  |                   <normaloff>:/res/icons/font-awesome-6/play-solid.svg</normaloff>:/res/icons/font-awesome-6/play-solid.svg</iconset> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item> | ||||||
|  |                <widget class="QToolButton" name="stepNextButton"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>...</string> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="icon"> | ||||||
|  |                  <iconset resource="../../../../scwx-qt.qrc"> | ||||||
|  |                   <normaloff>:/res/icons/font-awesome-6/angle-right-solid.svg</normaloff>:/res/icons/font-awesome-6/angle-right-solid.svg</iconset> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |               <item> | ||||||
|  |                <widget class="QToolButton" name="endButton"> | ||||||
|  |                 <property name="text"> | ||||||
|  |                  <string>...</string> | ||||||
|  |                 </property> | ||||||
|  |                 <property name="icon"> | ||||||
|  |                  <iconset resource="../../../../scwx-qt.qrc"> | ||||||
|  |                   <normaloff>:/res/icons/font-awesome-6/forward-step-solid.svg</normaloff>:/res/icons/font-awesome-6/forward-step-solid.svg</iconset> | ||||||
|  |                 </property> | ||||||
|  |                </widget> | ||||||
|  |               </item> | ||||||
|  |              </layout> | ||||||
|  |             </widget> | ||||||
|  |            </item> | ||||||
|  |           </layout> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item> | ||||||
|  |          <spacer name="verticalSpacer"> | ||||||
|  |           <property name="orientation"> | ||||||
|  |            <enum>Qt::Vertical</enum> | ||||||
|           </property> |           </property> | ||||||
|           <property name="rightMargin"> |           <property name="sizeHint" stdset="0"> | ||||||
|            <number>0</number> |            <size> | ||||||
|  |             <width>20</width> | ||||||
|  |             <height>40</height> | ||||||
|  |            </size> | ||||||
|           </property> |           </property> | ||||||
|           <property name="bottomMargin"> |          </spacer> | ||||||
|            <number>0</number> |         </item> | ||||||
|           </property> |        </layout> | ||||||
|           <item> |       </widget> | ||||||
|            <widget class="QTimeEdit" name="timeEdit"> |  | ||||||
|             <property name="correctionMode"> |  | ||||||
|              <enum>QAbstractSpinBox::CorrectToNearestValue</enum> |  | ||||||
|             </property> |  | ||||||
|             <property name="displayFormat"> |  | ||||||
|              <string>HH:mm</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QLabel" name="label"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>UTC</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|          </layout> |  | ||||||
|         </widget> |  | ||||||
|        </item> |  | ||||||
|        <item> |  | ||||||
|         <widget class="QFrame" name="frame_3"> |  | ||||||
|          <property name="frameShape"> |  | ||||||
|           <enum>QFrame::StyledPanel</enum> |  | ||||||
|          </property> |  | ||||||
|          <property name="frameShadow"> |  | ||||||
|           <enum>QFrame::Raised</enum> |  | ||||||
|          </property> |  | ||||||
|          <layout class="QGridLayout" name="gridLayout"> |  | ||||||
|           <property name="leftMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |  | ||||||
|           <property name="topMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |  | ||||||
|           <property name="rightMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |  | ||||||
|           <property name="bottomMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |  | ||||||
|           <item row="0" column="1"> |  | ||||||
|            <widget class="QSpinBox" name="loopTimeSpinBox"> |  | ||||||
|             <property name="correctionMode"> |  | ||||||
|              <enum>QAbstractSpinBox::CorrectToNearestValue</enum> |  | ||||||
|             </property> |  | ||||||
|             <property name="suffix"> |  | ||||||
|              <string> min</string> |  | ||||||
|             </property> |  | ||||||
|             <property name="minimum"> |  | ||||||
|              <number>1</number> |  | ||||||
|             </property> |  | ||||||
|             <property name="maximum"> |  | ||||||
|              <number>1440</number> |  | ||||||
|             </property> |  | ||||||
|             <property name="value"> |  | ||||||
|              <number>30</number> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item row="0" column="0"> |  | ||||||
|            <widget class="QLabel" name="loopTimeLabel"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Loop Time</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item row="1" column="0"> |  | ||||||
|            <widget class="QLabel" name="loopSpeedLabel"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Loop Speed</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item row="1" column="1"> |  | ||||||
|            <widget class="QDoubleSpinBox" name="loopSpeedSpinBox"> |  | ||||||
|             <property name="correctionMode"> |  | ||||||
|              <enum>QAbstractSpinBox::CorrectToNearestValue</enum> |  | ||||||
|             </property> |  | ||||||
|             <property name="suffix"> |  | ||||||
|              <string>x</string> |  | ||||||
|             </property> |  | ||||||
|             <property name="minimum"> |  | ||||||
|              <double>1.000000000000000</double> |  | ||||||
|             </property> |  | ||||||
|             <property name="value"> |  | ||||||
|              <double>1.000000000000000</double> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item row="2" column="0"> |  | ||||||
|            <widget class="QLabel" name="loopDelayLabel"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Loop Delay</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item row="2" column="1"> |  | ||||||
|            <widget class="QDoubleSpinBox" name="loopDelaySpinBox"> |  | ||||||
|             <property name="suffix"> |  | ||||||
|              <string> sec</string> |  | ||||||
|             </property> |  | ||||||
|             <property name="decimals"> |  | ||||||
|              <number>1</number> |  | ||||||
|             </property> |  | ||||||
|             <property name="maximum"> |  | ||||||
|              <double>15.000000000000000</double> |  | ||||||
|             </property> |  | ||||||
|             <property name="singleStep"> |  | ||||||
|              <double>0.100000000000000</double> |  | ||||||
|             </property> |  | ||||||
|             <property name="value"> |  | ||||||
|              <double>2.500000000000000</double> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|          </layout> |  | ||||||
|         </widget> |  | ||||||
|        </item> |  | ||||||
|        <item> |  | ||||||
|         <widget class="QFrame" name="frame_2"> |  | ||||||
|          <property name="frameShape"> |  | ||||||
|           <enum>QFrame::StyledPanel</enum> |  | ||||||
|          </property> |  | ||||||
|          <property name="frameShadow"> |  | ||||||
|           <enum>QFrame::Raised</enum> |  | ||||||
|          </property> |  | ||||||
|          <layout class="QHBoxLayout" name="horizontalLayout_2"> |  | ||||||
|           <property name="spacing"> |  | ||||||
|            <number>1</number> |  | ||||||
|           </property> |  | ||||||
|           <property name="leftMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |  | ||||||
|           <property name="topMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |  | ||||||
|           <property name="rightMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |  | ||||||
|           <property name="bottomMargin"> |  | ||||||
|            <number>0</number> |  | ||||||
|           </property> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QToolButton" name="beginButton"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>...</string> |  | ||||||
|             </property> |  | ||||||
|             <property name="icon"> |  | ||||||
|              <iconset resource="../../../../scwx-qt.qrc"> |  | ||||||
|               <normaloff>:/res/icons/font-awesome-6/backward-step-solid.svg</normaloff>:/res/icons/font-awesome-6/backward-step-solid.svg</iconset> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QToolButton" name="stepBackButton"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>...</string> |  | ||||||
|             </property> |  | ||||||
|             <property name="icon"> |  | ||||||
|              <iconset resource="../../../../scwx-qt.qrc"> |  | ||||||
|               <normaloff>:/res/icons/font-awesome-6/angle-left-solid.svg</normaloff>:/res/icons/font-awesome-6/angle-left-solid.svg</iconset> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QToolButton" name="playButton"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>...</string> |  | ||||||
|             </property> |  | ||||||
|             <property name="icon"> |  | ||||||
|              <iconset resource="../../../../scwx-qt.qrc"> |  | ||||||
|               <normaloff>:/res/icons/font-awesome-6/play-solid.svg</normaloff>:/res/icons/font-awesome-6/play-solid.svg</iconset> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QToolButton" name="stepNextButton"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>...</string> |  | ||||||
|             </property> |  | ||||||
|             <property name="icon"> |  | ||||||
|              <iconset resource="../../../../scwx-qt.qrc"> |  | ||||||
|               <normaloff>:/res/icons/font-awesome-6/angle-right-solid.svg</normaloff>:/res/icons/font-awesome-6/angle-right-solid.svg</iconset> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QToolButton" name="endButton"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>...</string> |  | ||||||
|             </property> |  | ||||||
|             <property name="icon"> |  | ||||||
|              <iconset resource="../../../../scwx-qt.qrc"> |  | ||||||
|               <normaloff>:/res/icons/font-awesome-6/forward-step-solid.svg</normaloff>:/res/icons/font-awesome-6/forward-step-solid.svg</iconset> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|          </layout> |  | ||||||
|         </widget> |  | ||||||
|        </item> |  | ||||||
|       </layout> |  | ||||||
|      </widget> |      </widget> | ||||||
|     </item> |     </item> | ||||||
|     <item> |  | ||||||
|      <spacer name="verticalSpacer"> |  | ||||||
|       <property name="orientation"> |  | ||||||
|        <enum>Qt::Vertical</enum> |  | ||||||
|       </property> |  | ||||||
|       <property name="sizeHint" stdset="0"> |  | ||||||
|        <size> |  | ||||||
|         <width>20</width> |  | ||||||
|         <height>40</height> |  | ||||||
|        </size> |  | ||||||
|       </property> |  | ||||||
|      </spacer> |  | ||||||
|     </item> |  | ||||||
|    </layout> |    </layout> | ||||||
|   </widget> |   </widget> | ||||||
|  </widget> |  </widget> | ||||||
|  |  | ||||||
|  | @ -176,28 +176,28 @@ bool WmoHeader::Parse(std::istream& is) | ||||||
| 
 | 
 | ||||||
|       if (wmoTokenList.size() < 3 || wmoTokenList.size() > 4) |       if (wmoTokenList.size() < 3 || wmoTokenList.size() > 4) | ||||||
|       { |       { | ||||||
|          logger_->debug("Invalid number of WMO tokens"); |          logger_->warn("Invalid number of WMO tokens"); | ||||||
|          headerValid = false; |          headerValid = false; | ||||||
|       } |       } | ||||||
|       else if (wmoTokenList[0].size() != 6) |       else if (wmoTokenList[0].size() != 6) | ||||||
|       { |       { | ||||||
|          logger_->debug("WMO identifier malformed"); |          logger_->warn("WMO identifier malformed"); | ||||||
|          headerValid = false; |          headerValid = false; | ||||||
|       } |       } | ||||||
|       else if (wmoTokenList[1].size() != 4) |       else if (wmoTokenList[1].size() != 4) | ||||||
|       { |       { | ||||||
|          logger_->debug("ICAO malformed"); |          logger_->warn("ICAO malformed"); | ||||||
|          headerValid = false; |          headerValid = false; | ||||||
|       } |       } | ||||||
|       else if (wmoTokenList[2].size() != 6) |       else if (wmoTokenList[2].size() != 6) | ||||||
|       { |       { | ||||||
|          logger_->debug("Date/time malformed"); |          logger_->warn("Date/time malformed"); | ||||||
|          headerValid = false; |          headerValid = false; | ||||||
|       } |       } | ||||||
|       else if (wmoTokenList.size() == 4 && wmoTokenList[3].size() != 3) |       else if (wmoTokenList.size() == 4 && wmoTokenList[3].size() != 3) | ||||||
|       { |       { | ||||||
|          // BBB indicator is optional
 |          // BBB indicator is optional
 | ||||||
|          logger_->debug("BBB indicator malformed"); |          logger_->warn("BBB indicator malformed"); | ||||||
|          headerValid = false; |          headerValid = false; | ||||||
|       } |       } | ||||||
|       else |       else | ||||||
|  | @ -226,7 +226,7 @@ bool WmoHeader::Parse(std::istream& is) | ||||||
|    { |    { | ||||||
|       if (awipsLine.size() != 6) |       if (awipsLine.size() != 6) | ||||||
|       { |       { | ||||||
|          logger_->debug("AWIPS Identifier Line bad size"); |          logger_->warn("AWIPS Identifier Line bad size"); | ||||||
|          headerValid = false; |          headerValid = false; | ||||||
|       } |       } | ||||||
|       else |       else | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat