WSJT-X/UDPExamples/MessageAggregatorMainWindow.cpp
Bill Somerville 3c384f7cbb Add UDP message to set temporary Maidenhead locator
When "Auto  Grid" is  checked in  "Settings->General" UDP  messages of
type "Location" will update a temporary  DE grid square. The intent is
to  allow  an external  application  joining  the WSJT-X  UDP  message
protocol to dynamically update the DE grid during mobile operation.

This change also tidies up  some outstanding issues around logging the
operator call.

This change  adds a new UDP  message "Logged ADIF" that  is emitted in
parallel with  "QSO Logged"  messages. The new  message is  valid ADIF
file format  and contains the  logged QSO  fields. The intent  is that
basic  UDP server  applications  might already  have  ADIF log  record
capture capabilities and could use  this message to feed existing ADIF
parsing routines to log QSOs. All that should be needed is to identify
this message type and the single field is ADIF compatible ASCII.

Thanks  to  Brian,   N9ADG,  for  the  patches  that   lead  to  these
enhancements.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@8454 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
2018-02-04 22:42:35 +00:00

177 lines
8.0 KiB
C++

#include "MessageAggregatorMainWindow.hpp"
#include <QtWidgets>
#include <QDateTime>
#include "DecodesModel.hpp"
#include "BeaconsModel.hpp"
#include "ClientWidget.hpp"
using port_type = MessageServer::port_type;
namespace
{
char const * const headings[] = {
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Time On"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Time Off"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Callsign"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Grid"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Name"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Frequency"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Mode"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Sent"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Rec'd"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Power"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Operator"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "My Call"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "My Grid"),
QT_TRANSLATE_NOOP ("MessageAggregatorMainWindow", "Comments"),
};
}
MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
: log_ {new QStandardItemModel {0, 14, this}}
, decodes_model_ {new DecodesModel {this}}
, beacons_model_ {new BeaconsModel {this}}
, server_ {new MessageServer {this}}
, multicast_group_line_edit_ {new QLineEdit}
, log_table_view_ {new QTableView}
{
// logbook
int column {0};
for (auto const& heading : headings)
{
log_->setHeaderData (column++, Qt::Horizontal, tr (heading));
}
connect (server_, &MessageServer::qso_logged, this, &MessageAggregatorMainWindow::log_qso);
// menu bar
auto file_menu = menuBar ()->addMenu (tr ("&File"));
auto exit_action = new QAction {tr ("E&xit"), this};
exit_action->setShortcuts (QKeySequence::Quit);
exit_action->setToolTip (tr ("Exit the application"));
file_menu->addAction (exit_action);
connect (exit_action, &QAction::triggered, this, &MessageAggregatorMainWindow::close);
view_menu_ = menuBar ()->addMenu (tr ("&View"));
// central layout
auto central_layout = new QVBoxLayout;
// server details
auto port_spin_box = new QSpinBox;
port_spin_box->setMinimum (1);
port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
auto group_box_layout = new QFormLayout;
group_box_layout->addRow (tr ("Port number:"), port_spin_box);
group_box_layout->addRow (tr ("Multicast Group (blank for unicast server):"), multicast_group_line_edit_);
auto group_box = new QGroupBox {tr ("Server Details")};
group_box->setLayout (group_box_layout);
central_layout->addWidget (group_box);
log_table_view_->setModel (log_);
log_table_view_->verticalHeader ()->hide ();
central_layout->addWidget (log_table_view_);
// central widget
auto central_widget = new QWidget;
central_widget->setLayout (central_layout);
// main window setup
setCentralWidget (central_widget);
setDockOptions (AnimatedDocks | AllowNestedDocks | AllowTabbedDocks);
setTabPosition (Qt::BottomDockWidgetArea, QTabWidget::North);
// connect up server
connect (server_, &MessageServer::error, [this] (QString const& message) {
QMessageBox::warning (this, QApplication::applicationName (), tr ("Network Error"), message);
});
connect (server_, &MessageServer::client_opened, this, &MessageAggregatorMainWindow::add_client);
connect (server_, &MessageServer::client_closed, this, &MessageAggregatorMainWindow::remove_client);
connect (server_, &MessageServer::client_closed, decodes_model_, &DecodesModel::clear_decodes);
connect (server_, &MessageServer::client_closed, beacons_model_, &BeaconsModel::clear_decodes);
connect (server_, &MessageServer::decode, [this] (bool is_new, QString const& id, QTime time
, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode
, QString const& message, bool low_confidence
, bool off_air) {
decodes_model_->add_decode (is_new, id, time, snr, delta_time, delta_frequency, mode, message
, low_confidence, off_air, dock_widgets_[id]->fast_mode ());});
connect (server_, &MessageServer::WSPR_decode, beacons_model_, &BeaconsModel::add_beacon_spot);
connect (server_, &MessageServer::clear_decodes, decodes_model_, &DecodesModel::clear_decodes);
connect (server_, &MessageServer::clear_decodes, beacons_model_, &BeaconsModel::clear_decodes);
connect (decodes_model_, &DecodesModel::reply, server_, &MessageServer::reply);
// UI behaviour
connect (port_spin_box, static_cast<void (QSpinBox::*)(int)> (&QSpinBox::valueChanged)
, [this] (port_type port) {server_->start (port);});
connect (multicast_group_line_edit_, &QLineEdit::editingFinished, [this, port_spin_box] () {
server_->start (port_spin_box->value (), QHostAddress {multicast_group_line_edit_->text ()});
});
port_spin_box->setValue (2237); // start up in unicast mode
show ();
}
void MessageAggregatorMainWindow::log_qso (QString const& /*id*/, QDateTime time_off, QString const& dx_call
, QString const& dx_grid, Frequency dial_frequency, QString const& mode
, QString const& report_sent, QString const& report_received
, QString const& tx_power, QString const& comments
, QString const& name, QDateTime time_on, QString const& operator_call
, QString const& my_call, QString const& my_grid)
{
QList<QStandardItem *> row;
row << new QStandardItem {time_on.toString ("dd-MMM-yyyy hh:mm:ss")}
<< new QStandardItem {time_off.toString ("dd-MMM-yyyy hh:mm:ss")}
<< new QStandardItem {dx_call}
<< new QStandardItem {dx_grid}
<< new QStandardItem {name}
<< new QStandardItem {Radio::frequency_MHz_string (dial_frequency)}
<< new QStandardItem {mode}
<< new QStandardItem {report_sent}
<< new QStandardItem {report_received}
<< new QStandardItem {tx_power}
<< new QStandardItem {operator_call}
<< new QStandardItem {my_call}
<< new QStandardItem {my_grid}
<< new QStandardItem {comments};
log_->appendRow (row);
log_table_view_->resizeColumnsToContents ();
log_table_view_->horizontalHeader ()->setStretchLastSection (true);
log_table_view_->scrollToBottom ();
}
void MessageAggregatorMainWindow::add_client (QString const& id, QString const& version, QString const& revision)
{
auto dock = new ClientWidget {decodes_model_, beacons_model_, id, version, revision, this};
dock->setAttribute (Qt::WA_DeleteOnClose);
auto view_action = dock->toggleViewAction ();
view_action->setEnabled (true);
view_menu_->addAction (view_action);
addDockWidget (Qt::BottomDockWidgetArea, dock);
connect (server_, &MessageServer::status_update, dock, &ClientWidget::update_status);
connect (server_, &MessageServer::decode, dock, &ClientWidget::decode_added);
connect (server_, &MessageServer::WSPR_decode, dock, &ClientWidget::beacon_spot_added);
connect (server_, &MessageServer::clear_decodes, dock, &ClientWidget::clear_decodes);
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 (dock, &ClientWidget::location, server_, &MessageServer::location);
connect (view_action, &QAction::toggled, dock, &ClientWidget::setVisible);
dock_widgets_[id] = dock;
server_->replay (id);
}
void MessageAggregatorMainWindow::remove_client (QString const& id)
{
auto iter = dock_widgets_.find (id);
if (iter != std::end (dock_widgets_))
{
(*iter)->close ();
dock_widgets_.erase (iter);
}
}
#include "moc_MessageAggregatorMainWindow.cpp"