diff --git a/MessageClient.cpp b/MessageClient.cpp index 7ccfbc3ce..873ba1fd4 100644 --- a/MessageClient.cpp +++ b/MessageClient.cpp @@ -188,6 +188,18 @@ void MessageClient::impl::parse_message (QByteArray const& msg) } break; + case NetworkMessage::Clear: + { + quint8 window {0}; + in >> window; + TRACE_UDP ("Clear window:" << window); + if (check_status (in) != Fail) + { + Q_EMIT self_->clear_decodes (window); + } + } + break; + case NetworkMessage::Replay: TRACE_UDP ("Replay"); if (check_status (in) != Fail) @@ -477,7 +489,7 @@ void MessageClient::WSPR_decode (bool is_new, QTime time, qint32 snr, float delt } } -void MessageClient::clear_decodes () +void MessageClient::decodes_cleared () { if (m_->server_port_ && !m_->server_string_.isEmpty ()) { diff --git a/MessageClient.hpp b/MessageClient.hpp index 0deb1a49d..ca5f02037 100644 --- a/MessageClient.hpp +++ b/MessageClient.hpp @@ -59,7 +59,7 @@ public: Q_SLOT void WSPR_decode (bool is_new, QTime time, qint32 snr, float delta_time, Frequency , qint32 drift, QString const& callsign, QString const& grid, qint32 power , bool off_air); - Q_SLOT void clear_decodes (); + Q_SLOT void decodes_cleared (); Q_SLOT void qso_logged (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 @@ -80,6 +80,10 @@ public: // with send_raw_datagram() above) Q_SLOT void add_blocked_destination (QHostAddress const&); + // this signal is emitted if the server has requested a decode + // window clear action + Q_SIGNAL void clear_decodes (quint8 window); + // this signal is emitted if the server sends us a reply, the only // reply supported is reply to a prior CQ or QRZ message Q_SIGNAL void reply (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode diff --git a/MessageServer.cpp b/MessageServer.cpp index 491afdbdd..dadf3d984 100644 --- a/MessageServer.cpp +++ b/MessageServer.cpp @@ -224,7 +224,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s break; case NetworkMessage::Clear: - Q_EMIT self_->clear_decodes (id); + Q_EMIT self_->decodes_cleared (id); break; case NetworkMessage::Status: @@ -455,6 +455,18 @@ void MessageServer::start (port_type port, QHostAddress const& multicast_group_a } } +void MessageServer::clear_decodes (QString const& id, quint8 window) +{ + auto iter = m_->clients_.find (id); + if (iter != std::end (m_->clients_)) + { + QByteArray message; + NetworkMessage::Builder out {&message, NetworkMessage::Clear, id, (*iter).negotiated_schema_number_}; + out << window; + m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); + } +} + void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time , quint32 delta_frequency, QString const& mode , QString const& message_text, bool low_confidence, quint8 modifiers) diff --git a/MessageServer.hpp b/MessageServer.hpp index 4a6022bfd..12377bef9 100644 --- a/MessageServer.hpp +++ b/MessageServer.hpp @@ -41,6 +41,9 @@ public: Q_SLOT void start (port_type port, QHostAddress const& multicast_group_address = QHostAddress {}); + // ask the client to clear one or both of the decode windows + Q_SLOT void clear_decodes (QString const& id, quint8 window = 0); + // ask the client with identification 'id' to make the same action // as a double click on the decode would // @@ -91,7 +94,7 @@ public: , QString const& name, QDateTime time_on, QString const& operator_call , QString const& my_call, QString const& my_grid , QString const& exchange_sent, QString const& exchange_rcvd); - Q_SIGNAL void clear_decodes (QString const& id); + Q_SIGNAL void decodes_cleared (QString const& id); Q_SIGNAL void logged_ADIF (QString const& id, QByteArray const& ADIF); // this signal is emitted when a network error occurs diff --git a/NetworkMessage.hpp b/NetworkMessage.hpp index a4d9ba0d5..4783bb369 100644 --- a/NetworkMessage.hpp +++ b/NetworkMessage.hpp @@ -186,16 +186,26 @@ * back a .WAV file. * * - * Clear Out 3 quint32 + * Clear Out/In 3 quint32 * Id (unique key) utf8 + * Window quint8 (In only) * * This message is send when all prior "Decode" messages in the - * "Band activity" window have been discarded and therefore are + * "Band Activity" window have been discarded and therefore are * no long available for actioning with a "Reply" message. It is * sent when the user erases the "Band activity" window and when * WSJT-X closes down normally. The server should discard all * decode messages upon receipt of this message. * + * It may also be sent to a WSJT-X instance in which case it + * clears one or both of the "Band Activity" and "Rx Frequency" + * windows. The Window argument can be one of the following + * values: + * + * 0 - clear the "Band Activity" window (default) + * 1 - clear the "Rx Frequency" window + * 2 - clear both "Band Activity" and "Rx Frequency" windows + * * * Reply In 4 quint32 * Id (target unique key) utf8 diff --git a/UDPExamples/BeaconsModel.cpp b/UDPExamples/BeaconsModel.cpp index 8955ea26a..7ac1323a1 100644 --- a/UDPExamples/BeaconsModel.cpp +++ b/UDPExamples/BeaconsModel.cpp @@ -121,7 +121,7 @@ void BeaconsModel::add_beacon_spot (bool is_new, QString const& client_id, QTime appendRow (make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air)); } -void BeaconsModel::clear_decodes (QString const& client_id) +void BeaconsModel::decodes_cleared (QString const& client_id) { for (auto row = rowCount () - 1; row >= 0; --row) { diff --git a/UDPExamples/BeaconsModel.hpp b/UDPExamples/BeaconsModel.hpp index 977a93ccc..b089349cc 100644 --- a/UDPExamples/BeaconsModel.hpp +++ b/UDPExamples/BeaconsModel.hpp @@ -32,7 +32,7 @@ public: Q_SLOT void add_beacon_spot (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time , Frequency frequency, qint32 drift, QString const& callsign, QString const& grid , qint32 power, bool off_air); - Q_SLOT void clear_decodes (QString const& client_id); + Q_SLOT void decodes_cleared (QString const& client_id); }; #endif diff --git a/UDPExamples/ClientWidget.cpp b/UDPExamples/ClientWidget.cpp index 7423f6d81..1715670bf 100644 --- a/UDPExamples/ClientWidget.cpp +++ b/UDPExamples/ClientWidget.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "validators/MaidenheadLocatorValidator.hpp" @@ -120,6 +121,9 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod , id_ {id} , calls_of_interest_ {calls_of_interest} , decodes_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} @@ -143,6 +147,10 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod decodes_table_view_->verticalHeader ()->hide (); decodes_table_view_->hideColumn (0); decodes_table_view_->horizontalHeader ()->setStretchLastSection (true); + decodes_table_view_->setContextMenuPolicy (Qt::ActionsContextMenu); + decodes_table_view_->insertAction (nullptr, erase_action_); + 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_); @@ -171,6 +179,8 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod 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}; @@ -219,8 +229,19 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod setAllowedAreas (Qt::BottomDockWidgetArea); setFloating (true); + // connect context menu actions + connect (erase_action_, &QAction::triggered, [this] (bool /*checked*/) { + Q_EMIT do_clear_decodes (id_); + }); + connect (erase_rx_frequency_action_, &QAction::triggered, [this] (bool /*checked*/) { + Q_EMIT do_clear_decodes (id_, 1); + }); + connect (erase_both_action_, &QAction::triggered, [this] (bool /*checked*/) { + Q_EMIT do_clear_decodes (id_, 2); + }); + // connect up table view signals - connect (decodes_table_view_, &QTableView::doubleClicked, this, [this] (QModelIndex const& index) { + connect (decodes_table_view_, &QTableView::doubleClicked, [this] (QModelIndex const& index) { Q_EMIT do_reply (decodes_proxy_model_.mapToSource (index), QApplication::keyboardModifiers () >> 24); }); @@ -313,7 +334,7 @@ void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id, beacons_table_view_->scrollToBottom (); } -void ClientWidget::clear_decodes (QString const& client_id) +void ClientWidget::decodes_cleared (QString const& client_id) { if (client_id == id_) { diff --git a/UDPExamples/ClientWidget.hpp b/UDPExamples/ClientWidget.hpp index 0459ad036..22488531c 100644 --- a/UDPExamples/ClientWidget.hpp +++ b/UDPExamples/ClientWidget.hpp @@ -12,6 +12,7 @@ class QAbstractItemModel; class QModelIndex; class QColor; +class QAction; using Frequency = MessageServer::Frequency; @@ -41,8 +42,9 @@ public: , float delta_time, Frequency delta_frequency, qint32 drift , QString const& callsign, QString const& grid, qint32 power , bool off_air); - Q_SLOT void clear_decodes (QString const& client_id); + 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_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); @@ -74,6 +76,9 @@ private: QRegularExpression base_call_re_; int rx_df_; } decodes_proxy_model_; + QAction * erase_action_; + QAction * erase_rx_frequency_action_; + QAction * erase_both_action_; QTableView * decodes_table_view_; QTableView * beacons_table_view_; QLineEdit * message_line_edit_; diff --git a/UDPExamples/DecodesModel.cpp b/UDPExamples/DecodesModel.cpp index 88b071c11..6121ff31a 100644 --- a/UDPExamples/DecodesModel.cpp +++ b/UDPExamples/DecodesModel.cpp @@ -125,7 +125,7 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time , off_air, is_fast)); } -void DecodesModel::clear_decodes (QString const& client_id) +void DecodesModel::decodes_cleared (QString const& client_id) { for (auto row = rowCount () - 1; row >= 0; --row) { diff --git a/UDPExamples/DecodesModel.hpp b/UDPExamples/DecodesModel.hpp index fa51732bf..17c9ae125 100644 --- a/UDPExamples/DecodesModel.hpp +++ b/UDPExamples/DecodesModel.hpp @@ -34,7 +34,7 @@ public: Q_SLOT void add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time , quint32 delta_frequency, QString const& mode, QString const& message , bool low_confidence, bool off_air, bool is_fast); - Q_SLOT void clear_decodes (QString const& client_id); + Q_SLOT void decodes_cleared (QString const& client_id); Q_SLOT void do_reply (QModelIndex const& source, quint8 modifiers); Q_SIGNAL void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency diff --git a/UDPExamples/MessageAggregatorMainWindow.cpp b/UDPExamples/MessageAggregatorMainWindow.cpp index 0c2c51c30..e6937e6cb 100644 --- a/UDPExamples/MessageAggregatorMainWindow.cpp +++ b/UDPExamples/MessageAggregatorMainWindow.cpp @@ -181,8 +181,8 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow () }); 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::client_closed, decodes_model_, &DecodesModel::decodes_cleared); + connect (server_, &MessageServer::client_closed, beacons_model_, &BeaconsModel::decodes_cleared); connect (server_, &MessageServer::decode, [this] (bool is_new, QString const& id, QTime time , qint32 snr, float delta_time , quint32 delta_frequency, QString const& mode @@ -191,8 +191,8 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow () 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 (server_, &MessageServer::decodes_cleared, decodes_model_, &DecodesModel::decodes_cleared); + connect (server_, &MessageServer::decodes_cleared, beacons_model_, &BeaconsModel::decodes_cleared); connect (decodes_model_, &DecodesModel::reply, server_, &MessageServer::reply); // UI behaviour @@ -248,7 +248,8 @@ void MessageAggregatorMainWindow::add_client (QString const& id, QString const& 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 (server_, &MessageServer::decodes_cleared, dock, &ClientWidget::decodes_cleared); + connect (dock, &ClientWidget::do_clear_decodes, server_, &MessageServer::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); diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 5a6665716..83830fb40 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -487,6 +487,17 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, }); // Network message handlers + connect (m_messageClient, &MessageClient::clear_decodes, [this] (quint8 window) { + ++window; + if (window & 1) + { + ui->decodedTextBrowser->erase (); + } + if (window & 2) + { + ui->decodedTextBrowser2->erase (); + } + }); connect (m_messageClient, &MessageClient::reply, this, &MainWindow::replyToCQ); connect (m_messageClient, &MessageClient::replay, this, &MainWindow::replayDecodes); connect (m_messageClient, &MessageClient::location, this, &MainWindow::locationChange); @@ -3310,7 +3321,7 @@ void MainWindow::on_EraseButton_clicked () void MainWindow::band_activity_cleared () { - m_messageClient->clear_decodes (); + m_messageClient->decodes_cleared (); QFile f(m_config.temp_dir ().absoluteFilePath ("decoded.txt")); if(f.exists()) f.remove(); }