mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-09-27 07:36:38 -04:00
Merge branch 'hotfix-2.0.1-rc1' of bitbucket.org:k1jt/wsjtx into hotfix-2.0.1-rc1
This commit is contained in:
commit
e018cbf738
@ -162,6 +162,7 @@ option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transient
|
|||||||
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
|
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
|
||||||
option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
||||||
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
|
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
|
||||||
|
option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
|
||||||
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
|
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
|
||||||
|
|
||||||
CMAKE_DEPENDENT_OPTION (WSJT_HAMLIB_VERBOSE_TRACE "Debugging option that turns on full Hamlib internal diagnostics." OFF WSJT_HAMLIB_TRACE OFF)
|
CMAKE_DEPENDENT_OPTION (WSJT_HAMLIB_VERBOSE_TRACE "Debugging option that turns on full Hamlib internal diagnostics." OFF WSJT_HAMLIB_TRACE OFF)
|
||||||
|
@ -1004,13 +1004,11 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
|||||||
// this must be done after the default paths above are set
|
// this must be done after the default paths above are set
|
||||||
read_settings ();
|
read_settings ();
|
||||||
|
|
||||||
// conditionally load LotW users data
|
// set up LoTW users CSV file fetching
|
||||||
ui_->LotW_CSV_fetch_push_button->setEnabled (false);
|
|
||||||
connect (&lotw_users_, &LotWUsers::load_finished, [this] () {
|
connect (&lotw_users_, &LotWUsers::load_finished, [this] () {
|
||||||
ui_->LotW_CSV_fetch_push_button->setEnabled (true);
|
ui_->LotW_CSV_fetch_push_button->setEnabled (true);
|
||||||
});
|
});
|
||||||
lotw_users_.set_local_file_path (writeable_data_dir_.absoluteFilePath ("lotw-user-activity.csv"));
|
lotw_users_.set_local_file_path (writeable_data_dir_.absoluteFilePath ("lotw-user-activity.csv"));
|
||||||
lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text ());
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// validation
|
// validation
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "LotWUsers.hpp"
|
#include "LotWUsers.hpp"
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -265,7 +266,9 @@ void LotWUsers::set_age_constraint (qint64 uploaded_since_days)
|
|||||||
|
|
||||||
bool LotWUsers::user (QString const& call) const
|
bool LotWUsers::user (QString const& call) const
|
||||||
{
|
{
|
||||||
if (m_->future_load_.valid ())
|
// check if a pending asynchronous load is ready
|
||||||
|
if (m_->future_load_.valid ()
|
||||||
|
&& std::future_status::ready == m_->future_load_.wait_for (std::chrono::seconds {0}))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -278,10 +281,13 @@ bool LotWUsers::user (QString const& call) const
|
|||||||
}
|
}
|
||||||
Q_EMIT load_finished ();
|
Q_EMIT load_finished ();
|
||||||
}
|
}
|
||||||
|
if (m_->last_uploaded_.size ())
|
||||||
|
{
|
||||||
auto p = m_->last_uploaded_.constFind (call);
|
auto p = m_->last_uploaded_.constFind (call);
|
||||||
if (p != m_->last_uploaded_.end ())
|
if (p != m_->last_uploaded_.end ())
|
||||||
{
|
{
|
||||||
return p.value ().daysTo (QDate::currentDate ()) <= m_->age_constraint_;
|
return p.value ().daysTo (QDate::currentDate ()) <= m_->age_constraint_;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "NetworkMessage.hpp"
|
#include "NetworkMessage.hpp"
|
||||||
|
|
||||||
@ -18,6 +19,13 @@
|
|||||||
|
|
||||||
#include "moc_MessageClient.cpp"
|
#include "moc_MessageClient.cpp"
|
||||||
|
|
||||||
|
// some trace macros
|
||||||
|
#if WSJT_TRACE_UDP
|
||||||
|
#define TRACE_UDP(MSG) qDebug () << QString {"MessageClient::%1:"}.arg (__func__) << MSG
|
||||||
|
#else
|
||||||
|
#define TRACE_UDP(MSG)
|
||||||
|
#endif
|
||||||
|
|
||||||
class MessageClient::impl
|
class MessageClient::impl
|
||||||
: public QUdpSocket
|
: public QUdpSocket
|
||||||
{
|
{
|
||||||
@ -101,6 +109,7 @@ void MessageClient::impl::host_info_results (QHostInfo host_info)
|
|||||||
if (blocked_addresses_.end () == std::find (blocked_addresses_.begin (), blocked_addresses_.end (), server))
|
if (blocked_addresses_.end () == std::find (blocked_addresses_.begin (), blocked_addresses_.end (), server))
|
||||||
{
|
{
|
||||||
server_ = server;
|
server_ = server;
|
||||||
|
TRACE_UDP ("resulting server:" << server);
|
||||||
|
|
||||||
// send initial heartbeat which allows schema negotiation
|
// send initial heartbeat which allows schema negotiation
|
||||||
heartbeat ();
|
heartbeat ();
|
||||||
@ -129,6 +138,7 @@ void MessageClient::impl::pending_datagrams ()
|
|||||||
port_type sender_port;
|
port_type sender_port;
|
||||||
if (0 <= readDatagram (datagram.data (), datagram.size (), &sender_address, &sender_port))
|
if (0 <= readDatagram (datagram.data (), datagram.size (), &sender_address, &sender_port))
|
||||||
{
|
{
|
||||||
|
TRACE_UDP ("message received from:" << sender_address << "port:" << sender_port);
|
||||||
parse_message (datagram);
|
parse_message (datagram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,6 +178,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
quint8 modifiers {0};
|
quint8 modifiers {0};
|
||||||
in >> time >> snr >> delta_time >> delta_frequency >> mode >> message
|
in >> time >> snr >> delta_time >> delta_frequency >> mode >> message
|
||||||
>> low_confidence >> modifiers;
|
>> low_confidence >> modifiers;
|
||||||
|
TRACE_UDP ("Reply: time:" << time << "snr:" << snr << "dt:" << delta_time << "df:" << delta_frequency << "mode:" << mode << "message:" << message << "low confidence:" << low_confidence << "modifiers: 0x" << hex << modifiers);
|
||||||
if (check_status (in) != Fail)
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->reply (time, snr, delta_time, delta_frequency
|
Q_EMIT self_->reply (time, snr, delta_time, delta_frequency
|
||||||
@ -178,6 +189,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NetworkMessage::Replay:
|
case NetworkMessage::Replay:
|
||||||
|
TRACE_UDP ("Replay");
|
||||||
if (check_status (in) != Fail)
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
last_message_.clear ();
|
last_message_.clear ();
|
||||||
@ -189,6 +201,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
{
|
{
|
||||||
bool auto_only {false};
|
bool auto_only {false};
|
||||||
in >> auto_only;
|
in >> auto_only;
|
||||||
|
TRACE_UDP ("Halt Tx auto_only:" << auto_only);
|
||||||
if (check_status (in) != Fail)
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->halt_tx (auto_only);
|
Q_EMIT self_->halt_tx (auto_only);
|
||||||
@ -201,6 +214,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
QByteArray message;
|
QByteArray message;
|
||||||
bool send {true};
|
bool send {true};
|
||||||
in >> message >> send;
|
in >> message >> send;
|
||||||
|
TRACE_UDP ("FreeText message:" << message << "send:" << send);
|
||||||
if (check_status (in) != Fail)
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->free_text (QString::fromUtf8 (message), send);
|
Q_EMIT self_->free_text (QString::fromUtf8 (message), send);
|
||||||
@ -212,6 +226,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
{
|
{
|
||||||
QByteArray location;
|
QByteArray location;
|
||||||
in >> location;
|
in >> location;
|
||||||
|
TRACE_UDP ("Location location:" << location);
|
||||||
if (check_status (in) != Fail)
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->location (QString::fromUtf8 (location));
|
Q_EMIT self_->location (QString::fromUtf8 (location));
|
||||||
@ -226,6 +241,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
QColor fg; // default invalid color
|
QColor fg; // default invalid color
|
||||||
bool last_only {false};
|
bool last_only {false};
|
||||||
in >> call >> bg >> fg >> last_only;
|
in >> call >> bg >> fg >> last_only;
|
||||||
|
TRACE_UDP ("HighlightCallsign call:" << call << "bg:" << bg << "fg:" << fg);
|
||||||
if (check_status (in) != Fail && call.size ())
|
if (check_status (in) != Fail && call.size ())
|
||||||
{
|
{
|
||||||
Q_EMIT self_->highlight_callsign (QString::fromUtf8 (call), bg, fg, last_only);
|
Q_EMIT self_->highlight_callsign (QString::fromUtf8 (call), bg, fg, last_only);
|
||||||
@ -240,9 +256,17 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
// parsed here they are still partially parsed in the
|
// parsed here they are still partially parsed in the
|
||||||
// message reader class to negotiate the maximum schema
|
// message reader class to negotiate the maximum schema
|
||||||
// number being used on the network.
|
// number being used on the network.
|
||||||
|
if (NetworkMessage::Heartbeat != in.type ())
|
||||||
|
{
|
||||||
|
TRACE_UDP ("ignoring message type:" << in.type ());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACE_UDP ("ignored message for id:" << in.id ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception const& e)
|
catch (std::exception const& e)
|
||||||
{
|
{
|
||||||
@ -264,6 +288,7 @@ void MessageClient::impl::heartbeat ()
|
|||||||
<< version_.toUtf8 () << revision_.toUtf8 ();
|
<< version_.toUtf8 () << revision_.toUtf8 ();
|
||||||
if (OK == check_status (hb))
|
if (OK == check_status (hb))
|
||||||
{
|
{
|
||||||
|
TRACE_UDP ("schema:" << schema_ << "max schema:" << NetworkMessage::Builder::schema_number << "version:" << version_ << "revision:" << revision_);
|
||||||
writeDatagram (message, server_, server_port_);
|
writeDatagram (message, server_, server_port_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,6 +302,7 @@ void MessageClient::impl::closedown ()
|
|||||||
NetworkMessage::Builder out {&message, NetworkMessage::Close, id_, schema_};
|
NetworkMessage::Builder out {&message, NetworkMessage::Close, id_, schema_};
|
||||||
if (OK == check_status (out))
|
if (OK == check_status (out))
|
||||||
{
|
{
|
||||||
|
TRACE_UDP ("");
|
||||||
writeDatagram (message, server_, server_port_);
|
writeDatagram (message, server_, server_port_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,6 +395,7 @@ void MessageClient::set_server (QString const& server)
|
|||||||
if (!server.isEmpty ())
|
if (!server.isEmpty ())
|
||||||
{
|
{
|
||||||
// queue a host address lookup
|
// queue a host address lookup
|
||||||
|
TRACE_UDP ("server host DNS lookup:" << server);
|
||||||
QHostInfo::lookupHost (server, &*m_, SLOT (host_info_results (QHostInfo)));
|
QHostInfo::lookupHost (server, &*m_, SLOT (host_info_results (QHostInfo)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,6 +442,7 @@ void MessageClient::status_update (Frequency f, QString const& mode, QString con
|
|||||||
<< tx_enabled << transmitting << decoding << rx_df << tx_df << de_call.toUtf8 ()
|
<< tx_enabled << transmitting << decoding << rx_df << tx_df << de_call.toUtf8 ()
|
||||||
<< de_grid.toUtf8 () << dx_grid.toUtf8 () << watchdog_timeout << sub_mode.toUtf8 ()
|
<< de_grid.toUtf8 () << dx_grid.toUtf8 () << watchdog_timeout << sub_mode.toUtf8 ()
|
||||||
<< fast_mode << special_op_mode;
|
<< fast_mode << special_op_mode;
|
||||||
|
TRACE_UDP ("frequency:" << f << "mode:" << mode << "DX:" << dx_call << "report:" << report << "Tx mode:" << tx_mode << "tx_enabled:" << tx_enabled << "Tx:" << transmitting << "decoding:" << decoding << "Rx df:" << rx_df << "Tx df:" << tx_df << "DE:" << de_call << "DE grid:" << de_grid << "DX grid:" << dx_grid << "w/d t/o:" << watchdog_timeout << "sub_mode:" << sub_mode << "fast mode:" << fast_mode << "spec op mode:" << special_op_mode);
|
||||||
m_->send_message (out, message);
|
m_->send_message (out, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,6 +457,7 @@ void MessageClient::decode (bool is_new, QTime time, qint32 snr, float delta_tim
|
|||||||
NetworkMessage::Builder out {&message, NetworkMessage::Decode, m_->id_, m_->schema_};
|
NetworkMessage::Builder out {&message, NetworkMessage::Decode, m_->id_, m_->schema_};
|
||||||
out << is_new << time << snr << delta_time << delta_frequency << mode.toUtf8 ()
|
out << is_new << time << snr << delta_time << delta_frequency << mode.toUtf8 ()
|
||||||
<< message_text.toUtf8 () << low_confidence << off_air;
|
<< message_text.toUtf8 () << low_confidence << off_air;
|
||||||
|
TRACE_UDP ("new" << is_new << "time:" << time << "snr:" << snr << "dt:" << delta_time << "df:" << delta_frequency << "mode:" << mode << "text:" << message_text << "low conf:" << low_confidence << "off air:" << off_air);
|
||||||
m_->send_message (out, message);
|
m_->send_message (out, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -443,6 +472,7 @@ void MessageClient::WSPR_decode (bool is_new, QTime time, qint32 snr, float delt
|
|||||||
NetworkMessage::Builder out {&message, NetworkMessage::WSPRDecode, m_->id_, m_->schema_};
|
NetworkMessage::Builder out {&message, NetworkMessage::WSPRDecode, m_->id_, m_->schema_};
|
||||||
out << is_new << time << snr << delta_time << frequency << drift << callsign.toUtf8 ()
|
out << is_new << time << snr << delta_time << frequency << drift << callsign.toUtf8 ()
|
||||||
<< grid.toUtf8 () << power << off_air;
|
<< grid.toUtf8 () << power << off_air;
|
||||||
|
TRACE_UDP ("new:" << is_new << "time:" << time << "snr:" << snr << "dt:" << delta_time << "frequency:" << frequency << "drift:" << drift << "call:" << callsign << "grid:" << grid << "pwr:" << power << "off air:" << off_air);
|
||||||
m_->send_message (out, message);
|
m_->send_message (out, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,6 +483,7 @@ void MessageClient::clear_decodes ()
|
|||||||
{
|
{
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder out {&message, NetworkMessage::Clear, m_->id_, m_->schema_};
|
NetworkMessage::Builder out {&message, NetworkMessage::Clear, m_->id_, m_->schema_};
|
||||||
|
TRACE_UDP ("");
|
||||||
m_->send_message (out, message);
|
m_->send_message (out, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,6 +504,7 @@ void MessageClient::qso_logged (QDateTime time_off, QString const& dx_call, QStr
|
|||||||
<< report_sent.toUtf8 () << report_received.toUtf8 () << tx_power.toUtf8 () << comments.toUtf8 ()
|
<< report_sent.toUtf8 () << report_received.toUtf8 () << tx_power.toUtf8 () << comments.toUtf8 ()
|
||||||
<< name.toUtf8 () << time_on << operator_call.toUtf8 () << my_call.toUtf8 () << my_grid.toUtf8 ()
|
<< name.toUtf8 () << time_on << operator_call.toUtf8 () << my_call.toUtf8 () << my_grid.toUtf8 ()
|
||||||
<< exchange_sent.toUtf8 () << exchange_rcvd.toUtf8 ();
|
<< exchange_sent.toUtf8 () << exchange_rcvd.toUtf8 ();
|
||||||
|
TRACE_UDP ("time off:" << time_off << "DX:" << dx_call << "DX grid:" << dx_grid << "dial:" << dial_frequency << "mode:" << mode << "sent:" << report_sent << "rcvd:" << report_received << "pwr:" << tx_power << "comments:" << comments << "name:" << name << "time on:" << time_on << "op:" << operator_call << "DE:" << my_call << "DE grid:" << my_grid << "exch sent:" << exchange_sent << "exch rcvd:" << exchange_rcvd);
|
||||||
m_->send_message (out, message);
|
m_->send_message (out, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,6 +517,7 @@ void MessageClient::logged_ADIF (QByteArray const& ADIF_record)
|
|||||||
NetworkMessage::Builder out {&message, NetworkMessage::LoggedADIF, m_->id_, m_->schema_};
|
NetworkMessage::Builder out {&message, NetworkMessage::LoggedADIF, m_->id_, m_->schema_};
|
||||||
QByteArray ADIF {"\n<adif_ver:5>3.0.7\n<programid:6>WSJT-X\n<EOH>\n" + ADIF_record + " <EOR>"};
|
QByteArray ADIF {"\n<adif_ver:5>3.0.7\n<programid:6>WSJT-X\n<EOH>\n" + ADIF_record + " <EOR>"};
|
||||||
out << ADIF;
|
out << ADIF;
|
||||||
|
TRACE_UDP ("ADIF:" << ADIF);
|
||||||
m_->send_message (out, message);
|
m_->send_message (out, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,9 @@
|
|||||||
#include <QSqlRecord>
|
#include <QSqlRecord>
|
||||||
#include <QSqlError>
|
#include <QSqlError>
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
|
#include <QTextStream>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include "Configuration.hpp"
|
||||||
#include "qt_db_helpers.hpp"
|
#include "qt_db_helpers.hpp"
|
||||||
#include "pimpl_impl.hpp"
|
#include "pimpl_impl.hpp"
|
||||||
|
|
||||||
@ -17,12 +19,15 @@ class FoxLog::impl final
|
|||||||
: public QSqlTableModel
|
: public QSqlTableModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
impl ();
|
impl (Configuration const * configuration);
|
||||||
|
|
||||||
|
Configuration const * configuration_;
|
||||||
QSqlQuery mutable dupe_query_;
|
QSqlQuery mutable dupe_query_;
|
||||||
|
QSqlQuery mutable export_query_;
|
||||||
};
|
};
|
||||||
|
|
||||||
FoxLog::impl::impl ()
|
FoxLog::impl::impl (Configuration const * configuration)
|
||||||
|
: configuration_ {configuration}
|
||||||
{
|
{
|
||||||
if (!database ().tables ().contains ("fox_log"))
|
if (!database ().tables ().contains ("fox_log"))
|
||||||
{
|
{
|
||||||
@ -43,6 +48,9 @@ FoxLog::impl::impl ()
|
|||||||
SQL_error_check (dupe_query_, &QSqlQuery::prepare,
|
SQL_error_check (dupe_query_, &QSqlQuery::prepare,
|
||||||
"SELECT COUNT(*) FROM fox_log WHERE call = :call AND band = :band");
|
"SELECT COUNT(*) FROM fox_log WHERE call = :call AND band = :band");
|
||||||
|
|
||||||
|
SQL_error_check (export_query_, &QSqlQuery::prepare,
|
||||||
|
"SELECT band, \"when\", call, grid, report_sent, report_rcvd FROM fox_log ORDER BY \"when\"");
|
||||||
|
|
||||||
setEditStrategy (QSqlTableModel::OnFieldChange);
|
setEditStrategy (QSqlTableModel::OnFieldChange);
|
||||||
setTable ("fox_log");
|
setTable ("fox_log");
|
||||||
setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)"));
|
setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)"));
|
||||||
@ -60,7 +68,8 @@ FoxLog::impl::impl ()
|
|||||||
SQL_error_check (*this, &QSqlTableModel::select);
|
SQL_error_check (*this, &QSqlTableModel::select);
|
||||||
}
|
}
|
||||||
|
|
||||||
FoxLog::FoxLog ()
|
FoxLog::FoxLog (Configuration const * configuration)
|
||||||
|
: m_ {configuration}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,3 +151,59 @@ void FoxLog::reset ()
|
|||||||
m_->setEditStrategy (QSqlTableModel::OnFieldChange);
|
m_->setEditStrategy (QSqlTableModel::OnFieldChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct ADIF_field
|
||||||
|
{
|
||||||
|
explicit ADIF_field (QString const& name, QString const& value)
|
||||||
|
: name_ {name}
|
||||||
|
, value_ {value}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString name_;
|
||||||
|
QString value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
QTextStream& operator << (QTextStream& os, ADIF_field const& field)
|
||||||
|
{
|
||||||
|
if (field.value_.size ())
|
||||||
|
{
|
||||||
|
os << QString {"<%1:%2>%3 "}.arg (field.name_).arg (field.value_.size ()).arg (field.value_);
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FoxLog::export_qsos (QTextStream& out) const
|
||||||
|
{
|
||||||
|
out << "WSJT-X FT8 DXpedition Mode Fox Log\n<eoh>";
|
||||||
|
|
||||||
|
SQL_error_check (m_->export_query_, static_cast<bool (QSqlQuery::*) ()> (&QSqlQuery::exec));
|
||||||
|
auto record = m_->export_query_.record ();
|
||||||
|
auto band_index = record.indexOf ("band");
|
||||||
|
auto when_index = record.indexOf ("when");
|
||||||
|
auto call_index = record.indexOf ("call");
|
||||||
|
auto grid_index = record.indexOf ("grid");
|
||||||
|
auto sent_index = record.indexOf ("report_sent");
|
||||||
|
auto rcvd_index = record.indexOf ("report_rcvd");
|
||||||
|
while (m_->export_query_.next ())
|
||||||
|
{
|
||||||
|
auto when = QDateTime::fromMSecsSinceEpoch (m_->export_query_.value (when_index).toULongLong () * 1000ull, Qt::UTC);
|
||||||
|
out << '\n'
|
||||||
|
<< ADIF_field {"band", m_->export_query_.value (band_index).toString ()}
|
||||||
|
<< ADIF_field {"mode", "FT8"}
|
||||||
|
<< ADIF_field {"qso_date", when.toString ("yyyyMMdd")}
|
||||||
|
<< ADIF_field {"time_on", when.toString ("hhmmss")}
|
||||||
|
<< ADIF_field {"call", m_->export_query_.value (call_index).toString ()}
|
||||||
|
<< ADIF_field {"gridsquare", m_->export_query_.value (grid_index).toString ()}
|
||||||
|
<< ADIF_field {"rst_sent", m_->export_query_.value (sent_index).toString ()}
|
||||||
|
<< ADIF_field {"rst_rcvd", m_->export_query_.value (rcvd_index).toString ()}
|
||||||
|
<< ADIF_field {"station_callsign", m_->configuration_->my_callsign ()}
|
||||||
|
<< ADIF_field {"my_gridsquare", m_->configuration_->my_grid ()}
|
||||||
|
<< ADIF_field {"operator", m_->configuration_->opCall ()}
|
||||||
|
<< "<eor>";
|
||||||
|
}
|
||||||
|
out << endl;
|
||||||
|
}
|
||||||
|
@ -7,12 +7,14 @@
|
|||||||
class QDateTime;
|
class QDateTime;
|
||||||
class QString;
|
class QString;
|
||||||
class QSqlTableModel;
|
class QSqlTableModel;
|
||||||
|
class QTextStream;
|
||||||
|
class Configuration;
|
||||||
|
|
||||||
class FoxLog final
|
class FoxLog final
|
||||||
: private boost::noncopyable
|
: private boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit FoxLog ();
|
explicit FoxLog (Configuration const *);
|
||||||
~FoxLog ();
|
~FoxLog ();
|
||||||
|
|
||||||
// returns false if insert fails, dupe call+band
|
// returns false if insert fails, dupe call+band
|
||||||
@ -23,6 +25,7 @@ public:
|
|||||||
|
|
||||||
QSqlTableModel * model ();
|
QSqlTableModel * model ();
|
||||||
void reset ();
|
void reset ();
|
||||||
|
void export_qsos (QTextStream&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
#include "FoxLogWindow.hpp"
|
#include "FoxLogWindow.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QSqlTableModel>
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QSqlTableModel>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
#include "SettingsGroup.hpp"
|
#include "SettingsGroup.hpp"
|
||||||
#include "Configuration.hpp"
|
#include "Configuration.hpp"
|
||||||
#include "MessageBox.hpp"
|
#include "MessageBox.hpp"
|
||||||
#include "models/Bands.hpp"
|
#include "models/Bands.hpp"
|
||||||
|
#include "models/FoxLog.hpp"
|
||||||
#include "item_delegates/ForeignKeyDelegate.hpp"
|
#include "item_delegates/ForeignKeyDelegate.hpp"
|
||||||
#include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp"
|
#include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp"
|
||||||
#include "item_delegates/CallsignDelegate.hpp"
|
#include "item_delegates/CallsignDelegate.hpp"
|
||||||
@ -22,23 +24,23 @@
|
|||||||
class FoxLogWindow::impl final
|
class FoxLogWindow::impl final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit impl (QSqlTableModel * log_model)
|
explicit impl (FoxLog * log)
|
||||||
: log_model_ {log_model}
|
: log_ {log}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QSqlTableModel * log_model_;
|
FoxLog * log_;
|
||||||
Ui::FoxLogWindow ui_;
|
Ui::FoxLogWindow ui_;
|
||||||
};
|
};
|
||||||
|
|
||||||
FoxLogWindow::FoxLogWindow (QSettings * settings, Configuration const * configuration
|
FoxLogWindow::FoxLogWindow (QSettings * settings, Configuration const * configuration
|
||||||
, QSqlTableModel * fox_log_model, QWidget * parent)
|
, FoxLog * fox_log, QWidget * parent)
|
||||||
: AbstractLogWindow {"Fox Log Window", settings, configuration, parent}
|
: AbstractLogWindow {"Fox Log Window", settings, configuration, parent}
|
||||||
, m_ {fox_log_model}
|
, m_ {fox_log}
|
||||||
{
|
{
|
||||||
setWindowTitle (QApplication::applicationName () + " - Fox Log");
|
setWindowTitle (QApplication::applicationName () + " - Fox Log");
|
||||||
m_->ui_.setupUi (this);
|
m_->ui_.setupUi (this);
|
||||||
m_->ui_.log_table_view->setModel (m_->log_model_);
|
m_->ui_.log_table_view->setModel (m_->log_->model ());
|
||||||
set_log_view (m_->ui_.log_table_view);
|
set_log_view (m_->ui_.log_table_view);
|
||||||
m_->ui_.log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this});
|
m_->ui_.log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this});
|
||||||
m_->ui_.log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this});
|
m_->ui_.log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this});
|
||||||
@ -50,6 +52,31 @@ FoxLogWindow::FoxLogWindow (QSettings * settings, Configuration const * configur
|
|||||||
m_->ui_.callers_label->setNum (0);
|
m_->ui_.callers_label->setNum (0);
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
|
auto export_action = new QAction {tr ("&Export ADIF ..."), m_->ui_.log_table_view};
|
||||||
|
m_->ui_.log_table_view->insertAction (nullptr, export_action);
|
||||||
|
connect (export_action, &QAction::triggered, [this, configuration] (bool /*checked*/) {
|
||||||
|
auto file_name = QFileDialog::getSaveFileName (this
|
||||||
|
, tr ("Export ADIF Log File")
|
||||||
|
, configuration->writeable_data_dir ().absolutePath ()
|
||||||
|
, tr ("ADIF Log (*.adi)"));
|
||||||
|
if (file_name.size () && m_->log_)
|
||||||
|
{
|
||||||
|
QFile ADIF_file {file_name};
|
||||||
|
if (ADIF_file.open (QIODevice::WriteOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
QTextStream output_stream {&ADIF_file};
|
||||||
|
m_->log_->export_qsos (output_stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox::warning_message (this
|
||||||
|
, tr ("Export ADIF File Error")
|
||||||
|
, tr ("Cannot open \"%1\" for writing: %2")
|
||||||
|
.arg (ADIF_file.fileName ()).arg (ADIF_file.errorString ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
auto reset_action = new QAction {tr ("&Reset ..."), m_->ui_.log_table_view};
|
auto reset_action = new QAction {tr ("&Reset ..."), m_->ui_.log_table_view};
|
||||||
m_->ui_.log_table_view->insertAction (nullptr, reset_action);
|
m_->ui_.log_table_view->insertAction (nullptr, reset_action);
|
||||||
connect (reset_action, &QAction::triggered, [this, configuration] (bool /*checked*/) {
|
connect (reset_action, &QAction::triggered, [this, configuration] (bool /*checked*/) {
|
||||||
@ -88,10 +115,10 @@ void FoxLogWindow::log_model_changed (int row)
|
|||||||
{
|
{
|
||||||
if (row >= 0)
|
if (row >= 0)
|
||||||
{
|
{
|
||||||
m_->log_model_->selectRow (row);
|
m_->log_->model ()->selectRow (row);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_->log_model_->select ();
|
m_->log_->model ()->select ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
class QSettings;
|
class QSettings;
|
||||||
class Configuration;
|
class Configuration;
|
||||||
class QFont;
|
class QFont;
|
||||||
class QSqlTableModel;
|
class FoxLog;
|
||||||
|
|
||||||
class FoxLogWindow final
|
class FoxLogWindow final
|
||||||
: public AbstractLogWindow
|
: public AbstractLogWindow
|
||||||
@ -15,7 +15,7 @@ class FoxLogWindow final
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit FoxLogWindow (QSettings *, Configuration const *, QSqlTableModel * fox_log_model
|
explicit FoxLogWindow (QSettings *, Configuration const *, FoxLog * fox_log
|
||||||
, QWidget * parent = nullptr);
|
, QWidget * parent = nullptr);
|
||||||
~FoxLogWindow ();
|
~FoxLogWindow ();
|
||||||
|
|
||||||
|
@ -400,7 +400,11 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
highlight_types types {Highlight::CQ, Highlight::LotW};
|
highlight_types types {Highlight::CQ};
|
||||||
|
if (m_config && m_config->lotw_users ().user (decodedText.CQersCall()))
|
||||||
|
{
|
||||||
|
types.push_back (Highlight::LotW);
|
||||||
|
}
|
||||||
set_colours (m_config, &bg, &fg, types);
|
set_colours (m_config, &bg, &fg, types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2484,15 +2484,15 @@ void MainWindow::on_actionAstronomical_data_toggled (bool checked)
|
|||||||
|
|
||||||
void MainWindow::on_fox_log_action_triggered()
|
void MainWindow::on_fox_log_action_triggered()
|
||||||
{
|
{
|
||||||
if (!m_foxLog) m_foxLog.reset (new FoxLog);
|
if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config});
|
||||||
if (!m_foxLogWindow)
|
if (!m_foxLogWindow)
|
||||||
{
|
{
|
||||||
m_foxLogWindow.reset (new FoxLogWindow {m_settings, &m_config, m_foxLog->model ()});
|
m_foxLogWindow.reset (new FoxLogWindow {m_settings, &m_config, m_foxLog.data ()});
|
||||||
|
|
||||||
// Connect signals from fox log window
|
// Connect signals from fox log window
|
||||||
connect (this, &MainWindow::finished, m_foxLogWindow.data (), &FoxLogWindow::close);
|
connect (this, &MainWindow::finished, m_foxLogWindow.data (), &FoxLogWindow::close);
|
||||||
connect (m_foxLogWindow.data (), &FoxLogWindow::reset_log_model, [this] () {
|
connect (m_foxLogWindow.data (), &FoxLogWindow::reset_log_model, [this] () {
|
||||||
if (!m_foxLog) m_foxLog.reset (new FoxLog);
|
if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config});
|
||||||
m_foxLog->reset ();
|
m_foxLog->reset ();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -4913,7 +4913,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
|
|||||||
}
|
}
|
||||||
if(!bHisCall) {
|
if(!bHisCall) {
|
||||||
t=t0a;
|
t=t0a;
|
||||||
msgtype(t0a, ui->tx1);
|
msgtype(t0a + my_grid, ui->tx1);
|
||||||
}
|
}
|
||||||
if(SpecOp::NA_VHF==m_config.special_op_id()) sent=my_grid;
|
if(SpecOp::NA_VHF==m_config.special_op_id()) sent=my_grid;
|
||||||
if(SpecOp::FIELD_DAY==m_config.special_op_id()) sent=m_config.Field_Day_Exchange();
|
if(SpecOp::FIELD_DAY==m_config.special_op_id()) sent=m_config.Field_Day_Exchange();
|
||||||
@ -8271,7 +8271,7 @@ list2Done:
|
|||||||
m_hisGrid=m_foxQSO[hc1].grid;
|
m_hisGrid=m_foxQSO[hc1].grid;
|
||||||
m_rptSent=m_foxQSO[hc1].sent;
|
m_rptSent=m_foxQSO[hc1].sent;
|
||||||
m_rptRcvd=m_foxQSO[hc1].rcvd;
|
m_rptRcvd=m_foxQSO[hc1].rcvd;
|
||||||
if (!m_foxLog) m_foxLog.reset (new FoxLog);
|
if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config});
|
||||||
if (!m_foxLogWindow) on_fox_log_action_triggered ();
|
if (!m_foxLogWindow) on_fox_log_action_triggered ();
|
||||||
if (m_foxLog->add_QSO (QSO_time, m_hisCall, m_hisGrid, m_rptSent, m_rptRcvd, m_lastBand))
|
if (m_foxLog->add_QSO (QSO_time, m_hisCall, m_hisGrid, m_rptSent, m_rptRcvd, m_lastBand))
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,7 @@ extern "C" {
|
|||||||
#cmakedefine01 WSJT_SOFT_KEYING
|
#cmakedefine01 WSJT_SOFT_KEYING
|
||||||
#cmakedefine01 WSJT_ENABLE_EXPERIMENTAL_FEATURES
|
#cmakedefine01 WSJT_ENABLE_EXPERIMENTAL_FEATURES
|
||||||
#cmakedefine01 WSJT_RIG_NONE_CAN_SPLIT
|
#cmakedefine01 WSJT_RIG_NONE_CAN_SPLIT
|
||||||
|
#cmakedefine01 WSJT_TRACE_UDP
|
||||||
|
|
||||||
#define WSJTX_STRINGIZE1(x) #x
|
#define WSJTX_STRINGIZE1(x) #x
|
||||||
#define WSJTX_STRINGIZE(x) WSJTX_STRINGIZE1(x)
|
#define WSJTX_STRINGIZE(x) WSJTX_STRINGIZE1(x)
|
||||||
|
Loading…
Reference in New Issue
Block a user