From 769ce896e7eb83d9afb97cd0a6eb36930818f6eb Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 8 Dec 2023 05:15:57 -0600 Subject: [PATCH] Add county selection dialog --- scwx-qt/scwx-qt.cmake | 3 + .../source/scwx/qt/config/county_database.cpp | 5 + .../source/scwx/qt/config/county_database.hpp | 1 + scwx-qt/source/scwx/qt/ui/county_dialog.cpp | 175 ++++++++++++++++++ scwx-qt/source/scwx/qt/ui/county_dialog.hpp | 37 ++++ scwx-qt/source/scwx/qt/ui/county_dialog.ui | 104 +++++++++++ 6 files changed, 325 insertions(+) create mode 100644 scwx-qt/source/scwx/qt/ui/county_dialog.cpp create mode 100644 scwx-qt/source/scwx/qt/ui/county_dialog.hpp create mode 100644 scwx-qt/source/scwx/qt/ui/county_dialog.ui diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index b032971e..a5ab11f9 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -203,6 +203,7 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp source/scwx/qt/ui/alert_dock_widget.hpp source/scwx/qt/ui/animation_dock_widget.hpp source/scwx/qt/ui/collapsible_group.hpp + source/scwx/qt/ui/county_dialog.hpp source/scwx/qt/ui/flow_layout.hpp source/scwx/qt/ui/imgui_debug_dialog.hpp source/scwx/qt/ui/imgui_debug_widget.hpp @@ -222,6 +223,7 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp source/scwx/qt/ui/alert_dock_widget.cpp source/scwx/qt/ui/animation_dock_widget.cpp source/scwx/qt/ui/collapsible_group.cpp + source/scwx/qt/ui/county_dialog.cpp source/scwx/qt/ui/flow_layout.cpp source/scwx/qt/ui/imgui_debug_dialog.cpp source/scwx/qt/ui/imgui_debug_widget.cpp @@ -241,6 +243,7 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui source/scwx/qt/ui/alert_dock_widget.ui source/scwx/qt/ui/animation_dock_widget.ui source/scwx/qt/ui/collapsible_group.ui + source/scwx/qt/ui/county_dialog.ui source/scwx/qt/ui/imgui_debug_dialog.ui source/scwx/qt/ui/layer_dialog.ui source/scwx/qt/ui/open_url_dialog.ui diff --git a/scwx-qt/source/scwx/qt/config/county_database.cpp b/scwx-qt/source/scwx/qt/config/county_database.cpp index de968474..106b6911 100644 --- a/scwx-qt/source/scwx/qt/config/county_database.cpp +++ b/scwx-qt/source/scwx/qt/config/county_database.cpp @@ -225,6 +225,11 @@ GetCounties(const std::string& state) return counties; } +const std::unordered_map& GetStates() +{ + return stateMap_; +} + } // namespace CountyDatabase } // namespace config } // namespace qt diff --git a/scwx-qt/source/scwx/qt/config/county_database.hpp b/scwx-qt/source/scwx/qt/config/county_database.hpp index 5cc92d3d..5ee33e11 100644 --- a/scwx-qt/source/scwx/qt/config/county_database.hpp +++ b/scwx-qt/source/scwx/qt/config/county_database.hpp @@ -18,6 +18,7 @@ void Initialize(); std::string GetCountyName(const std::string& id); std::unordered_map GetCounties(const std::string& state); +const std::unordered_map& GetStates(); } // namespace CountyDatabase } // namespace config diff --git a/scwx-qt/source/scwx/qt/ui/county_dialog.cpp b/scwx-qt/source/scwx/qt/ui/county_dialog.cpp new file mode 100644 index 00000000..64c6d574 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/county_dialog.cpp @@ -0,0 +1,175 @@ +#include "county_dialog.hpp" +#include "ui_county_dialog.h" + +#include +#include + +#include +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +static const std::string logPrefix_ = "scwx::qt::ui::county_dialog"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +class CountyDialog::Impl +{ +public: + explicit Impl(CountyDialog* self) : + self_ {self}, + model_ {new QStandardItemModel(self)}, + proxyModel_ {new QSortFilterProxyModel(self)}, + states_ {config::CountyDatabase::GetStates()} + { + } + ~Impl() = default; + + void UpdateModel(const std::string& stateName); + + CountyDialog* self_; + QStandardItemModel* model_; + QSortFilterProxyModel* proxyModel_; + + std::string selectedCounty_ {"?"}; + + const std::unordered_map& states_; +}; + +CountyDialog::CountyDialog(QWidget* parent) : + QDialog(parent), p {std::make_unique(this)}, ui(new Ui::CountyDialog) +{ + ui->setupUi(this); + + for (auto& state : p->states_) + { + ui->stateComboBox->addItem(QString::fromStdString(state.second)); + } + ui->stateComboBox->model()->sort(0); + ui->stateComboBox->setCurrentIndex(0); + + p->proxyModel_->setSourceModel(p->model_); + ui->countyView->setModel(p->proxyModel_); + ui->countyView->setEditTriggers( + QAbstractItemView::EditTrigger::NoEditTriggers); + ui->countyView->sortByColumn(0, Qt::SortOrder::AscendingOrder); + ui->countyView->header()->setSectionResizeMode( + QHeaderView::ResizeMode::Stretch); + + connect(ui->stateComboBox, + &QComboBox::currentTextChanged, + this, + [this](const QString& text) { p->UpdateModel(text.toStdString()); }); + p->UpdateModel(ui->stateComboBox->currentText().toStdString()); + + // Button Box + ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok) + ->setEnabled(false); + + connect(ui->countyView, + &QTreeView::doubleClicked, + this, + [this]() { Q_EMIT accept(); }); + connect( + ui->countyView->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, + [this](const QItemSelection& selected, const QItemSelection& deselected) + { + if (selected.size() == 0 && deselected.size() == 0) + { + // Items which stay selected but change their index are not + // included in selected and deselected. Thus, this signal might + // be emitted with both selected and deselected empty, if only + // the indices of selected items change. + return; + } + + ui->buttonBox->button(QDialogButtonBox::Ok) + ->setEnabled(selected.size() > 0); + + if (selected.size() > 0) + { + QModelIndex selectedIndex = + p->proxyModel_->mapToSource(selected[0].indexes()[0]); + selectedIndex = p->model_->index(selectedIndex.row(), 1); + QVariant variantData = p->model_->data(selectedIndex); + if (variantData.typeId() == QMetaType::QString) + { + p->selectedCounty_ = variantData.toString().toStdString(); + } + else + { + logger_->warn("Unexpected selection data type"); + p->selectedCounty_ = std::string {"?"}; + } + } + else + { + p->selectedCounty_ = std::string {"?"}; + } + + logger_->debug("Selected: {}", p->selectedCounty_); + }); +} + +CountyDialog::~CountyDialog() +{ + delete ui; +} + +std::string CountyDialog::county_fips_id() +{ + return p->selectedCounty_; +} + +void CountyDialog::SelectState(const std::string& state) +{ + auto it = p->states_.find(state); + if (it != p->states_.cend()) + { + ui->stateComboBox->setCurrentText(QString::fromStdString(it->second)); + } +} + +void CountyDialog::Impl::UpdateModel(const std::string& stateName) +{ + // Clear existing counties + model_->clear(); + + // Reset selected county and disable OK button + selectedCounty_ = std::string {"?"}; + self_->ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok) + ->setEnabled(false); + + // Reset headers + model_->setHorizontalHeaderLabels({tr("County / Area"), tr("FIPS ID")}); + + // Find the state ID from the statename + auto it = std::find_if(states_.cbegin(), + states_.cend(), + [&](const std::pair& record) + { return record.second == stateName; }); + + if (it != states_.cend()) + { + QStandardItem* root = model_->invisibleRootItem(); + + // Add each county to the model + for (auto& county : config::CountyDatabase::GetCounties(it->first)) + { + root->appendRow( + {new QStandardItem(QString::fromStdString(county.second)), + new QStandardItem(QString::fromStdString(county.first))}); + } + } +} + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/county_dialog.hpp b/scwx-qt/source/scwx/qt/ui/county_dialog.hpp new file mode 100644 index 00000000..76045c81 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/county_dialog.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace Ui +{ +class CountyDialog; +} + +namespace scwx +{ +namespace qt +{ +namespace ui +{ +class CountyDialog : public QDialog +{ + Q_OBJECT + Q_DISABLE_COPY_MOVE(CountyDialog) + +public: + explicit CountyDialog(QWidget* parent = nullptr); + ~CountyDialog(); + + std::string county_fips_id(); + + void SelectState(const std::string& state); + +private: + class Impl; + std::unique_ptr p; + Ui::CountyDialog* ui; +}; + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/county_dialog.ui b/scwx-qt/source/scwx/qt/ui/county_dialog.ui new file mode 100644 index 00000000..71741c86 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/county_dialog.ui @@ -0,0 +1,104 @@ + + + CountyDialog + + + + 0 + 0 + 400 + 400 + + + + Select County + + + + + + true + + + 0 + + + true + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + buttonBox + accepted() + CountyDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CountyDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +