From 31b6120e60958acfc86112af4e6d161547f20b2a Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Mon, 12 Nov 2018 02:11:58 +0000 Subject: [PATCH] Add a Cabrillo contest log model --- CMakeLists.txt | 1 + models/CabrilloLog.cpp | 134 +++++++++++++++++++++++++++++++++++++++++ models/CabrilloLog.hpp | 37 ++++++++++++ models/models.pri | 8 ++- 4 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 models/CabrilloLog.cpp create mode 100644 models/CabrilloLog.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 24de4aebc..2d626fb6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -268,6 +268,7 @@ set (wsjt_qt_CXXSRCS widgets/FoxLogWindow.cpp item_delegates/CallsignDelegate.cpp item_delegates/MaidenheadLocatorDelegate.cpp + models/CabrilloLog.cpp ) set (wsjt_qtmm_CXXSRCS diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp new file mode 100644 index 000000000..7eb820fee --- /dev/null +++ b/models/CabrilloLog.cpp @@ -0,0 +1,134 @@ +#include "CabrilloLog.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Configuration.hpp" +#include "Bands.hpp" +#include "qt_db_helpers.hpp" +#include "pimpl_impl.hpp" + +class CabrilloLog::impl final + : public QSqlTableModel +{ +public: + impl (Configuration const *); + + Configuration const * configuration_; + QSqlQuery mutable dupe_query_; + QSqlQuery mutable export_query_; +}; + +CabrilloLog::impl::impl (Configuration const * configuration) + : QSqlTableModel {} + , configuration_ {configuration} +{ + if (!database ().tables ().contains ("cabrillo_log")) + { + QSqlQuery query; + SQL_error_check (query, static_cast (&QSqlQuery::exec), + "CREATE TABLE cabrillo_log (" + " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + " frequency INTEGER NOT NULL," + " \"when\" DATETIME NOT NULL," + " call VARCHAR(20) NOT NULL," + " exchange_sent VARCHAR(32) NOT NULL," + " exchange_rcvd VARCHAR(32) NOT NULL," + " band VARCHAR(6) NOT NULL" + ")"); + } + + SQL_error_check (dupe_query_, &QSqlQuery::prepare, + "SELECT COUNT(*) FROM cabrillo_log WHERE call = :call AND band = :band"); + + SQL_error_check (export_query_, &QSqlQuery::prepare, + "SELECT frequency, \"when\", exchange_sent, call, exchange_rcvd FROM cabrillo_log ORDER BY \"when\""); + + setEditStrategy (QSqlTableModel::OnManualSubmit); + setTable ("cabrillo_log"); + setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Frequency")); + setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date and Time")); + setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call")); + setHeaderData (fieldIndex ("exchange_sent"), Qt::Horizontal, tr ("Sent")); + setHeaderData (fieldIndex ("exchange_rcvd"), Qt::Horizontal, tr ("Rcvd")); + setHeaderData (fieldIndex ("band"), Qt::Horizontal, tr ("Band")); + SQL_error_check (*this, &QSqlTableModel::select); +} + +CabrilloLog::CabrilloLog (Configuration const * configuration) + : m_ {configuration} +{ + Q_ASSERT (configuration); +} + +CabrilloLog::~CabrilloLog () +{ +} + +QAbstractItemModel * CabrilloLog::model () +{ + return &*m_; +} + +void CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call + , QString const& exchange_sent, QString const& exchange_received) +{ + ConditionalTransaction transaction {*m_}; + auto record = m_->record (); + record.setValue ("frequency", frequency / 1000ull); // kHz + record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull); + record.setValue ("call", call); + record.setValue ("exchange_sent", exchange_sent); + record.setValue ("exchange_rcvd", exchange_received); + record.setValue ("band", m_->configuration_->bands ()->find (frequency)); + SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record); + transaction.submit (); +} + +bool CabrilloLog::dupe (Frequency frequency, QString const& call) const +{ + m_->dupe_query_.bindValue (":call", call); + m_->dupe_query_.bindValue (":band", m_->configuration_->bands ()->find (frequency)); + SQL_error_check (m_->dupe_query_, static_cast (&QSqlQuery::exec)); + m_->dupe_query_.next (); + return m_->dupe_query_.value (0).toInt (); +} + +void CabrilloLog::reset () +{ + ConditionalTransaction transaction {*m_}; + SQL_error_check (*m_, &QSqlTableModel::removeRows, 0, m_->rowCount (), QModelIndex {}); + transaction.submit (); +} + +void CabrilloLog::export_qsos (QTextStream& stream) const +{ + SQL_error_check (m_->export_query_, static_cast (&QSqlQuery::exec)); + auto record = m_->export_query_.record (); + auto frequency_index = record.indexOf ("frequency"); + auto when_index = record.indexOf ("when"); + auto call_index = record.indexOf ("call"); + auto sent_index = record.indexOf ("exchange_sent"); + auto rcvd_index = record.indexOf ("exchange_rcvd"); + while (m_->export_query_.next ()) + { + auto frequency = m_->export_query_.value (frequency_index).value (); + auto my_call = m_->configuration_->my_callsign (); + frequency = frequency > 50000000ull ? frequency / 1000ull : frequency; + stream << QString {"QSO: %1 DG %2 %3 %4 %5 %6\n"} + .arg (frequency, 5) + .arg (QDateTime::fromMSecsSinceEpoch (m_->export_query_.value (when_index).toULongLong () * 1000ull).toString ("yyyy-MM-dd hhmm")) + .arg (my_call, -12) + .arg (m_->export_query_.value (sent_index).toString (), -13) + .arg (m_->export_query_.value (call_index).toString (), -12) + .arg (m_->export_query_.value (rcvd_index).toString (), -13); + } +} diff --git a/models/CabrilloLog.hpp b/models/CabrilloLog.hpp new file mode 100644 index 000000000..9571adeeb --- /dev/null +++ b/models/CabrilloLog.hpp @@ -0,0 +1,37 @@ +#ifndef CABRILLO_LOG_HPP_ +#define CABRILLO_LOG_HPP_ + +#include +#include "Radio.hpp" +#include "pimpl_h.hpp" + +class Configuration; +class QDateTime; +class QString; +class QAbstractItemModel; +class QTextStream; + +class CabrilloLog final + : private boost::noncopyable +{ +public: + using Frequency = Radio::Frequency; + + explicit CabrilloLog (Configuration const *); + ~CabrilloLog (); + + // returns false if insert fails + void add_QSO (Frequency, QDateTime const&, QString const& call + , QString const& report_sent, QString const& report_received); + bool dupe (Frequency, QString const& call) const; + + QAbstractItemModel * model (); + void reset (); + void export_qsos (QTextStream&) const; + +private: + class impl; + pimpl m_; +}; + +#endif diff --git a/models/models.pri b/models/models.pri index a88948fa7..ae3ea4824 100644 --- a/models/models.pri +++ b/models/models.pri @@ -3,11 +3,15 @@ SOURCES += \ models/FrequencyList.cpp \ models/StationList.cpp \ models/Modes.cpp \ - models/IARURegions.cpp + models/IARURegions.cpp \ + models/FoxLog.cpp \ + models/CabrilloLog.cpp HEADERS += \ models/Bands.hpp \ models/FrequencyList.hpp \ models/StationList.hpp \ models/Modes.hpp \ - models/IARURegions.hpp + models/IARURegions.hpp \ + models/FoxLog.hpp \ + models/CabrilloLog.hpp