Merge pull request #62 from dpaulat/feature/timeline-part-3

Complete Timeline Animation
This commit is contained in:
Dan Paulat 2023-06-20 22:54:23 -05:00 committed by GitHub
commit effe78e1be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 730 additions and 525 deletions

View file

@ -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,

View file

@ -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>

View file

@ -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 =

View file

@ -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()

View file

@ -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();

View file

@ -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);

View file

@ -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_);
} }
} }

View file

@ -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);

View file

@ -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>

View file

@ -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