diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 74ce7840..ab666399 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -90,11 +90,13 @@ set(SRC_MAP source/scwx/qt/map/alert_layer.cpp source/scwx/qt/map/radar_product_layer.cpp source/scwx/qt/map/radar_range_layer.cpp) set(HDR_MODEL source/scwx/qt/model/alert_model.hpp + source/scwx/qt/model/alert_proxy_model.hpp source/scwx/qt/model/radar_product_model.hpp source/scwx/qt/model/radar_site_model.hpp source/scwx/qt/model/tree_item.hpp source/scwx/qt/model/tree_model.hpp) set(SRC_MODEL source/scwx/qt/model/alert_model.cpp + source/scwx/qt/model/alert_proxy_model.cpp source/scwx/qt/model/radar_product_model.cpp source/scwx/qt/model/radar_site_model.cpp source/scwx/qt/model/tree_item.cpp diff --git a/scwx-qt/source/scwx/qt/model/alert_model.cpp b/scwx-qt/source/scwx/qt/model/alert_model.cpp index 58a4636b..1d380cdb 100644 --- a/scwx-qt/source/scwx/qt/model/alert_model.cpp +++ b/scwx-qt/source/scwx/qt/model/alert_model.cpp @@ -21,18 +21,10 @@ namespace model static const std::string logPrefix_ = "scwx::qt::model::alert_model"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); -static constexpr size_t kColumnEtn = 0u; -static constexpr size_t kColumnOfficeId = 1u; -static constexpr size_t kColumnPhenomenon = 2u; -static constexpr size_t kColumnSignificance = 3u; -static constexpr size_t kColumnState = 4u; -static constexpr size_t kColumnCounties = 5u; -static constexpr size_t kColumnStartTime = 6u; -static constexpr size_t kColumnEndTime = 7u; -static constexpr size_t kColumnDistance = 8u; -static constexpr size_t kFirstColumn = kColumnEtn; -static constexpr size_t kLastColumn = kColumnDistance; -static constexpr size_t kNumColumns = 9u; +static constexpr int kFirstColumn = static_cast(AlertModel::Column::Etn); +static constexpr int kLastColumn = + static_cast(AlertModel::Column::Distance); +static const int kNumColumns = 9; class AlertModelImpl { @@ -42,8 +34,10 @@ public: static std::string GetCounties(const types::TextEventKey& key); static std::string GetState(const types::TextEventKey& key); - static std::string GetStartTime(const types::TextEventKey& key); - static std::string GetEndTime(const types::TextEventKey& key); + static std::string GetStartTimeString(const types::TextEventKey& key); + static std::chrono::system_clock::time_point + GetEndTime(const types::TextEventKey& key); + static std::string GetEndTimeString(const types::TextEventKey& key); std::shared_ptr textEventManager_; @@ -95,7 +89,7 @@ int AlertModel::rowCount(const QModelIndex& parent) const int AlertModel::columnCount(const QModelIndex& parent) const { - return parent.isValid() ? 0 : static_cast(kNumColumns); + return parent.isValid() ? 0 : kNumColumns; } QVariant AlertModel::data(const QModelIndex& index, int role) const @@ -108,28 +102,44 @@ QVariant AlertModel::data(const QModelIndex& index, int role) const switch (index.column()) { - case kColumnEtn: + case static_cast(Column::Etn): return textEventKey.etn_; - case kColumnOfficeId: + + case static_cast(Column::OfficeId): return QString::fromStdString(textEventKey.officeId_); - case kColumnPhenomenon: + + case static_cast(Column::Phenomenon): return QString::fromStdString( awips::GetPhenomenonText(textEventKey.phenomenon_)); - case kColumnSignificance: + + case static_cast(Column::Significance): return QString::fromStdString( awips::GetSignificanceText(textEventKey.significance_)); - case kColumnState: + + case static_cast(Column::State): return QString::fromStdString(AlertModelImpl::GetState(textEventKey)); - case kColumnCounties: + + case static_cast(Column::Counties): return QString::fromStdString( AlertModelImpl::GetCounties(textEventKey)); - case kColumnStartTime: + + case static_cast(Column::StartTime): return QString::fromStdString( - AlertModelImpl::GetStartTime(textEventKey)); - case kColumnEndTime: - return QString::fromStdString( - AlertModelImpl::GetEndTime(textEventKey)); - case kColumnDistance: + AlertModelImpl::GetStartTimeString(textEventKey)); + + case static_cast(Column::EndTime): + if (role == Qt::DisplayRole) + { + return QString::fromStdString( + AlertModelImpl::GetEndTimeString(textEventKey)); + } + else + { + return QVariant::fromValue( + AlertModelImpl::GetEndTime(textEventKey)); + } + + case static_cast(Column::Distance): if (role == Qt::DisplayRole) { if (p->distanceDisplay_ == scwx::common::DistanceType::Miles) @@ -149,6 +159,7 @@ QVariant AlertModel::data(const QModelIndex& index, int role) const { return p->distanceMap_.at(textEventKey); } + default: break; } @@ -166,24 +177,33 @@ AlertModel::headerData(int section, Qt::Orientation orientation, int role) const { switch (section) { - case kColumnEtn: + case static_cast(Column::Etn): return tr("ETN"); - case kColumnOfficeId: + + case static_cast(Column::OfficeId): return tr("Office ID"); - case kColumnPhenomenon: + + case static_cast(Column::Phenomenon): return tr("Phenomenon"); - case kColumnSignificance: + + case static_cast(Column::Significance): return tr("Significance"); - case kColumnState: + + case static_cast(Column::State): return tr("State"); - case kColumnCounties: + + case static_cast(Column::Counties): return tr("Counties / Areas"); - case kColumnStartTime: + + case static_cast(Column::StartTime): return tr("Start Time"); - case kColumnEndTime: + + case static_cast(Column::EndTime): return tr("End Time"); - case kColumnDistance: + + case static_cast(Column::Distance): return tr("Distance"); + default: break; } @@ -267,8 +287,9 @@ void AlertModel::HandleMapUpdate(double latitude, double longitude) p->previousPosition_ = {latitude, longitude}; - QModelIndex topLeft = createIndex(0, kColumnDistance); - QModelIndex bottomRight = createIndex(rowCount() - 1, kColumnDistance); + QModelIndex topLeft = createIndex(0, static_cast(Column::Distance)); + QModelIndex bottomRight = + createIndex(rowCount() - 1, static_cast(Column::Distance)); emit dataChanged(topLeft, bottomRight); } @@ -312,7 +333,7 @@ std::string AlertModelImpl::GetState(const types::TextEventKey& key) return util::ToString(lastSegment->header_->ugc_.states()); } -std::string AlertModelImpl::GetStartTime(const types::TextEventKey& key) +std::string AlertModelImpl::GetStartTimeString(const types::TextEventKey& key) { auto messageList = manager::TextEventManager::Instance()->message_list(key); auto& firstMessage = messageList.front(); @@ -321,14 +342,19 @@ std::string AlertModelImpl::GetStartTime(const types::TextEventKey& key) firstSegment->header_->vtecString_[0].pVtec_.event_begin()); } -std::string AlertModelImpl::GetEndTime(const types::TextEventKey& key) +std::chrono::system_clock::time_point +AlertModelImpl::GetEndTime(const types::TextEventKey& key) { auto messageList = manager::TextEventManager::Instance()->message_list(key); auto& lastMessage = messageList.back(); size_t segmentCount = lastMessage->segment_count(); auto lastSegment = lastMessage->segment(segmentCount - 1); - return util::TimeString( - lastSegment->header_->vtecString_[0].pVtec_.event_end()); + return lastSegment->header_->vtecString_[0].pVtec_.event_end(); +} + +std::string AlertModelImpl::GetEndTimeString(const types::TextEventKey& key) +{ + return util::TimeString(GetEndTime(key)); } } // namespace model diff --git a/scwx-qt/source/scwx/qt/model/alert_model.hpp b/scwx-qt/source/scwx/qt/model/alert_model.hpp index d15de462..52fd5e1a 100644 --- a/scwx-qt/source/scwx/qt/model/alert_model.hpp +++ b/scwx-qt/source/scwx/qt/model/alert_model.hpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -19,6 +20,20 @@ class AlertModelImpl; class AlertModel : public QAbstractTableModel { public: + enum class Column : int + { + Etn = 0, + OfficeId = 1, + Phenomenon = 2, + Significance = 3, + State = 4, + Counties = 5, + StartTime = 6, + EndTime = 7, + Distance = 8 + }; + typedef util::Iterator ColumnIterator; + explicit AlertModel(QObject* parent = nullptr); ~AlertModel(); diff --git a/scwx-qt/source/scwx/qt/model/alert_proxy_model.cpp b/scwx-qt/source/scwx/qt/model/alert_proxy_model.cpp new file mode 100644 index 00000000..b04c21a2 --- /dev/null +++ b/scwx-qt/source/scwx/qt/model/alert_proxy_model.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace model +{ + +static const std::string logPrefix_ = "scwx::qt::model::alert_proxy_model"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +class AlertProxyModelImpl +{ +public: + explicit AlertProxyModelImpl(); + ~AlertProxyModelImpl() = default; + + bool alertActiveFilterEnabled_; +}; + +AlertProxyModel::AlertProxyModel(QObject* parent) : + QSortFilterProxyModel(parent), p(std::make_unique()) +{ +} +AlertProxyModel::~AlertProxyModel() = default; + +void AlertProxyModel::SetAlertActiveFilter(bool enabled) +{ + p->alertActiveFilterEnabled_ = enabled; + invalidateRowsFilter(); +} + +bool AlertProxyModel::filterAcceptsRow(int sourceRow, + const QModelIndex& sourceParent) const +{ + bool acceptAlertActiveFilter = true; + + if (p->alertActiveFilterEnabled_) + { + // Get source model index + QModelIndex endTimeIndex = + sourceModel()->index(sourceRow, + static_cast(AlertModel::Column::EndTime), + sourceParent); + + // Get source end time + auto endTime = sourceModel() + ->data(endTimeIndex, qt::types::SortRole) + .value(); + + // Compare end time to current + if (endTime < std::chrono::system_clock::now()) + { + acceptAlertActiveFilter = false; + } + } + + return acceptAlertActiveFilter && + QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); +} + +AlertProxyModelImpl::AlertProxyModelImpl() : alertActiveFilterEnabled_ {false} +{ +} + +} // namespace model +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/model/alert_proxy_model.hpp b/scwx-qt/source/scwx/qt/model/alert_proxy_model.hpp new file mode 100644 index 00000000..ee8b81c1 --- /dev/null +++ b/scwx-qt/source/scwx/qt/model/alert_proxy_model.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace model +{ + +class AlertProxyModelImpl; + +class AlertProxyModel : public QSortFilterProxyModel +{ +private: + Q_DISABLE_COPY(AlertProxyModel) + +public: + explicit AlertProxyModel(QObject* parent = nullptr); + ~AlertProxyModel(); + + void SetAlertActiveFilter(bool enabled); + + bool filterAcceptsRow(int sourceRow, + const QModelIndex& sourceParent) const override; + +private: + std::unique_ptr p; + + friend class AlertProxyModelImpl; +}; + +} // namespace model +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/alert_dock_widget.cpp b/scwx-qt/source/scwx/qt/ui/alert_dock_widget.cpp index 1b5370db..23d47767 100644 --- a/scwx-qt/source/scwx/qt/ui/alert_dock_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/alert_dock_widget.cpp @@ -3,12 +3,11 @@ #include #include +#include #include #include #include -#include - namespace scwx { namespace qt @@ -27,7 +26,7 @@ public: self_ {self}, textEventManager_ {manager::TextEventManager::Instance()}, alertModel_ {std::make_unique()}, - proxyModel_ {std::make_unique()}, + proxyModel_ {std::make_unique()}, alertDialog_ {new AlertDialog(self)}, mapPosition_ {}, mapUpdateDeferred_ {false}, @@ -46,7 +45,7 @@ public: AlertDockWidget* self_; std::shared_ptr textEventManager_; std::unique_ptr alertModel_; - std::unique_ptr proxyModel_; + std::unique_ptr proxyModel_; AlertDialog* alertDialog_; @@ -65,6 +64,9 @@ AlertDockWidget::AlertDockWidget(QWidget* parent) : ui->setupUi(this); ui->alertView->setModel(p->proxyModel_.get()); + ui->alertView->header()->setSortIndicator( + static_cast(model::AlertModel::Column::Distance), + Qt::AscendingOrder); ui->alertSettings->addAction(ui->actionActiveAlerts); @@ -72,6 +74,9 @@ AlertDockWidget::AlertDockWidget(QWidget* parent) : ui->alertGoButton->setEnabled(false); p->ConnectSignals(); + + // Check Active Alerts and trigger signal + ui->actionActiveAlerts->trigger(); } AlertDockWidget::~AlertDockWidget() @@ -111,6 +116,10 @@ void AlertDockWidgetImpl::ConnectSignals() &QLineEdit::textChanged, proxyModel_.get(), &QSortFilterProxyModel::setFilterWildcard); + connect(self_->ui->actionActiveAlerts, + &QAction::triggered, + proxyModel_.get(), + &model::AlertProxyModel::SetAlertActiveFilter); connect(textEventManager_.get(), &manager::TextEventManager::AlertUpdated, alertModel_.get(),