mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-21 19:55:20 -05:00
Added UDP replies to halt Tx and set free text message
Also added Tx status to status UDP message. Added the above features to the reference UDP server message_aggregator. Merged from the wsjtx-1.5 branch. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5334 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
1deffffe7f
commit
3b3ef37848
@ -402,6 +402,10 @@ set (all_C_and_CXXSRCS
|
||||
${all_CXXSRCS}
|
||||
)
|
||||
|
||||
set (message_aggregator_STYLESHEETS
|
||||
qss/default.qss
|
||||
)
|
||||
|
||||
set (TOP_LEVEL_RESOURCES
|
||||
shortcuts.txt
|
||||
mouse_commands.txt
|
||||
@ -890,9 +894,13 @@ set_target_properties (wsjtx PROPERTIES
|
||||
target_link_libraries (wsjtx wsjt_fort wsjt_cxx wsjt_qt ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
qt5_use_modules (wsjtx Widgets OpenGL Network Multimedia SerialPort)
|
||||
|
||||
add_resources (message_aggregator_RESOURCES /qss ${message_aggregator_STYLESHEETS})
|
||||
configure_file (message_aggregator.qrc.in message_aggregator.qrc @ONLY)
|
||||
qt5_add_resources (message_aggregator_RESOURCES_RCC ${CMAKE_BINARY_DIR}/message_aggregator.qrc)
|
||||
add_executable (message_aggregator
|
||||
${message_aggregator_CXXSRCS}
|
||||
wsjtx.rc
|
||||
${message_aggregator_RESOURCES_RCC}
|
||||
)
|
||||
target_link_libraries (message_aggregator wsjt_qt)
|
||||
qt5_use_modules (message_aggregator Widgets OpenGL Network)
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <exception>
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QFile>
|
||||
#include <QStandardItemModel>
|
||||
#include <QStandardItem>
|
||||
#include <QSortFilterProxyModel>
|
||||
@ -51,6 +52,8 @@
|
||||
using port_type = MessageServer::port_type;
|
||||
using Frequency = MessageServer::Frequency;
|
||||
|
||||
QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
|
||||
|
||||
//
|
||||
// Decodes Model - simple data model for all decodes
|
||||
//
|
||||
@ -191,6 +194,8 @@ public:
|
||||
: QDockWidget {id, parent}
|
||||
, id_ {id}
|
||||
, decodes_table_view_ {new QTableView}
|
||||
, message_line_edit_ {new QLineEdit}
|
||||
, halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}}
|
||||
, mode_label_ {new QLabel}
|
||||
, dx_call_label_ {new QLabel}
|
||||
, frequency_label_ {new QLabel}
|
||||
@ -207,6 +212,21 @@ public:
|
||||
decodes_table_view_->hideColumn (0);
|
||||
content_layout->addWidget (decodes_table_view_);
|
||||
|
||||
// set up controls
|
||||
auto control_layout = new QHBoxLayout;
|
||||
auto form_layout = new QFormLayout;
|
||||
form_layout->addRow (tr ("Free text:"), message_line_edit_);
|
||||
message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this});
|
||||
connect (message_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
Q_EMIT do_free_text (id_, message_line_edit_->text ());
|
||||
});
|
||||
control_layout->addLayout (form_layout);
|
||||
control_layout->addWidget (halt_tx_button_);
|
||||
connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||
Q_EMIT do_halt_tx (id_);
|
||||
});
|
||||
content_layout->addLayout (control_layout);
|
||||
|
||||
// set up status area
|
||||
auto status_bar = new QStatusBar;
|
||||
status_bar->addPermanentWidget (mode_label_);
|
||||
@ -232,7 +252,7 @@ public:
|
||||
}
|
||||
|
||||
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode)
|
||||
, QString const& report, QString const& tx_mode, bool transmitting)
|
||||
{
|
||||
if (id == id_)
|
||||
{
|
||||
@ -240,6 +260,8 @@ public:
|
||||
dx_call_label_->setText ("DX CALL: " + dx_call);
|
||||
frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f));
|
||||
report_label_->setText ("SNR: " + report);
|
||||
update_dynamic_property (frequency_label_, "transmitting", transmitting);
|
||||
halt_tx_button_->setEnabled (transmitting);
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,6 +278,8 @@ public:
|
||||
}
|
||||
|
||||
Q_SIGNAL void do_reply (QModelIndex const&);
|
||||
Q_SIGNAL void do_halt_tx (QString const& id);
|
||||
Q_SIGNAL void do_free_text (QString const& id, QString const& text);
|
||||
|
||||
private:
|
||||
class DecodesFilterModel final
|
||||
@ -280,6 +304,9 @@ private:
|
||||
|
||||
QString id_;
|
||||
QTableView * decodes_table_view_;
|
||||
QLineEdit * message_line_edit_;
|
||||
QAbstractButton * set_free_text_button_;
|
||||
QAbstractButton * halt_tx_button_;
|
||||
QLabel * mode_label_;
|
||||
QLabel * dx_call_label_;
|
||||
QLabel * frequency_label_;
|
||||
@ -406,6 +433,8 @@ private:
|
||||
connect (server_, &MessageServer::status_update, dock, &ClientWidget::update_status);
|
||||
connect (server_, &MessageServer::decode, dock, &ClientWidget::decode_added);
|
||||
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);
|
||||
connect (view_action, &QAction::toggled, dock, &ClientWidget::setVisible);
|
||||
dock_widgets_[id] = dock;
|
||||
server_->replay (id);
|
||||
@ -444,6 +473,15 @@ int main (int argc, char * argv[])
|
||||
app.setApplicationName ("WSJT-X Reference UDP Message Aggregator Server");
|
||||
app.setApplicationVersion ("1.0");
|
||||
|
||||
{
|
||||
QFile file {":/qss/default.qss"};
|
||||
if (!file.open (QFile::ReadOnly))
|
||||
{
|
||||
throw_qstring ("failed to open \"" + file.fileName () + "\": " + file.errorString ());
|
||||
}
|
||||
app.setStyleSheet (file.readAll());
|
||||
}
|
||||
|
||||
MainWindow window;
|
||||
return app.exec ();
|
||||
}
|
||||
|
@ -123,6 +123,22 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
||||
}
|
||||
break;
|
||||
|
||||
case NetworkMessage::HaltTx:
|
||||
if (check_status (in))
|
||||
{
|
||||
Q_EMIT self_->halt_tx ();
|
||||
}
|
||||
break;
|
||||
|
||||
case NetworkMessage::FreeText:
|
||||
if (check_status (in))
|
||||
{
|
||||
QByteArray message;
|
||||
in >> message;
|
||||
Q_EMIT self_->free_text (QString::fromUtf8 (message));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
@ -235,13 +251,14 @@ void MessageClient::send_raw_datagram (QByteArray const& message, QHostAddress c
|
||||
}
|
||||
|
||||
void MessageClient::status_update (Frequency f, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode)
|
||||
, QString const& report, QString const& tx_mode, bool transmitting)
|
||||
{
|
||||
if (m_->server_port_ && !m_->server_.isNull ())
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Status, m_->id_};
|
||||
out << f << mode.toUtf8 () << dx_call.toUtf8 () << report.toUtf8 () << tx_mode.toUtf8 ();
|
||||
out << f << mode.toUtf8 () << dx_call.toUtf8 () << report.toUtf8 () << tx_mode.toUtf8 ()
|
||||
<< transmitting;
|
||||
if (m_->check_status (out))
|
||||
{
|
||||
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
|
||||
// outgoing messages
|
||||
Q_SLOT void status_update (Frequency, QString const& mode, QString const& dx_call, QString const& report
|
||||
, QString const& tx_mode);
|
||||
, QString const& tx_mode, bool transmitting);
|
||||
Q_SLOT void decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
|
||||
, QString const& mode, QString const& message);
|
||||
Q_SLOT void clear_decodes ();
|
||||
@ -69,6 +69,14 @@ public:
|
||||
// all decodes
|
||||
Q_SIGNAL void replay ();
|
||||
|
||||
// this signal is emitted if the server has requested transmission
|
||||
// to halt immediately
|
||||
Q_SIGNAL void halt_tx ();
|
||||
|
||||
// this signal is emitted if the server has requested a new free
|
||||
// message text
|
||||
Q_SIGNAL void free_text (QString const&);
|
||||
|
||||
// this signal is emitted when network errors occur or if a host
|
||||
// lookup fails
|
||||
Q_SIGNAL void error (QString const&) const;
|
||||
|
@ -142,11 +142,13 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
QByteArray dx_call;
|
||||
QByteArray report;
|
||||
QByteArray tx_mode;
|
||||
in >> f >> mode >> dx_call >> report >> tx_mode;
|
||||
bool transmitting;
|
||||
in >> f >> mode >> dx_call >> report >> tx_mode >> transmitting;
|
||||
if (check_status (in))
|
||||
{
|
||||
Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call)
|
||||
, QString::fromUtf8 (report), QString::fromUtf8 (tx_mode));
|
||||
, QString::fromUtf8 (report), QString::fromUtf8 (tx_mode)
|
||||
, transmitting);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -313,3 +315,32 @@ void MessageServer::replay (QString const& id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::halt_tx (QString const& id)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, id};
|
||||
if (m_->check_status (out))
|
||||
{
|
||||
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::free_text (QString const& id, QString const& text)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::FreeText, id};
|
||||
out << text.toUtf8 ();
|
||||
if (m_->check_status (out))
|
||||
{
|
||||
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,11 +48,17 @@ public:
|
||||
// ask the client with identification 'id' to replay all decodes
|
||||
Q_SLOT void replay (QString const& id);
|
||||
|
||||
// ask the client with identification 'id' to halt transmitting immediately
|
||||
Q_SLOT void halt_tx (QString const& id);
|
||||
|
||||
// ask the client with identification 'id' to set the free text message
|
||||
Q_SLOT void free_text (QString const& id, QString const& text);
|
||||
|
||||
// the following signals are emitted when a client broadcasts the
|
||||
// matching message
|
||||
Q_SIGNAL void client_opened (QString const& id);
|
||||
Q_SIGNAL void status_update (QString const& id, Frequency, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode);
|
||||
, QString const& report, QString const& tx_mode, bool transmitting);
|
||||
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);
|
||||
|
@ -43,6 +43,12 @@
|
||||
* serialization purposes (currently a quint32 size followed by size
|
||||
* bytes, no terminator is present or counted).
|
||||
*
|
||||
* The QDataStream format document linked above is not complete for
|
||||
* the QByteArray serialization format, it is similar to the QString
|
||||
* serialization format in that it differentiates between empty
|
||||
* strings and null strings. Empty strings have a length of zero
|
||||
* whereas null strings have a length field of 0xffffffff.
|
||||
*
|
||||
* Schema Version 1:
|
||||
* -----------------
|
||||
*
|
||||
@ -58,6 +64,7 @@
|
||||
* DX call utf8
|
||||
* Report utf8
|
||||
* Tx Mode utf8
|
||||
* Transmitting bool
|
||||
*
|
||||
* Decode Out 2 quint32
|
||||
* Id (unique key) utf8
|
||||
@ -99,6 +106,13 @@
|
||||
*
|
||||
* Replay In 7 quint32
|
||||
* Id (unique key) utf8
|
||||
*
|
||||
* Halt Tx In 8
|
||||
* Id (unique key) utf8
|
||||
*
|
||||
* Free Text In 9
|
||||
* Id (unique key) utf8
|
||||
* Text utf8
|
||||
*/
|
||||
|
||||
#include <QDataStream>
|
||||
@ -122,6 +136,8 @@ namespace NetworkMessage
|
||||
QSOLogged,
|
||||
Close,
|
||||
Replay,
|
||||
HaltTx,
|
||||
FreeText,
|
||||
maximum_message_type_ // ONLY add new message types
|
||||
// immediately before here
|
||||
};
|
||||
|
@ -187,11 +187,19 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
|
||||
connect (m_logDlg.data (), &LogQSO::acceptQSO, this, &MainWindow::acceptQSO2);
|
||||
connect (this, &MainWindow::finished, m_logDlg.data (), &LogQSO::close);
|
||||
|
||||
|
||||
// Network message handlers
|
||||
connect (m_messageClient, &MessageClient::reply, this, &MainWindow::replyToCQ);
|
||||
connect (m_messageClient, &MessageClient::replay, this, &MainWindow::replayDecodes);
|
||||
connect (m_messageClient, &MessageClient::halt_tx, ui->stopTxButton, &QAbstractButton::click);
|
||||
connect (m_messageClient, &MessageClient::error, this, &MainWindow::networkError);
|
||||
connect (m_messageClient, &MessageClient::free_text, [this] (QString const& text) {
|
||||
if (0 == ui->tabWidget->currentIndex ()) {
|
||||
ui->tx5->setCurrentText (text);
|
||||
ui->txrb5->click ();
|
||||
} else {
|
||||
ui->freeTextMsg->setCurrentText (text);
|
||||
ui->rbFreeText->click ();
|
||||
}});
|
||||
|
||||
on_EraseButton_clicked ();
|
||||
|
||||
@ -1022,7 +1030,7 @@ void MainWindow::displayDialFrequency ()
|
||||
|
||||
void MainWindow::statusChanged()
|
||||
{
|
||||
m_messageClient->status_update (m_dialFreq, m_mode, m_hisCall, QString::number (ui->rptSpinBox->value ()), m_modeTx);
|
||||
m_messageClient->status_update (m_dialFreq, m_mode, m_hisCall, QString::number (ui->rptSpinBox->value ()), m_modeTx, m_transmitting);
|
||||
|
||||
QFile f {m_config.temp_dir ().absoluteFilePath ("wsjtx_status.txt")};
|
||||
if(f.open(QFile::WriteOnly | QIODevice::Text)) {
|
||||
@ -1865,6 +1873,7 @@ void MainWindow::guiUpdate()
|
||||
|
||||
m_transmitting = true;
|
||||
transmitDisplay (true);
|
||||
m_messageClient->status_update (m_dialFreq, m_mode, m_hisCall, QString::number (ui->rptSpinBox->value ()), m_modeTx, m_transmitting);
|
||||
}
|
||||
|
||||
if(!m_btxok && btxok0 && g_iptt==1) stopTx();
|
||||
@ -1996,6 +2005,7 @@ void MainWindow::stopTx()
|
||||
tx_status_label->setText("");
|
||||
ptt0Timer->start(200); //Sequencer delay
|
||||
monitor (true);
|
||||
m_messageClient->status_update (m_dialFreq, m_mode, m_hisCall, QString::number (ui->rptSpinBox->value ()), m_modeTx, m_transmitting);
|
||||
}
|
||||
|
||||
void MainWindow::stopTx2()
|
||||
|
5
message_aggregator.qrc.in
Normal file
5
message_aggregator.qrc.in
Normal file
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC>
|
||||
<RCC version="1.0">
|
||||
<qresource>@message_aggregator_RESOURCES@
|
||||
</qresource>
|
||||
</RCC>
|
5
qss/default.qss
Normal file
5
qss/default.qss
Normal file
@ -0,0 +1,5 @@
|
||||
/* default stylesheet for the message aggregator application */
|
||||
|
||||
[transmitting="true"] {
|
||||
background-color: yellow
|
||||
}
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QFont>
|
||||
#include <QWidget>
|
||||
#include <QStyle>
|
||||
#include <QVariant>
|
||||
|
||||
QString font_as_stylesheet (QFont const& font)
|
||||
{
|
||||
@ -24,3 +27,11 @@ QString font_as_stylesheet (QFont const& font)
|
||||
.arg (font.styleName ())
|
||||
.arg (font_weight);
|
||||
}
|
||||
|
||||
void update_dynamic_property (QWidget * widget, char const * property, QVariant const& value)
|
||||
{
|
||||
widget->setProperty (property, value);
|
||||
widget->style ()->unpolish (widget);
|
||||
widget->style ()->polish (widget);
|
||||
widget->update ();
|
||||
}
|
||||
|
@ -9,10 +9,10 @@
|
||||
#include <QMetaType>
|
||||
#include <QMetaEnum>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QHostAddress>
|
||||
#include <QHash>
|
||||
|
||||
class QVariant;
|
||||
|
||||
#define ENUM_QDATASTREAM_OPS_DECL(CLASS, ENUM) \
|
||||
QDataStream& operator << (QDataStream&, CLASS::ENUM); \
|
||||
@ -72,6 +72,10 @@ void throw_qstring (QString const& qs)
|
||||
|
||||
QString font_as_stylesheet (QFont const&);
|
||||
|
||||
// do what is necessary to change a dynamic property and trigger any
|
||||
// conditional style sheet updates
|
||||
void update_dynamic_property (QWidget *, char const * property, QVariant const& value);
|
||||
|
||||
// Register some useful Qt types with QMetaType
|
||||
Q_DECLARE_METATYPE (QHostAddress);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user