mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-23 20:58:55 -05:00
New UDP messages to close and reconfigure WSJT-X plus more status fields
The Status(1) message acquires the new fields Frequency Tolerance, T/R Period, and Configuration Name. The Rx DF, Tx DF fields become unsigned (this should be a benign change which is just for correctness as -ve values have never been possible). The Close(6) message becomes bi-directional allowing external applications to gracefully close down WSJT-X instances. A new message SwitchConfiguration(14) is provided that allows an external application to switch the current configuration of a WSJT-X instance. Another new message Configure(15) is provided to allow external applications to adjust some key parameters like the mode and submode. See the NetworkMessages.hpp header commentary for full details. The UDPExamples/MessageAggregator reference application has been updated to be able to exercise all of the above changes. Note that this commit enforces stricter checking on the "Settings->Reporting->Allow UDP requests" option, which must be checked before any state changing incoming messages to a WSJT-X instance are processed.
This commit is contained in:
parent
7d3b346afa
commit
c65d832356
@ -2092,7 +2092,12 @@ void Configuration::impl::accept ()
|
||||
Q_EMIT self_->udp_server_port_changed (new_port);
|
||||
}
|
||||
|
||||
accept_udp_requests_ = ui_->accept_udp_requests_check_box->isChecked ();
|
||||
if (ui_->accept_udp_requests_check_box->isChecked () != accept_udp_requests_)
|
||||
{
|
||||
accept_udp_requests_ = ui_->accept_udp_requests_check_box->isChecked ();
|
||||
Q_EMIT self_->accept_udp_requests_changed (accept_udp_requests_);
|
||||
}
|
||||
|
||||
n1mm_server_name_ = ui_->n1mm_server_name_line_edit->text ();
|
||||
n1mm_server_port_ = ui_->n1mm_server_port_spin_box->value ();
|
||||
broadcast_to_n1mm_ = ui_->enable_n1mm_broadcast_check_box->isChecked ();
|
||||
|
@ -271,6 +271,7 @@ public:
|
||||
//
|
||||
Q_SIGNAL void udp_server_changed (QString const& udp_server) const;
|
||||
Q_SIGNAL void udp_server_port_changed (port_type server_port) const;
|
||||
Q_SIGNAL void accept_udp_requests_changed (bool checked) const;
|
||||
|
||||
// signal updates to decode highlighting
|
||||
Q_SIGNAL void decode_highlighting_changed (DecodeHighlightingModel const&) const;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include <QUdpSocket>
|
||||
#include <QHostInfo>
|
||||
@ -35,6 +36,7 @@ public:
|
||||
impl (QString const& id, QString const& version, QString const& revision,
|
||||
port_type server_port, MessageClient * self)
|
||||
: self_ {self}
|
||||
, enabled_ {false}
|
||||
, id_ {id}
|
||||
, version_ {version}
|
||||
, revision_ {revision}
|
||||
@ -79,6 +81,7 @@ public:
|
||||
Q_SLOT void host_info_results (QHostInfo);
|
||||
|
||||
MessageClient * self_;
|
||||
bool enabled_;
|
||||
QString id_;
|
||||
QString version_;
|
||||
QString revision_;
|
||||
@ -160,6 +163,12 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
||||
schema_ = in.schema ();
|
||||
}
|
||||
|
||||
if (!enabled_)
|
||||
{
|
||||
TRACE_UDP ("message processing disabled for id:" << in.id ());
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// message format is described in NetworkMessage.hpp
|
||||
//
|
||||
@ -200,6 +209,15 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
||||
}
|
||||
break;
|
||||
|
||||
case NetworkMessage::Close:
|
||||
TRACE_UDP ("Close");
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
last_message_.clear ();
|
||||
Q_EMIT self_->close ();
|
||||
}
|
||||
break;
|
||||
|
||||
case NetworkMessage::Replay:
|
||||
TRACE_UDP ("Replay");
|
||||
if (check_status (in) != Fail)
|
||||
@ -265,14 +283,38 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
||||
{
|
||||
QByteArray configuration_name;
|
||||
in >> configuration_name;
|
||||
TRACE_UDP ("SwitchConfiguration name:" << configuration_name);
|
||||
if (check_status (in) != Fail && configuration_name.size ())
|
||||
TRACE_UDP ("Switch Configuration name:" << configuration_name);
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->switch_configuration (QString::fromUtf8 (configuration_name));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NetworkMessage::Configure:
|
||||
{
|
||||
QByteArray mode;
|
||||
quint32 frequency_tolerance;
|
||||
QByteArray submode;
|
||||
bool fast_mode {false};
|
||||
quint32 tr_period {std::numeric_limits<quint32>::max ()};
|
||||
quint32 rx_df {std::numeric_limits<quint32>::max ()};
|
||||
QByteArray dx_call;
|
||||
QByteArray dx_grid;
|
||||
bool generate_messages {false};
|
||||
in >> mode >> frequency_tolerance >> submode >> fast_mode >> tr_period >> rx_df
|
||||
>> dx_call >> dx_grid >> generate_messages;
|
||||
TRACE_UDP ("Configure mode:" << mode << "frequency tolerance:" << frequency_tolerance << "submode:" << submode << "fast mode:" << fast_mode << "T/R period:" << tr_period << "rx df:" << rx_df << "dx call:" << dx_call << "dx grid:" << dx_grid << "generate messages:" << generate_messages);
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->configure (QString::fromUtf8 (mode), frequency_tolerance
|
||||
, QString::fromUtf8 (submode), fast_mode, tr_period, rx_df
|
||||
, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid)
|
||||
, generate_messages);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Ignore
|
||||
//
|
||||
@ -450,13 +492,19 @@ void MessageClient::add_blocked_destination (QHostAddress const& a)
|
||||
}
|
||||
}
|
||||
|
||||
void MessageClient::enable (bool flag)
|
||||
{
|
||||
m_->enabled_ = flag;
|
||||
}
|
||||
|
||||
void MessageClient::status_update (Frequency f, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode
|
||||
, bool tx_enabled, bool transmitting, bool decoding
|
||||
, qint32 rx_df, qint32 tx_df, QString const& de_call
|
||||
, quint32 rx_df, quint32 tx_df, QString const& de_call
|
||||
, QString const& de_grid, QString const& dx_grid
|
||||
, bool watchdog_timeout, QString const& sub_mode
|
||||
, bool fast_mode, quint8 special_op_mode
|
||||
, quint32 frequency_tolerance, quint32 tr_period
|
||||
, QString const& configuration_name)
|
||||
{
|
||||
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
||||
@ -466,8 +514,8 @@ void MessageClient::status_update (Frequency f, QString const& mode, QString con
|
||||
out << f << mode.toUtf8 () << dx_call.toUtf8 () << report.toUtf8 () << tx_mode.toUtf8 ()
|
||||
<< tx_enabled << transmitting << decoding << rx_df << tx_df << de_call.toUtf8 ()
|
||||
<< de_grid.toUtf8 () << dx_grid.toUtf8 () << watchdog_timeout << sub_mode.toUtf8 ()
|
||||
<< fast_mode << special_op_mode << configuration_name.toUtf8 ();
|
||||
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 << "configuration name:" << configuration_name);
|
||||
<< fast_mode << special_op_mode << frequency_tolerance << tr_period << configuration_name.toUtf8 ();
|
||||
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 << "frequency tolerance:" << frequency_tolerance << "T/R period:" << tr_period << "configuration name:" << configuration_name);
|
||||
m_->send_message (out, message);
|
||||
}
|
||||
}
|
||||
|
@ -47,12 +47,16 @@ public:
|
||||
// change the server port messages are sent to
|
||||
Q_SLOT void set_server_port (port_type server_port = 0u);
|
||||
|
||||
// enable incoming messages
|
||||
Q_SLOT void enable (bool);
|
||||
|
||||
// outgoing messages
|
||||
Q_SLOT void status_update (Frequency, QString const& mode, QString const& dx_call, QString const& report
|
||||
, QString const& tx_mode, bool tx_enabled, bool transmitting, bool decoding
|
||||
, qint32 rx_df, qint32 tx_df, QString const& de_call, QString const& de_grid
|
||||
, quint32 rx_df, quint32 tx_df, QString const& de_call, QString const& de_grid
|
||||
, QString const& dx_grid, bool watchdog_timeout, QString const& sub_mode
|
||||
, bool fast_mode, quint8 special_op_mode, QString const& configuration_name);
|
||||
, bool fast_mode, quint8 special_op_mode, quint32 frequency_tolerance
|
||||
, quint32 tr_period, QString const& configuration_name);
|
||||
Q_SLOT void decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
|
||||
, QString const& mode, QString const& message, bool low_confidence
|
||||
, bool off_air);
|
||||
@ -89,6 +93,10 @@ public:
|
||||
Q_SIGNAL void reply (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode
|
||||
, QString const& message_text, bool low_confidence, quint8 modifiers);
|
||||
|
||||
// this signal is emitted if the server has requested this client to
|
||||
// close down gracefully
|
||||
Q_SIGNAL void close ();
|
||||
|
||||
// this signal is emitted if the server has requested a replay of
|
||||
// all decodes
|
||||
Q_SIGNAL void replay ();
|
||||
@ -105,10 +113,16 @@ public:
|
||||
// callsign request for the specified call
|
||||
Q_SIGNAL void highlight_callsign (QString const& callsign, QColor const& bg, QColor const& fg, bool last_only);
|
||||
|
||||
// this signal is emitted if the server has requested a switch to a
|
||||
// new configuration
|
||||
// this signal is emitted if the server has requested a
|
||||
// configuration switch
|
||||
Q_SIGNAL void switch_configuration (QString const& configuration_name);
|
||||
|
||||
// this signal is emitted if the server has requested a
|
||||
// configuration change
|
||||
Q_SIGNAL void configure (QString const& mode, quint32 frequency_tolerance, QString const& submode
|
||||
, bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call
|
||||
, QString const& dx_grid, bool generate_messages);
|
||||
|
||||
// this signal is emitted when network errors occur or if a host
|
||||
// lookup fails
|
||||
Q_SIGNAL void error (QString const&) const;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "MessageServer.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <limits>
|
||||
|
||||
#include <QNetworkInterface>
|
||||
#include <QUdpSocket>
|
||||
@ -16,6 +17,11 @@
|
||||
|
||||
#include "moc_MessageServer.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
auto quint32_max = std::numeric_limits<quint32>::max ();
|
||||
}
|
||||
|
||||
class MessageServer::impl
|
||||
: public QUdpSocket
|
||||
{
|
||||
@ -238,8 +244,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
bool tx_enabled {false};
|
||||
bool transmitting {false};
|
||||
bool decoding {false};
|
||||
qint32 rx_df {-1};
|
||||
qint32 tx_df {-1};
|
||||
quint32 rx_df {quint32_max};
|
||||
quint32 tx_df {quint32_max};
|
||||
QByteArray de_call;
|
||||
QByteArray de_grid;
|
||||
QByteArray dx_grid;
|
||||
@ -247,10 +253,12 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
QByteArray sub_mode;
|
||||
bool fast_mode {false};
|
||||
quint8 special_op_mode {0};
|
||||
quint32 frequency_tolerance {quint32_max};
|
||||
quint32 tr_period {quint32_max};
|
||||
QByteArray configuration_name;
|
||||
in >> f >> mode >> dx_call >> report >> tx_mode >> tx_enabled >> transmitting >> decoding
|
||||
>> rx_df >> tx_df >> de_call >> de_grid >> dx_grid >> watchdog_timeout >> sub_mode
|
||||
>> fast_mode >> special_op_mode >> configuration_name;
|
||||
>> fast_mode >> special_op_mode >> frequency_tolerance >> tr_period >> configuration_name;
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call)
|
||||
@ -259,7 +267,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
, QString::fromUtf8 (de_call), QString::fromUtf8 (de_grid)
|
||||
, QString::fromUtf8 (dx_grid), watchdog_timeout
|
||||
, QString::fromUtf8 (sub_mode), fast_mode
|
||||
, special_op_mode, QString::fromUtf8 (configuration_name));
|
||||
, special_op_mode, frequency_tolerance, tr_period
|
||||
, QString::fromUtf8 (configuration_name));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -494,6 +503,17 @@ void MessageServer::replay (QString const& id)
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::close (QString const& id)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Close, id, (*iter).negotiated_schema_number_};
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::halt_tx (QString const& id, bool auto_only)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
@ -554,3 +574,18 @@ void MessageServer::switch_configuration (QString const& id, QString const& conf
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::configure (QString const& id, QString const& mode, quint32 frequency_tolerance
|
||||
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
|
||||
, QString const& dx_call, QString const& dx_grid, bool generate_messages)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Configure, id, (*iter).negotiated_schema_number_};
|
||||
out << mode.toUtf8 () << frequency_tolerance << submode.toUtf8 () << fast_mode << tr_period << rx_df
|
||||
<< dx_call.toUtf8 () << dx_grid.toUtf8 () << generate_messages;
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,9 @@ public:
|
||||
Q_SLOT void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
|
||||
, QString const& mode, QString const& message, bool low_confidence, quint8 modifiers);
|
||||
|
||||
// ask the client with identification 'id' to close down gracefully
|
||||
Q_SLOT void close (QString const& id);
|
||||
|
||||
// ask the client with identification 'id' to replay all decodes
|
||||
Q_SLOT void replay (QString const& id);
|
||||
|
||||
@ -72,18 +75,25 @@ public:
|
||||
, QColor const& bg = QColor {}, QColor const& fg = QColor {}
|
||||
, bool last_only = false);
|
||||
|
||||
// ask the client with identification 'id' to switch configuration
|
||||
// ask the client with identification 'id' to switch to
|
||||
// configuration 'configuration_name'
|
||||
Q_SLOT void switch_configuration (QString const& id, QString const& configuration_name);
|
||||
|
||||
// ask the client with identification 'id' to change configuration
|
||||
Q_SLOT void configure (QString const& id, QString const& mode, quint32 frequency_tolerance
|
||||
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
|
||||
, QString const& dx_call, QString const& dx_grid, bool generate_messages);
|
||||
|
||||
// the following signals are emitted when a client broadcasts the
|
||||
// matching message
|
||||
Q_SIGNAL void client_opened (QString const& id, QString const& version, QString const& revision);
|
||||
Q_SIGNAL void status_update (QString const& id, Frequency, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode, bool tx_enabled
|
||||
, bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df
|
||||
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
|
||||
, QString const& de_call, QString const& de_grid, QString const& dx_grid
|
||||
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode
|
||||
, quint8 special_op_mode, QString const& configuration_name);
|
||||
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
|
||||
, QString const& configuration_name);
|
||||
Q_SIGNAL void client_closed (QString const& id);
|
||||
Q_SIGNAL void decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time
|
||||
, quint32 delta_frequency, QString const& mode, QString const& message
|
||||
|
@ -116,8 +116,8 @@
|
||||
* Tx Enabled bool
|
||||
* Transmitting bool
|
||||
* Decoding bool
|
||||
* Rx DF qint32
|
||||
* Tx DF qint32
|
||||
* Rx DF quint32
|
||||
* Tx DF quint32
|
||||
* DE call utf8
|
||||
* DE grid utf8
|
||||
* DX grid utf8
|
||||
@ -125,6 +125,8 @@
|
||||
* Sub-mode utf8
|
||||
* Fast mode bool
|
||||
* Special Operation Mode quint8
|
||||
* Frequency Tolerance quint32
|
||||
* T/R Period quint32
|
||||
* Configuration Name utf8
|
||||
*
|
||||
* WSJT-X sends this status message when various internal state
|
||||
@ -134,20 +136,22 @@
|
||||
*
|
||||
* Application start up,
|
||||
* "Enable Tx" button status changes,
|
||||
* Dial frequency changes,
|
||||
* Changes to the "DX Call" field,
|
||||
* Operating mode, sub-mode or fast mode changes,
|
||||
* Transmit mode changed (in dual JT9+JT65 mode),
|
||||
* Changes to the "Rpt" spinner,
|
||||
* After an old decodes replay sequence (see Replay below),
|
||||
* When switching between Tx and Rx mode,
|
||||
* At the start and end of decoding,
|
||||
* When the Rx DF changes,
|
||||
* When the Tx DF changes,
|
||||
* When settings are exited,
|
||||
* When the DX call or grid changes,
|
||||
* When the Tx watchdog is set or reset,
|
||||
* When the configuration name changes.
|
||||
* dial frequency changes,
|
||||
* changes to the "DX Call" field,
|
||||
* operating mode, sub-mode or fast mode changes,
|
||||
* transmit mode changed (in dual JT9+JT65 mode),
|
||||
* changes to the "Rpt" spinner,
|
||||
* after an old decodes replay sequence (see Replay below),
|
||||
* when switching between Tx and Rx mode,
|
||||
* at the start and end of decoding,
|
||||
* when the Rx DF changes,
|
||||
* when the Tx DF changes,
|
||||
* when settings are exited,
|
||||
* when the DX call or grid changes,
|
||||
* when the Tx watchdog is set or reset,
|
||||
* when the frequency tolerance is changed,
|
||||
* when the T/R period is changed,
|
||||
* when the configuration name changes.
|
||||
*
|
||||
* The Special operation mode is an enumeration that indicates the
|
||||
* setting selected in the WSJT-X "Settings->Advanced->Special
|
||||
@ -161,6 +165,10 @@
|
||||
* 5 -> FOX
|
||||
* 6 -> HOUND
|
||||
*
|
||||
* The Frequency Tolerance and T/R period fields may have a value
|
||||
* of the maximum quint32 value which implies the field is not
|
||||
* applicable.
|
||||
*
|
||||
*
|
||||
* Decode Out 2 quint32
|
||||
* Id (unique key) utf8
|
||||
@ -273,11 +281,12 @@
|
||||
* button.
|
||||
*
|
||||
*
|
||||
* Close Out 6 quint32
|
||||
* Close Out/In 6 quint32
|
||||
* Id (unique key) utf8
|
||||
*
|
||||
* Close is sent by a client immediately prior to it shutting
|
||||
* down gracefully.
|
||||
* Close is sent by a client immediately prior to it shutting
|
||||
* down gracefully. When sent by a server it requests the target
|
||||
* client to close down gracefully.
|
||||
*
|
||||
*
|
||||
* Replay In 7 quint32
|
||||
@ -418,13 +427,33 @@
|
||||
* cleared.
|
||||
*
|
||||
*
|
||||
* Switch Configuration In 14 quint32
|
||||
* SwitchConfiguration In 14 quint32
|
||||
* Id (unique key) utf8
|
||||
* Configuration Name utf8
|
||||
*
|
||||
* The server may send this message at any time. The message
|
||||
* specifies the name of the configuration to switch to. The new
|
||||
* configuration must exist.
|
||||
*
|
||||
*
|
||||
* Configure In 15 quint32
|
||||
* Id (unique key) utf8
|
||||
* Mode utf8
|
||||
* Frequency Tolerance quint32
|
||||
* Submode utf8
|
||||
* Fast Mode bool
|
||||
* T/R Period quint32
|
||||
* Rx DF quint32
|
||||
* DX Call utf8
|
||||
* DX Grid utf8
|
||||
* Generate Messages bool
|
||||
*
|
||||
* The server may send this message at any time. The message
|
||||
* specifies various configuration options. For utf8 string
|
||||
* fields an empty value implies no change, for the quint32 Rx DF
|
||||
* and Frequency Tolerance fields the maximum quint32 value
|
||||
* implies no change. Invalid or unrecognized values will be
|
||||
* silently ignored.
|
||||
*/
|
||||
|
||||
#include <QDataStream>
|
||||
@ -455,6 +484,7 @@ namespace NetworkMessage
|
||||
LoggedADIF,
|
||||
HighlightCallsign,
|
||||
SwitchConfiguration,
|
||||
Configure,
|
||||
maximum_message_type_ // ONLY add new message types
|
||||
// immediately before here
|
||||
};
|
||||
|
@ -1,8 +1,11 @@
|
||||
#include "ClientWidget.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <QRegExp>
|
||||
#include <QColor>
|
||||
#include <QtWidgets>
|
||||
#include <QAction>
|
||||
#include <QDebug>
|
||||
|
||||
#include "validators/MaidenheadLocatorValidator.hpp"
|
||||
|
||||
@ -11,6 +14,9 @@ namespace
|
||||
//QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
|
||||
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"};
|
||||
QRegularExpression cq_re {"(CQ|CQDX|QRZ)[^A-Z0-9/]+"};
|
||||
QRegExpValidator message_validator {message_alphabet};
|
||||
MaidenheadLocatorValidator locator_validator;
|
||||
quint32 quint32_max {std::numeric_limits<quint32>::max ()};
|
||||
|
||||
void update_dynamic_property (QWidget * widget, char const * property, QVariant const& value)
|
||||
{
|
||||
@ -21,9 +27,10 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id)
|
||||
: client_id_ {client_id}
|
||||
, rx_df_ (-1)
|
||||
ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id, QObject * parent)
|
||||
: QSortFilterProxyModel {parent}
|
||||
, client_id_ {client_id}
|
||||
, rx_df_ (quint32_max)
|
||||
{
|
||||
}
|
||||
|
||||
@ -49,7 +56,7 @@ QVariant ClientWidget::IdFilterModel::data (QModelIndex const& proxy_index, int
|
||||
break;
|
||||
|
||||
case 4: // DF
|
||||
if (qAbs (QSortFilterProxyModel::data (proxy_index).toInt () - rx_df_) <= 10)
|
||||
if (qAbs (QSortFilterProxyModel::data (proxy_index).toUInt () - rx_df_) <= 10)
|
||||
{
|
||||
return QColor {255, 200, 200};
|
||||
}
|
||||
@ -87,7 +94,7 @@ void ClientWidget::IdFilterModel::de_call (QString const& call)
|
||||
}
|
||||
}
|
||||
|
||||
void ClientWidget::IdFilterModel::rx_df (int df)
|
||||
void ClientWidget::IdFilterModel::rx_df (quint32 df)
|
||||
{
|
||||
if (df != rx_df_)
|
||||
{
|
||||
@ -119,27 +126,48 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
, QListWidget const * calls_of_interest, QWidget * parent)
|
||||
: QDockWidget {make_title (id, version, revision), parent}
|
||||
, id_ {id}
|
||||
, done_ {false}
|
||||
, calls_of_interest_ {calls_of_interest}
|
||||
, decodes_proxy_model_ {id_}
|
||||
, decodes_proxy_model_ {id}
|
||||
, beacons_proxy_model_ {id}
|
||||
, erase_action_ {new QAction {tr ("&Erase Band Activity"), this}}
|
||||
, erase_rx_frequency_action_ {new QAction {tr ("Erase &Rx Frequency"), this}}
|
||||
, erase_both_action_ {new QAction {tr ("Erase &Both"), this}}
|
||||
, decodes_table_view_ {new QTableView}
|
||||
, beacons_table_view_ {new QTableView}
|
||||
, message_line_edit_ {new QLineEdit}
|
||||
, grid_line_edit_ {new QLineEdit}
|
||||
, decodes_table_view_ {new QTableView {this}}
|
||||
, beacons_table_view_ {new QTableView {this}}
|
||||
, message_line_edit_ {new QLineEdit {this}}
|
||||
, grid_line_edit_ {new QLineEdit {this}}
|
||||
, generate_messages_push_button_ {new QPushButton {tr ("&Gen Msgs"), this}}
|
||||
, auto_off_button_ {nullptr}
|
||||
, halt_tx_button_ {nullptr}
|
||||
, de_label_ {new QLabel {this}}
|
||||
, frequency_label_ {new QLabel {this}}
|
||||
, tx_df_label_ {new QLabel {this}}
|
||||
, report_label_ {new QLabel {this}}
|
||||
, configuration_line_edit_ {new QLineEdit {this}}
|
||||
, mode_line_edit_ {new QLineEdit {this}}
|
||||
, frequency_tolerance_spin_box_ {new QSpinBox {this}}
|
||||
, tx_mode_label_ {new QLabel {this}}
|
||||
, submode_line_edit_ {new QLineEdit {this}}
|
||||
, fast_mode_check_box_ {new QCheckBox {this}}
|
||||
, tr_period_spin_box_ {new QSpinBox {this}}
|
||||
, rx_df_spin_box_ {new QSpinBox {this}}
|
||||
, dx_call_line_edit_ {new QLineEdit {this}}
|
||||
, dx_grid_line_edit_ {new QLineEdit {this}}
|
||||
, decodes_page_ {new QWidget {this}}
|
||||
, beacons_page_ {new QWidget {this}}
|
||||
, content_widget_ {new QFrame {this}}
|
||||
, status_bar_ {new QStatusBar {this}}
|
||||
, control_button_box_ {new QDialogButtonBox {this}}
|
||||
, form_layout_ {new QFormLayout}
|
||||
, horizontal_layout_ {new QHBoxLayout}
|
||||
, subform1_layout_ {new QFormLayout}
|
||||
, subform2_layout_ {new QFormLayout}
|
||||
, subform3_layout_ {new QFormLayout}
|
||||
, decodes_layout_ {new QVBoxLayout {decodes_page_}}
|
||||
, beacons_layout_ {new QVBoxLayout {beacons_page_}}
|
||||
, content_layout_ {new QVBoxLayout {content_widget_}}
|
||||
, decodes_stack_ {new QStackedLayout}
|
||||
, auto_off_button_ {new QPushButton {tr ("&Auto Off")}}
|
||||
, halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}}
|
||||
, de_label_ {new QLabel}
|
||||
, mode_label_ {new QLabel}
|
||||
, fast_mode_ {false}
|
||||
, frequency_label_ {new QLabel}
|
||||
, dx_label_ {new QLabel}
|
||||
, rx_df_label_ {new QLabel}
|
||||
, tx_df_label_ {new QLabel}
|
||||
, report_label_ {new QLabel}
|
||||
, configuration_line_edit_ {new QLineEdit}
|
||||
, columns_resized_ {false}
|
||||
{
|
||||
// set up widgets
|
||||
@ -153,12 +181,33 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
decodes_table_view_->insertAction (nullptr, erase_rx_frequency_action_);
|
||||
decodes_table_view_->insertAction (nullptr, erase_both_action_);
|
||||
|
||||
auto form_layout = new QFormLayout;
|
||||
form_layout->addRow (tr ("Free text:"), message_line_edit_);
|
||||
form_layout->addRow (tr ("Temporary grid:"), grid_line_edit_);
|
||||
form_layout->addRow (tr ("Configuration name:"), configuration_line_edit_);
|
||||
message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this});
|
||||
grid_line_edit_->setValidator (new MaidenheadLocatorValidator {this});
|
||||
message_line_edit_->setValidator (&message_validator);
|
||||
grid_line_edit_->setValidator (&locator_validator);
|
||||
dx_grid_line_edit_->setValidator (&locator_validator);
|
||||
tr_period_spin_box_->setRange (5, 30);
|
||||
tr_period_spin_box_->setSuffix (" s");
|
||||
rx_df_spin_box_->setRange (200, 5000);
|
||||
frequency_tolerance_spin_box_->setRange (10, 1000);
|
||||
frequency_tolerance_spin_box_->setPrefix ("\u00b1");
|
||||
frequency_tolerance_spin_box_->setSuffix (" Hz");
|
||||
|
||||
form_layout_->addRow (tr ("Free text:"), message_line_edit_);
|
||||
form_layout_->addRow (tr ("Temporary grid:"), grid_line_edit_);
|
||||
form_layout_->addRow (tr ("Configuration name:"), configuration_line_edit_);
|
||||
form_layout_->addRow (horizontal_layout_);
|
||||
subform1_layout_->addRow (tr ("Mode:"), mode_line_edit_);
|
||||
subform2_layout_->addRow (tr ("Submode:"), submode_line_edit_);
|
||||
subform3_layout_->addRow (tr ("Fast mode:"), fast_mode_check_box_);
|
||||
subform1_layout_->addRow (tr ("T/R period:"), tr_period_spin_box_);
|
||||
subform2_layout_->addRow (tr ("Rx DF:"), rx_df_spin_box_);
|
||||
subform3_layout_->addRow (tr ("Freq. Tol:"), frequency_tolerance_spin_box_);
|
||||
subform1_layout_->addRow (tr ("DX call:"), dx_call_line_edit_);
|
||||
subform2_layout_->addRow (tr ("DX grid:"), dx_grid_line_edit_);
|
||||
subform3_layout_->addRow (generate_messages_push_button_);
|
||||
horizontal_layout_->addLayout (subform1_layout_);
|
||||
horizontal_layout_->addLayout (subform2_layout_);
|
||||
horizontal_layout_->addLayout (subform3_layout_);
|
||||
|
||||
connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) {
|
||||
Q_EMIT do_free_text (id_, text, false);
|
||||
});
|
||||
@ -171,66 +220,99 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
connect (configuration_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
Q_EMIT switch_configuration (id_, configuration_line_edit_->text ());
|
||||
});
|
||||
connect (mode_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, mode_line_edit_->text (), quint32_max, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (frequency_tolerance_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
|
||||
QString empty;
|
||||
auto f = frequency_tolerance_spin_box_->specialValueText ().size () ? quint32_max : i;
|
||||
Q_EMIT configure (id_, empty, f, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (submode_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, submode_line_edit_->text (), fast_mode ()
|
||||
, quint32_max, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (fast_mode_check_box_, &QCheckBox::stateChanged, [this] (int state) {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, Qt::Checked == state
|
||||
, quint32_max, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (tr_period_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
, i, quint32_max, empty, empty, false);
|
||||
});
|
||||
connect (rx_df_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
, quint32_max, i, empty, empty, false);
|
||||
});
|
||||
connect (dx_call_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, dx_call_line_edit_->text (), empty, false);
|
||||
});
|
||||
connect (dx_grid_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, empty, dx_grid_line_edit_->text (), false);
|
||||
});
|
||||
|
||||
auto decodes_page = new QWidget;
|
||||
auto decodes_layout = new QVBoxLayout {decodes_page};
|
||||
decodes_layout->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
decodes_layout->addWidget (decodes_table_view_);
|
||||
decodes_layout->addLayout (form_layout);
|
||||
decodes_layout_->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
decodes_layout_->addWidget (decodes_table_view_);
|
||||
decodes_layout_->addLayout (form_layout_);
|
||||
|
||||
auto beacons_proxy_model = new IdFilterModel {id_};
|
||||
beacons_proxy_model->setSourceModel (beacons_model);
|
||||
beacons_table_view_->setModel (beacons_proxy_model);
|
||||
beacons_proxy_model_.setSourceModel (beacons_model);
|
||||
beacons_table_view_->setModel (&beacons_proxy_model_);
|
||||
beacons_table_view_->verticalHeader ()->hide ();
|
||||
beacons_table_view_->hideColumn (0);
|
||||
beacons_table_view_->horizontalHeader ()->setStretchLastSection (true);
|
||||
beacons_table_view_->setContextMenuPolicy (Qt::ActionsContextMenu);
|
||||
beacons_table_view_->insertAction (nullptr, erase_action_);
|
||||
|
||||
auto beacons_page = new QWidget;
|
||||
auto beacons_layout = new QVBoxLayout {beacons_page};
|
||||
beacons_layout->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
beacons_layout->addWidget (beacons_table_view_);
|
||||
beacons_layout_->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
beacons_layout_->addWidget (beacons_table_view_);
|
||||
|
||||
decodes_stack_->addWidget (decodes_page);
|
||||
decodes_stack_->addWidget (beacons_page);
|
||||
decodes_stack_->addWidget (decodes_page_);
|
||||
decodes_stack_->addWidget (beacons_page_);
|
||||
|
||||
// stack alternative views
|
||||
auto content_layout = new QVBoxLayout;
|
||||
content_layout->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
content_layout->addLayout (decodes_stack_);
|
||||
content_layout_->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
content_layout_->addLayout (decodes_stack_);
|
||||
|
||||
// set up controls
|
||||
auto control_button_box = new QDialogButtonBox;
|
||||
control_button_box->addButton (auto_off_button_, QDialogButtonBox::ActionRole);
|
||||
control_button_box->addButton (halt_tx_button_, QDialogButtonBox::ActionRole);
|
||||
auto_off_button_ = control_button_box_->addButton (tr ("&Auto Off"), QDialogButtonBox::ActionRole);
|
||||
halt_tx_button_ = control_button_box_->addButton (tr ("&Halt Tx"), QDialogButtonBox::ActionRole);
|
||||
connect (generate_messages_push_button_, &QAbstractButton::clicked, [this] (bool /*checked*/) {
|
||||
QString empty;
|
||||
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode ()
|
||||
, quint32_max, quint32_max, empty, empty, true);
|
||||
});
|
||||
connect (auto_off_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||
Q_EMIT do_halt_tx (id_, true);
|
||||
});
|
||||
connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||
Q_EMIT do_halt_tx (id_, false);
|
||||
});
|
||||
content_layout->addWidget (control_button_box);
|
||||
content_layout_->addWidget (control_button_box_);
|
||||
|
||||
// set up status area
|
||||
auto status_bar = new QStatusBar;
|
||||
status_bar->addPermanentWidget (de_label_);
|
||||
status_bar->addPermanentWidget (mode_label_);
|
||||
status_bar->addPermanentWidget (frequency_label_);
|
||||
status_bar->addPermanentWidget (dx_label_);
|
||||
status_bar->addPermanentWidget (rx_df_label_);
|
||||
status_bar->addPermanentWidget (tx_df_label_);
|
||||
status_bar->addPermanentWidget (report_label_);
|
||||
content_layout->addWidget (status_bar);
|
||||
connect (this, &ClientWidget::topLevelChanged, status_bar, &QStatusBar::setSizeGripEnabled);
|
||||
status_bar_->addPermanentWidget (de_label_);
|
||||
status_bar_->addPermanentWidget (tx_mode_label_);
|
||||
status_bar_->addPermanentWidget (frequency_label_);
|
||||
status_bar_->addPermanentWidget (tx_df_label_);
|
||||
status_bar_->addPermanentWidget (report_label_);
|
||||
content_layout_->addWidget (status_bar_);
|
||||
connect (this, &ClientWidget::topLevelChanged, status_bar_, &QStatusBar::setSizeGripEnabled);
|
||||
|
||||
// set up central widget
|
||||
auto content_widget = new QFrame;
|
||||
content_widget->setFrameStyle (QFrame::StyledPanel | QFrame::Sunken);
|
||||
content_widget->setLayout (content_layout);
|
||||
setWidget (content_widget);
|
||||
content_widget_->setFrameStyle (QFrame::StyledPanel | QFrame::Sunken);
|
||||
setWidget (content_widget_);
|
||||
// setMinimumSize (QSize {550, 0});
|
||||
setFeatures (DockWidgetMovable | DockWidgetFloatable);
|
||||
setAllowedAreas (Qt::BottomDockWidgetArea);
|
||||
setFloating (true);
|
||||
|
||||
@ -257,6 +339,25 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
|
||||
}
|
||||
}
|
||||
|
||||
void ClientWidget::dispose ()
|
||||
{
|
||||
done_ = true;
|
||||
close ();
|
||||
}
|
||||
|
||||
void ClientWidget::closeEvent (QCloseEvent *e)
|
||||
{
|
||||
if (!done_)
|
||||
{
|
||||
Q_EMIT do_close (id_);
|
||||
e->ignore (); // defer closure until client actually closes
|
||||
}
|
||||
else
|
||||
{
|
||||
QDockWidget::closeEvent (e);
|
||||
}
|
||||
}
|
||||
|
||||
ClientWidget::~ClientWidget ()
|
||||
{
|
||||
for (int row = 0; row < calls_of_interest_->count (); ++row)
|
||||
@ -266,16 +367,45 @@ ClientWidget::~ClientWidget ()
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientWidget::fast_mode () const
|
||||
{
|
||||
return fast_mode_check_box_->isChecked ();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void update_line_edit (QLineEdit * le, QString const& value, bool allow_empty = true)
|
||||
{
|
||||
le->setEnabled (value.size () || allow_empty);
|
||||
if (!(le->hasFocus () && le->isModified ()))
|
||||
{
|
||||
le->setText (value);
|
||||
}
|
||||
}
|
||||
|
||||
void update_spin_box (QSpinBox * sb, int value, QString const& special_value = QString {})
|
||||
{
|
||||
sb->setSpecialValueText (special_value);
|
||||
bool enable {0 == special_value.size ()};
|
||||
sb->setEnabled (enable);
|
||||
if (!sb->hasFocus () && enable)
|
||||
{
|
||||
sb->setValue (value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientWidget::update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode, bool tx_enabled
|
||||
, bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df
|
||||
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
|
||||
, QString const& de_call, QString const& de_grid, QString const& dx_grid
|
||||
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode
|
||||
, quint8 special_op_mode, QString const& configuration_name)
|
||||
, bool watchdog_timeout, QString const& submode, bool fast_mode
|
||||
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
|
||||
, QString const& configuration_name)
|
||||
{
|
||||
if (id == id_)
|
||||
if (id == id_)
|
||||
{
|
||||
fast_mode_ = fast_mode;
|
||||
fast_mode_check_box_->setChecked (fast_mode);
|
||||
decodes_proxy_model_.de_call (de_call);
|
||||
decodes_proxy_model_.rx_df (rx_df);
|
||||
QString special;
|
||||
@ -293,26 +423,26 @@ void ClientWidget::update_status (QString const& id, Frequency f, QString const&
|
||||
.arg (de_grid.size () ? '(' + de_grid + ')' : QString {})
|
||||
.arg (special)
|
||||
: QString {});
|
||||
mode_label_->setText (QString {"Mode: %1%2%3%4"}
|
||||
.arg (mode)
|
||||
.arg (sub_mode)
|
||||
.arg (fast_mode && !mode.contains (QRegularExpression {R"(ISCAT|MSK144)"}) ? "fast" : "")
|
||||
update_line_edit (mode_line_edit_, mode);
|
||||
update_spin_box (frequency_tolerance_spin_box_, frequency_tolerance
|
||||
, quint32_max == frequency_tolerance ? QString {"n/a"} : QString {});
|
||||
update_line_edit (submode_line_edit_, submode, false);
|
||||
tx_mode_label_->setText (QString {"Tx Mode: %1"}
|
||||
.arg (tx_mode.isEmpty () || tx_mode == mode ? "" : '(' + tx_mode + ')'));
|
||||
frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f));
|
||||
dx_label_->setText (dx_call.size () >= 0 ? QString {"DX: %1%2"}.arg (dx_call)
|
||||
.arg (dx_grid.size () ? '(' + dx_grid + ')' : QString {}) : QString {});
|
||||
rx_df_label_->setText (rx_df >= 0 ? QString {"Rx: %1"}.arg (rx_df) : "");
|
||||
tx_df_label_->setText (tx_df >= 0 ? QString {"Tx: %1"}.arg (tx_df) : "");
|
||||
update_line_edit (dx_call_line_edit_, dx_call);
|
||||
update_line_edit (dx_grid_line_edit_, dx_grid);
|
||||
if (rx_df != quint32_max) update_spin_box (rx_df_spin_box_, rx_df);
|
||||
update_spin_box (tr_period_spin_box_, tr_period
|
||||
, quint32_max == tr_period ? QString {"n/a"} : QString {});
|
||||
tx_df_label_->setText (QString {"Tx: %1"}.arg (tx_df));
|
||||
report_label_->setText ("SNR: " + report);
|
||||
update_dynamic_property (frequency_label_, "transmitting", transmitting);
|
||||
auto_off_button_->setEnabled (tx_enabled);
|
||||
halt_tx_button_->setEnabled (transmitting);
|
||||
update_dynamic_property (mode_label_, "decoding", decoding);
|
||||
update_line_edit (configuration_line_edit_, configuration_name);
|
||||
update_dynamic_property (mode_line_edit_, "decoding", decoding);
|
||||
update_dynamic_property (tx_df_label_, "watchdog_timeout", watchdog_timeout);
|
||||
if (!configuration_line_edit_->hasFocus ())
|
||||
{
|
||||
configuration_line_edit_->setText (configuration_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
#ifndef WSJTX_UDP_CLIENT_WIDGET_MODEL_HPP__
|
||||
#define WSJTX_UDP_CLIENT_WIDGET_MODEL_HPP__
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QObject>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QString>
|
||||
#include <QRegularExpression>
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "MessageServer.hpp"
|
||||
|
||||
@ -13,6 +13,20 @@ class QAbstractItemModel;
|
||||
class QModelIndex;
|
||||
class QColor;
|
||||
class QAction;
|
||||
class QListWidget;
|
||||
class QFormLayout;
|
||||
class QVBoxLayout;
|
||||
class QHBoxLayout;
|
||||
class QStackedLayout;
|
||||
class QTableView;
|
||||
class QLineEdit;
|
||||
class QAbstractButton;
|
||||
class QLabel;
|
||||
class QCheckBox;
|
||||
class QSpinBox;
|
||||
class QFrame;
|
||||
class QStatusBar;
|
||||
class QDialogButtonBox;
|
||||
|
||||
using Frequency = MessageServer::Frequency;
|
||||
|
||||
@ -25,16 +39,18 @@ public:
|
||||
explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
|
||||
, QString const& id, QString const& version, QString const& revision
|
||||
, QListWidget const * calls_of_interest, QWidget * parent = nullptr);
|
||||
void dispose ();
|
||||
~ClientWidget ();
|
||||
|
||||
bool fast_mode () const {return fast_mode_;}
|
||||
bool fast_mode () const;
|
||||
|
||||
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode, bool tx_enabled
|
||||
, bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df
|
||||
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
|
||||
, QString const& de_call, QString const& de_grid, QString const& dx_grid
|
||||
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode
|
||||
, quint8 special_op_mode, QString const& configuration_name);
|
||||
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
|
||||
, QString const& configuration_name);
|
||||
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime, qint32 snr
|
||||
, float delta_time, quint32 delta_frequency, QString const& mode
|
||||
, QString const& message, bool low_confidence, bool off_air);
|
||||
@ -45,6 +61,7 @@ public:
|
||||
Q_SLOT void decodes_cleared (QString const& client_id);
|
||||
|
||||
Q_SIGNAL void do_clear_decodes (QString const& id, quint8 window = 0);
|
||||
Q_SIGNAL void do_close (QString const& id);
|
||||
Q_SIGNAL void do_reply (QModelIndex const&, quint8 modifier);
|
||||
Q_SIGNAL void do_halt_tx (QString const& id, bool auto_only);
|
||||
Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool);
|
||||
@ -53,31 +70,38 @@ public:
|
||||
, QColor const& bg = QColor {}, QColor const& fg = QColor {}
|
||||
, bool last_only = false);
|
||||
Q_SIGNAL void switch_configuration (QString const& id, QString const& configuration_name);
|
||||
Q_SIGNAL void configure (QString const& id, QString const& mode, quint32 frequency_tolerance
|
||||
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
|
||||
, QString const& dx_call, QString const& dx_grid, bool generate_messages);
|
||||
|
||||
private:
|
||||
|
||||
QString id_;
|
||||
QListWidget const * calls_of_interest_;
|
||||
class IdFilterModel final
|
||||
: public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
IdFilterModel (QString const& client_id);
|
||||
IdFilterModel (QString const& client_id, QObject * = nullptr);
|
||||
|
||||
void de_call (QString const&);
|
||||
void rx_df (int);
|
||||
void rx_df (quint32);
|
||||
|
||||
QVariant data (QModelIndex const& proxy_index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
bool filterAcceptsRow (int source_row, QModelIndex const& source_parent) const override;
|
||||
|
||||
private:
|
||||
QString client_id_;
|
||||
QString call_;
|
||||
QRegularExpression base_call_re_;
|
||||
int rx_df_;
|
||||
} decodes_proxy_model_;
|
||||
quint32 rx_df_;
|
||||
};
|
||||
|
||||
void closeEvent (QCloseEvent *) override;
|
||||
|
||||
QString id_;
|
||||
bool done_;
|
||||
QListWidget const * calls_of_interest_;
|
||||
IdFilterModel decodes_proxy_model_;
|
||||
IdFilterModel beacons_proxy_model_;
|
||||
|
||||
QAction * erase_action_;
|
||||
QAction * erase_rx_frequency_action_;
|
||||
QAction * erase_both_action_;
|
||||
@ -85,18 +109,39 @@ private:
|
||||
QTableView * beacons_table_view_;
|
||||
QLineEdit * message_line_edit_;
|
||||
QLineEdit * grid_line_edit_;
|
||||
QStackedLayout * decodes_stack_;
|
||||
QAbstractButton * generate_messages_push_button_;
|
||||
QAbstractButton * auto_off_button_;
|
||||
QAbstractButton * halt_tx_button_;
|
||||
QLabel * de_label_;
|
||||
QLabel * mode_label_;
|
||||
bool fast_mode_;
|
||||
QLabel * frequency_label_;
|
||||
QLabel * dx_label_;
|
||||
QLabel * rx_df_label_;
|
||||
QLabel * tx_df_label_;
|
||||
QLabel * report_label_;
|
||||
QLineEdit * configuration_line_edit_;
|
||||
QLineEdit * mode_line_edit_;
|
||||
QSpinBox * frequency_tolerance_spin_box_;
|
||||
QLabel * tx_mode_label_;
|
||||
QLineEdit * submode_line_edit_;
|
||||
QCheckBox * fast_mode_check_box_;
|
||||
QSpinBox * tr_period_spin_box_;
|
||||
QSpinBox * rx_df_spin_box_;
|
||||
QLineEdit * dx_call_line_edit_;
|
||||
QLineEdit * dx_grid_line_edit_;
|
||||
QWidget * decodes_page_;
|
||||
QWidget * beacons_page_;
|
||||
QFrame * content_widget_;
|
||||
QStatusBar * status_bar_;
|
||||
QDialogButtonBox * control_button_box_;
|
||||
|
||||
QFormLayout * form_layout_;
|
||||
QHBoxLayout * horizontal_layout_;
|
||||
QFormLayout * subform1_layout_;
|
||||
QFormLayout * subform2_layout_;
|
||||
QFormLayout * subform3_layout_;
|
||||
QVBoxLayout * decodes_layout_;
|
||||
QVBoxLayout * beacons_layout_;
|
||||
QVBoxLayout * content_layout_;
|
||||
QStackedLayout * decodes_stack_;
|
||||
|
||||
bool columns_resized_;
|
||||
};
|
||||
|
||||
|
@ -250,6 +250,7 @@ void MessageAggregatorMainWindow::add_client (QString const& id, QString const&
|
||||
connect (server_, &MessageServer::WSPR_decode, dock, &ClientWidget::beacon_spot_added);
|
||||
connect (server_, &MessageServer::decodes_cleared, dock, &ClientWidget::decodes_cleared);
|
||||
connect (dock, &ClientWidget::do_clear_decodes, server_, &MessageServer::clear_decodes);
|
||||
connect (dock, &ClientWidget::do_close, server_, &MessageServer::close);
|
||||
connect (dock, &ClientWidget::do_reply, decodes_model_, &DecodesModel::do_reply);
|
||||
connect (dock, &ClientWidget::do_halt_tx, server_, &MessageServer::halt_tx);
|
||||
connect (dock, &ClientWidget::do_free_text, server_, &MessageServer::free_text);
|
||||
@ -257,6 +258,7 @@ void MessageAggregatorMainWindow::add_client (QString const& id, QString const&
|
||||
connect (view_action, &QAction::toggled, dock, &ClientWidget::setVisible);
|
||||
connect (dock, &ClientWidget::highlight_callsign, server_, &MessageServer::highlight_callsign);
|
||||
connect (dock, &ClientWidget::switch_configuration, server_, &MessageServer::switch_configuration);
|
||||
connect (dock, &ClientWidget::configure, server_, &MessageServer::configure);
|
||||
dock_widgets_[id] = dock;
|
||||
server_->replay (id); // request decodes and status
|
||||
}
|
||||
@ -266,7 +268,7 @@ void MessageAggregatorMainWindow::remove_client (QString const& id)
|
||||
auto iter = dock_widgets_.find (id);
|
||||
if (iter != std::end (dock_widgets_))
|
||||
{
|
||||
(*iter)->close ();
|
||||
(*iter)->dispose ();
|
||||
dock_widgets_.erase (iter);
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,8 @@ public:
|
||||
, bool /*transmitting*/, bool /*decoding*/, qint32 /*rx_df*/, qint32 /*tx_df*/
|
||||
, QString const& /*de_call*/, QString const& /*de_grid*/, QString const& /*dx_grid*/
|
||||
, bool /* watchdog_timeout */, QString const& sub_mode, bool /*fast_mode*/
|
||||
, quint8 /*special_op_mode*/, QString const& /*configuration_name*/)
|
||||
, quint8 /*special_op_mode*/, quint32 /*frequency_tolerance*/, quint32 /*tr_period*/
|
||||
, QString const& /*configuration_name*/)
|
||||
{
|
||||
if (id == id_)
|
||||
{
|
||||
|
@ -17,3 +17,17 @@ QValidator::State RestrictedSpinBox::validate (QString& input, int& pos) const
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
void RestrictedSpinBox::fixup (QString& input) const
|
||||
{
|
||||
auto iter = std::lower_bound (values ().begin (), values ().end (), valueFromText (input));
|
||||
HintedSpinBox::fixup (input);
|
||||
if (iter != values ().end ())
|
||||
{
|
||||
input = textFromValue (*iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
input = textFromValue (values ().back ());
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ public:
|
||||
protected:
|
||||
// override the base class validation
|
||||
QValidator::State validate (QString& input, int& pos) const override;
|
||||
void fixup (QString& input) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <fftw3.h>
|
||||
#include <QApplication>
|
||||
#include <QStringListModel>
|
||||
#include <QSettings>
|
||||
#include <QKeyEvent>
|
||||
@ -201,6 +202,7 @@ namespace
|
||||
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>;]*"};
|
||||
// grid exact match excluding RR73
|
||||
QRegularExpression grid_regexp {"\\A(?![Rr]{2}73)[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}\\z"};
|
||||
auto quint32_max = std::numeric_limits<quint32>::max ();
|
||||
|
||||
bool message_is_73 (int type, QStringList const& msg_parts)
|
||||
{
|
||||
@ -410,7 +412,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
m_config.udp_server_name (), m_config.udp_server_port (),
|
||||
this}},
|
||||
psk_Reporter {new PSK_Reporter {m_messageClient, this}},
|
||||
m_manual {&m_network_manager}
|
||||
m_manual {&m_network_manager},
|
||||
m_block_udp_status_updates {false}
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setUnifiedTitleAndToolBarOnMac (true);
|
||||
@ -501,6 +504,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
});
|
||||
|
||||
// Network message handlers
|
||||
m_messageClient->enable (m_config.accept_udp_requests ());
|
||||
connect (m_messageClient, &MessageClient::clear_decodes, [this] (quint8 window) {
|
||||
++window;
|
||||
if (window & 1)
|
||||
@ -513,54 +517,51 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
}
|
||||
});
|
||||
connect (m_messageClient, &MessageClient::reply, this, &MainWindow::replyToCQ);
|
||||
connect (m_messageClient, &MessageClient::close, this, &MainWindow::close);
|
||||
connect (m_messageClient, &MessageClient::replay, this, &MainWindow::replayDecodes);
|
||||
connect (m_messageClient, &MessageClient::location, this, &MainWindow::locationChange);
|
||||
connect (m_messageClient, &MessageClient::halt_tx, [this] (bool auto_only) {
|
||||
if (m_config.accept_udp_requests ()) {
|
||||
if (auto_only) {
|
||||
if (ui->autoButton->isChecked ()) {
|
||||
ui->autoButton->click();
|
||||
}
|
||||
} else {
|
||||
ui->stopTxButton->click();
|
||||
if (auto_only) {
|
||||
if (ui->autoButton->isChecked ()) {
|
||||
ui->autoButton->click();
|
||||
}
|
||||
} else {
|
||||
ui->stopTxButton->click();
|
||||
}
|
||||
});
|
||||
connect (m_messageClient, &MessageClient::error, this, &MainWindow::networkError);
|
||||
connect (m_messageClient, &MessageClient::free_text, [this] (QString const& text, bool send) {
|
||||
if (m_config.accept_udp_requests ()) {
|
||||
tx_watchdog (false);
|
||||
// send + non-empty text means set and send the free text
|
||||
// message, !send + non-empty text means set the current free
|
||||
// text message, send + empty text means send the current free
|
||||
// text message without change, !send + empty text means clear
|
||||
// the current free text message
|
||||
if (0 == ui->tabWidget->currentIndex ()) {
|
||||
if (!text.isEmpty ()) {
|
||||
ui->tx5->setCurrentText (text);
|
||||
}
|
||||
if (send) {
|
||||
ui->txb5->click ();
|
||||
} else if (text.isEmpty ()) {
|
||||
ui->tx5->setCurrentText (text);
|
||||
}
|
||||
} else if (1 == ui->tabWidget->currentIndex ()) {
|
||||
if (!text.isEmpty ()) {
|
||||
ui->freeTextMsg->setCurrentText (text);
|
||||
}
|
||||
if (send) {
|
||||
ui->rbFreeText->click ();
|
||||
} else if (text.isEmpty ()) {
|
||||
ui->freeTextMsg->setCurrentText (text);
|
||||
}
|
||||
tx_watchdog (false);
|
||||
// send + non-empty text means set and send the free text
|
||||
// message, !send + non-empty text means set the current free
|
||||
// text message, send + empty text means send the current free
|
||||
// text message without change, !send + empty text means clear
|
||||
// the current free text message
|
||||
if (0 == ui->tabWidget->currentIndex ()) {
|
||||
if (!text.isEmpty ()) {
|
||||
ui->tx5->setCurrentText (text);
|
||||
}
|
||||
if (send) {
|
||||
ui->txb5->click ();
|
||||
} else if (text.isEmpty ()) {
|
||||
ui->tx5->setCurrentText (text);
|
||||
}
|
||||
} else if (1 == ui->tabWidget->currentIndex ()) {
|
||||
if (!text.isEmpty ()) {
|
||||
ui->freeTextMsg->setCurrentText (text);
|
||||
}
|
||||
if (send) {
|
||||
ui->rbFreeText->click ();
|
||||
} else if (text.isEmpty ()) {
|
||||
ui->freeTextMsg->setCurrentText (text);
|
||||
}
|
||||
QApplication::alert (this);
|
||||
}
|
||||
QApplication::alert (this);
|
||||
});
|
||||
|
||||
connect (m_messageClient, &MessageClient::highlight_callsign, ui->decodedTextBrowser, &DisplayText::highlight_callsign);
|
||||
|
||||
connect (m_messageClient, &MessageClient::switch_configuration, m_multi_settings, &MultiSettings::select_configuration);
|
||||
connect (m_messageClient, &MessageClient::configure, this, &MainWindow::remote_configure);
|
||||
|
||||
// Hook up WSPR band hopping
|
||||
connect (ui->band_hopping_schedule_push_button, &QPushButton::clicked
|
||||
@ -711,6 +712,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
connect (&m_config, &Configuration::transceiver_failure, this, &MainWindow::handle_transceiver_failure);
|
||||
connect (&m_config, &Configuration::udp_server_changed, m_messageClient, &MessageClient::set_server);
|
||||
connect (&m_config, &Configuration::udp_server_port_changed, m_messageClient, &MessageClient::set_server_port);
|
||||
connect (&m_config, &Configuration::accept_udp_requests_changed, m_messageClient, &MessageClient::enable);
|
||||
|
||||
// set up configurations menu
|
||||
connect (m_multi_settings, &MultiSettings::configurationNameChanged, [this] (QString const& name) {
|
||||
@ -905,20 +907,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
if(m_bFast9) m_bFastMode=true;
|
||||
ui->cbFast9->setChecked(m_bFast9 or m_bFastMode);
|
||||
|
||||
if(m_mode=="FT4") on_actionFT4_triggered();
|
||||
if(m_mode=="FT8") on_actionFT8_triggered();
|
||||
if(m_mode=="JT4") on_actionJT4_triggered();
|
||||
if(m_mode=="JT9") on_actionJT9_triggered();
|
||||
if(m_mode=="JT65") on_actionJT65_triggered();
|
||||
if(m_mode=="JT9+JT65") on_actionJT9_JT65_triggered();
|
||||
if(m_mode=="WSPR") on_actionWSPR_triggered();
|
||||
if(m_mode=="WSPR-LF") on_actionWSPR_LF_triggered();
|
||||
if(m_mode=="ISCAT") on_actionISCAT_triggered();
|
||||
if(m_mode=="MSK144") on_actionMSK144_triggered();
|
||||
if(m_mode=="QRA64") on_actionQRA64_triggered();
|
||||
if(m_mode=="Echo") on_actionEcho_triggered();
|
||||
set_mode (m_mode);
|
||||
if(m_mode=="Echo") monitor(false); //Don't auto-start Monitor in Echo mode.
|
||||
if(m_mode=="FreqCal") on_actionFreqCal_triggered();
|
||||
|
||||
ui->sbSubmode->setValue (vhf ? m_nSubMode : 0);
|
||||
if(m_mode=="MSK144") {
|
||||
@ -1762,19 +1752,7 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog
|
||||
bool b = vhf && (m_mode=="JT4" or m_mode=="JT65" or m_mode=="ISCAT" or
|
||||
m_mode=="JT9" or m_mode=="MSK144" or m_mode=="QRA64");
|
||||
if(b) VHF_features_enabled(b);
|
||||
if(m_mode=="FT4") on_actionFT4_triggered();
|
||||
if(m_mode=="FT8") on_actionFT8_triggered();
|
||||
if(m_mode=="JT4") on_actionJT4_triggered();
|
||||
if(m_mode=="JT9") on_actionJT9_triggered();
|
||||
if(m_mode=="JT9+JT65") on_actionJT9_JT65_triggered();
|
||||
if(m_mode=="JT65") on_actionJT65_triggered();
|
||||
if(m_mode=="QRA64") on_actionQRA64_triggered();
|
||||
if(m_mode=="FreqCal") on_actionFreqCal_triggered();
|
||||
if(m_mode=="ISCAT") on_actionISCAT_triggered();
|
||||
if(m_mode=="MSK144") on_actionMSK144_triggered();
|
||||
if(m_mode=="WSPR") on_actionWSPR_triggered();
|
||||
if(m_mode=="WSPR-LF") on_actionWSPR_LF_triggered();
|
||||
if(m_mode=="Echo") on_actionEcho_triggered();
|
||||
set_mode (m_mode);
|
||||
if(b) VHF_features_enabled(b);
|
||||
|
||||
m_config.transceiver_online ();
|
||||
@ -7190,6 +7168,7 @@ void MainWindow::transmitDisplay (bool transmitting)
|
||||
void MainWindow::on_sbFtol_valueChanged(int value)
|
||||
{
|
||||
m_wideGraph->setTol (value);
|
||||
statusUpdate ();
|
||||
}
|
||||
|
||||
void::MainWindow::VHF_features_enabled(bool b)
|
||||
@ -7227,6 +7206,7 @@ void MainWindow::on_sbTR_valueChanged(int value)
|
||||
if(m_transmitting) {
|
||||
on_stopTxButton_clicked();
|
||||
}
|
||||
statusUpdate ();
|
||||
}
|
||||
|
||||
QChar MainWindow::current_submode () const
|
||||
@ -7328,11 +7308,6 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de
|
||||
, QString const& mode, QString const& message_text
|
||||
, bool /*low_confidence*/, quint8 modifiers)
|
||||
{
|
||||
if (!m_config.accept_udp_requests ())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString format_string {"%1 %2 %3 %4 %5 %6"};
|
||||
auto const& time_string = time.toString ("~" == mode || "&" == mode
|
||||
|| "+" == mode ? "hhmmss" : "hhmm");
|
||||
@ -7901,8 +7876,18 @@ void MainWindow::on_cbCQTx_toggled(bool b)
|
||||
|
||||
void MainWindow::statusUpdate () const
|
||||
{
|
||||
if (!ui) return;
|
||||
if (!ui || m_block_udp_status_updates) return;
|
||||
auto submode = current_submode ();
|
||||
auto ftol = ui->sbFtol->value ();
|
||||
if (!(ui->sbFtol->isVisible () && ui->sbFtol->isEnabled ()))
|
||||
{
|
||||
ftol = quint32_max;
|
||||
}
|
||||
auto tr_period = ui->sbTR->value ();
|
||||
if (!(ui->sbTR->isVisible () && ui->sbTR->isEnabled ()))
|
||||
{
|
||||
tr_period = quint32_max;
|
||||
}
|
||||
m_messageClient->status_update (m_freqNominal, m_mode, m_hisCall,
|
||||
QString::number (ui->rptSpinBox->value ()),
|
||||
m_modeTx, ui->autoButton->isChecked (),
|
||||
@ -7912,7 +7897,7 @@ void MainWindow::statusUpdate () const
|
||||
m_hisGrid, m_tx_watchdog,
|
||||
submode != QChar::Null ? QString {submode} : QString {}, m_bFastMode,
|
||||
static_cast<quint8> (m_config.special_op_id ()),
|
||||
m_multi_settings->configuration_name ());
|
||||
ftol, tr_period, m_multi_settings->configuration_name ());
|
||||
}
|
||||
|
||||
void MainWindow::childEvent (QChildEvent * e)
|
||||
@ -8754,3 +8739,79 @@ void MainWindow::on_pbBestSP_clicked()
|
||||
if(!m_bBestSPArmed) ui->pbBestSP->setStyleSheet ("");
|
||||
if(m_bBestSPArmed) m_dateTimeBestSP=QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
|
||||
void MainWindow::set_mode (QString const& mode)
|
||||
{
|
||||
if ("FT4" == mode) on_actionFT4_triggered ();
|
||||
else if ("FT8" == mode) on_actionFT8_triggered ();
|
||||
else if ("JT4" == mode) on_actionJT4_triggered ();
|
||||
else if ("JT9" == mode) on_actionJT9_triggered ();
|
||||
else if ("JT9+JT65" == mode) on_actionJT9_JT65_triggered ();
|
||||
else if ("JT65" == mode) on_actionJT65_triggered ();
|
||||
else if ("QRA64" == mode) on_actionQRA64_triggered ();
|
||||
else if ("FreqCal" == mode) on_actionFreqCal_triggered ();
|
||||
else if ("ISCAT" == mode) on_actionISCAT_triggered ();
|
||||
else if ("MSK144" == mode) on_actionMSK144_triggered ();
|
||||
else if ("WSPR" == mode) on_actionWSPR_triggered ();
|
||||
else if ("WSPR-LF" == mode) on_actionWSPR_LF_triggered ();
|
||||
else if ("Echo" == mode) on_actionEcho_triggered ();
|
||||
}
|
||||
|
||||
void MainWindow::remote_configure (QString const& mode, quint32 frequency_tolerance
|
||||
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
|
||||
, QString const& dx_call, QString const& dx_grid, bool generate_messages)
|
||||
{
|
||||
if (mode.size ())
|
||||
{
|
||||
set_mode (mode);
|
||||
}
|
||||
if (frequency_tolerance != quint32_max && ui->sbFtol->isVisible ())
|
||||
{
|
||||
ui->sbFtol->setValue (frequency_tolerance);
|
||||
}
|
||||
if (submode.size () && ui->sbSubmode->isVisible ())
|
||||
{
|
||||
ui->sbSubmode->setValue (submode.toUpper ().at (0).toLatin1 () - 'A');
|
||||
}
|
||||
if (ui->cbFast9->isVisible () && ui->cbFast9->isChecked () != fast_mode)
|
||||
{
|
||||
ui->cbFast9->click ();
|
||||
}
|
||||
if (tr_period != quint32_max && ui->sbTR->isVisible ())
|
||||
{
|
||||
ui->sbTR->setValue (tr_period);
|
||||
ui->sbTR->interpretText ();
|
||||
}
|
||||
if (rx_df != quint32_max && ui->RxFreqSpinBox->isVisible ())
|
||||
{
|
||||
m_block_udp_status_updates = true;
|
||||
ui->RxFreqSpinBox->setValue (rx_df);
|
||||
ui->RxFreqSpinBox->interpretText ();
|
||||
m_block_udp_status_updates = false;
|
||||
}
|
||||
if (dx_call.size () && ui->dxCallEntry->isVisible ())
|
||||
{
|
||||
ui->dxCallEntry->setText (dx_call);
|
||||
}
|
||||
if (dx_grid.size () && ui->dxGridEntry->isVisible ())
|
||||
{
|
||||
ui->dxGridEntry->setText (dx_grid);
|
||||
}
|
||||
if (generate_messages && ui->genStdMsgsPushButton->isVisible ())
|
||||
{
|
||||
ui->genStdMsgsPushButton->click ();
|
||||
}
|
||||
if (m_config.udpWindowToFront ())
|
||||
{
|
||||
show ();
|
||||
raise ();
|
||||
activateWindow ();
|
||||
}
|
||||
if (m_config.udpWindowRestore () && isMinimized ())
|
||||
{
|
||||
showNormal ();
|
||||
raise ();
|
||||
}
|
||||
tx_watchdog (false);
|
||||
QApplication::alert (this);
|
||||
}
|
||||
|
@ -313,6 +313,9 @@ private slots:
|
||||
void on_pbBestSP_clicked();
|
||||
int setTxMsg(int n);
|
||||
bool stdCall(QString const& w);
|
||||
void remote_configure (QString const& mode, quint32 frequency_tolerance, QString const& submode
|
||||
, bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call
|
||||
, QString const& dx_grid, bool generate_messages);
|
||||
|
||||
private:
|
||||
Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo,
|
||||
@ -339,6 +342,7 @@ private:
|
||||
Q_SIGNAL void toggleShorthand () const;
|
||||
|
||||
private:
|
||||
void set_mode (QString const& mode);
|
||||
void astroUpdate ();
|
||||
void writeAllTxt(QString message);
|
||||
void auto_sequence (DecodedText const& message, unsigned start_tolerance, unsigned stop_tolerance);
|
||||
@ -680,6 +684,7 @@ private:
|
||||
QHash<QString, QVariant> m_pwrBandTuneMemory; // Remembers power level by band for tuning
|
||||
QByteArray m_geometryNoControls;
|
||||
QVector<double> m_phaseEqCoefficients;
|
||||
bool m_block_udp_status_updates;
|
||||
|
||||
//---------------------------------------------------- private functions
|
||||
void readSettings();
|
||||
|
Loading…
Reference in New Issue
Block a user