| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | #include "ClientWidget.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | #include <limits>
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | #include <QRegExp>
 | 
					
						
							|  |  |  | #include <QColor>
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | #include <QtWidgets>
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  | #include <QAction>
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | #include <QDebug>
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-07 17:49:45 +00:00
										 |  |  | #include "validators/MaidenheadLocatorValidator.hpp"
 | 
					
						
							| 
									
										
										
										
											2018-02-04 22:42:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   //QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
 | 
					
						
							|  |  |  |   QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"}; | 
					
						
							| 
									
										
										
										
											2016-06-09 23:39:48 +00:00
										 |  |  |   QRegularExpression cq_re {"(CQ|CQDX|QRZ)[^A-Z0-9/]+"}; | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   QRegExpValidator message_validator {message_alphabet}; | 
					
						
							|  |  |  |   MaidenheadLocatorValidator locator_validator; | 
					
						
							|  |  |  |   quint32 quint32_max {std::numeric_limits<quint32>::max ()}; | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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 (); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id, QObject * parent) | 
					
						
							|  |  |  |   : QSortFilterProxyModel {parent} | 
					
						
							|  |  |  |   , client_id_ {client_id} | 
					
						
							|  |  |  |   , rx_df_ (quint32_max) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QVariant ClientWidget::IdFilterModel::data (QModelIndex const& proxy_index, int role) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (role == Qt::BackgroundRole) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       switch (proxy_index.column ()) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-09-22 22:08:41 +00:00
										 |  |  |         case 8:                 // message
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |           { | 
					
						
							|  |  |  |             auto message = QSortFilterProxyModel::data (proxy_index).toString (); | 
					
						
							|  |  |  |             if (base_call_re_.pattern ().size () | 
					
						
							|  |  |  |                 && message.contains (base_call_re_)) | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 return QColor {255,200,200}; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             if (message.contains (cq_re)) | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 return QColor {200, 255, 200}; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case 4:                 // DF
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |           if (qAbs (QSortFilterProxyModel::data (proxy_index).toUInt () - rx_df_) <= 10) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |             { | 
					
						
							|  |  |  |               return QColor {255, 200, 200}; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return QSortFilterProxyModel::data (proxy_index, role); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ClientWidget::IdFilterModel::filterAcceptsRow (int source_row | 
					
						
							|  |  |  |                                                     , QModelIndex const& source_parent) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto source_index_col0 = sourceModel ()->index (source_row, 0, source_parent); | 
					
						
							|  |  |  |   return sourceModel ()->data (source_index_col0).toString () == client_id_; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ClientWidget::IdFilterModel::de_call (QString const& call) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (call != call_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       beginResetModel (); | 
					
						
							|  |  |  |       if (call.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           base_call_re_.setPattern ("[^A-Z0-9]*" + Radio::base_callsign (call) + "[^A-Z0-9]*"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           base_call_re_.setPattern (QString {}); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       call_ = call; | 
					
						
							|  |  |  |       endResetModel (); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | void ClientWidget::IdFilterModel::rx_df (quint32 df) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   if (df != rx_df_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       beginResetModel (); | 
					
						
							|  |  |  |       rx_df_ = df; | 
					
						
							|  |  |  |       endResetModel (); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   QString make_title (QString const& id, QString const& version, QString const& revision) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     QString title {id}; | 
					
						
							|  |  |  |     if (version.size ()) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         title += QString {" v%1"}.arg (version); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     if (revision.size ()) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         title += QString {" (%1)"}.arg (revision); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     return title; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |                             , QString const& id, QString const& version, QString const& revision | 
					
						
							| 
									
										
										
										
											2018-03-28 22:25:46 +00:00
										 |  |  |                             , QListWidget const * calls_of_interest, QWidget * parent) | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |   : QDockWidget {make_title (id, version, revision), parent} | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |   , id_ {id} | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   , done_ {false} | 
					
						
							| 
									
										
										
										
											2018-03-28 22:25:46 +00:00
										 |  |  |   , calls_of_interest_ {calls_of_interest} | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   , decodes_proxy_model_ {id} | 
					
						
							|  |  |  |   , beacons_proxy_model_ {id} | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  |   , 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}} | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   , 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_}} | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |   , decodes_stack_ {new QStackedLayout} | 
					
						
							| 
									
										
										
										
											2017-09-22 22:08:41 +00:00
										 |  |  |   , columns_resized_ {false} | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   // set up widgets
 | 
					
						
							|  |  |  |   decodes_proxy_model_.setSourceModel (decodes_model); | 
					
						
							|  |  |  |   decodes_table_view_->setModel (&decodes_proxy_model_); | 
					
						
							|  |  |  |   decodes_table_view_->verticalHeader ()->hide (); | 
					
						
							|  |  |  |   decodes_table_view_->hideColumn (0); | 
					
						
							|  |  |  |   decodes_table_view_->horizontalHeader ()->setStretchLastSection (true); | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  |   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_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   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_); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |   connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) { | 
					
						
							|  |  |  |       Q_EMIT do_free_text (id_, text, false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   connect (message_line_edit_, &QLineEdit::editingFinished, [this] () { | 
					
						
							|  |  |  |       Q_EMIT do_free_text (id_, message_line_edit_->text (), true); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-02-04 22:42:35 +00:00
										 |  |  |   connect (grid_line_edit_, &QLineEdit::editingFinished, [this] () { | 
					
						
							|  |  |  |       Q_EMIT location (id_, grid_line_edit_->text ()); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-06-13 01:44:28 +01:00
										 |  |  |   connect (configuration_line_edit_, &QLineEdit::editingFinished, [this] () { | 
					
						
							|  |  |  |       Q_EMIT switch_configuration (id_, configuration_line_edit_->text ()); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   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); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   decodes_layout_->setContentsMargins (QMargins {2, 2, 2, 2}); | 
					
						
							|  |  |  |   decodes_layout_->addWidget (decodes_table_view_); | 
					
						
							|  |  |  |   decodes_layout_->addLayout (form_layout_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   beacons_proxy_model_.setSourceModel (beacons_model); | 
					
						
							|  |  |  |   beacons_table_view_->setModel (&beacons_proxy_model_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |   beacons_table_view_->verticalHeader ()->hide (); | 
					
						
							|  |  |  |   beacons_table_view_->hideColumn (0); | 
					
						
							|  |  |  |   beacons_table_view_->horizontalHeader ()->setStretchLastSection (true); | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  |   beacons_table_view_->setContextMenuPolicy (Qt::ActionsContextMenu); | 
					
						
							|  |  |  |   beacons_table_view_->insertAction (nullptr, erase_action_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   beacons_layout_->setContentsMargins (QMargins {2, 2, 2, 2}); | 
					
						
							|  |  |  |   beacons_layout_->addWidget (beacons_table_view_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   decodes_stack_->addWidget (decodes_page_); | 
					
						
							|  |  |  |   decodes_stack_->addWidget (beacons_page_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // stack alternative views
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   content_layout_->setContentsMargins (QMargins {2, 2, 2, 2}); | 
					
						
							|  |  |  |   content_layout_->addLayout (decodes_stack_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // set up controls
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   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); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |   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); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   content_layout_->addWidget (control_button_box_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // set up status area
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // set up central widget
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |   content_widget_->setFrameStyle (QFrame::StyledPanel | QFrame::Sunken); | 
					
						
							|  |  |  |   setWidget (content_widget_); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |   // setMinimumSize (QSize {550, 0});
 | 
					
						
							|  |  |  |   setAllowedAreas (Qt::BottomDockWidgetArea); | 
					
						
							| 
									
										
										
										
											2018-03-28 22:25:46 +00:00
										 |  |  |   setFloating (true); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  |   // 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); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |   // connect up table view signals
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  |   connect (decodes_table_view_, &QTableView::doubleClicked, [this] (QModelIndex const& index) { | 
					
						
							| 
									
										
										
										
											2017-09-22 15:36:24 +00:00
										 |  |  |       Q_EMIT do_reply (decodes_proxy_model_.mapToSource (index), QApplication::keyboardModifiers () >> 24); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-03-28 22:25:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // tell new client about calls of interest
 | 
					
						
							|  |  |  |   for (int row = 0; row < calls_of_interest_->count (); ++row) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       Q_EMIT highlight_callsign (id_, calls_of_interest_->item (row)->text (), QColor {Qt::blue}, QColor {Qt::yellow}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | 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); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 22:25:46 +00:00
										 |  |  | ClientWidget::~ClientWidget () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   for (int row = 0; row < calls_of_interest_->count (); ++row) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // tell client to forget calls of interest
 | 
					
						
							|  |  |  |       Q_EMIT highlight_callsign (id_, calls_of_interest_->item (row)->text ()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | 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); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-10 22:20:30 +00:00
										 |  |  | void ClientWidget::update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |                                   , QString const& report, QString const& tx_mode, bool tx_enabled | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |                                   , bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df | 
					
						
							| 
									
										
										
										
											2018-02-04 22:42:35 +00:00
										 |  |  |                                   , QString const& de_call, QString const& de_grid, QString const& dx_grid | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |                                   , bool watchdog_timeout, QString const& submode, bool fast_mode | 
					
						
							|  |  |  |                                   , quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period | 
					
						
							|  |  |  |                                   , QString const& configuration_name) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |     if (id == id_) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |       fast_mode_check_box_->setChecked (fast_mode); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |       decodes_proxy_model_.de_call (de_call); | 
					
						
							|  |  |  |       decodes_proxy_model_.rx_df (rx_df); | 
					
						
							| 
									
										
										
										
											2018-12-02 23:19:08 +00:00
										 |  |  |       QString special; | 
					
						
							|  |  |  |       switch (special_op_mode) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 1: special = "[NA VHF]"; break; | 
					
						
							|  |  |  |         case 2: special = "[EU VHF]"; break; | 
					
						
							|  |  |  |         case 3: special = "[FD]"; break; | 
					
						
							|  |  |  |         case 4: special = "[RTTY RU]"; break; | 
					
						
							| 
									
										
										
										
											2020-06-04 03:39:49 +01:00
										 |  |  |         case 5: special = "[WW DIGI]"; break; | 
					
						
							|  |  |  |         case 6: special = "[Fox]"; break; | 
					
						
							|  |  |  |         case 7: special = "[Hound]"; break; | 
					
						
							| 
									
										
										
										
											2018-12-02 23:19:08 +00:00
										 |  |  |         default: break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       de_label_->setText (de_call.size () >= 0 ? QString {"DE: %1%2%3"}.arg (de_call) | 
					
						
							|  |  |  |                           .arg (de_grid.size () ? '(' + de_grid + ')' : QString {}) | 
					
						
							|  |  |  |                           .arg (special) | 
					
						
							|  |  |  |                           : QString {}); | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |       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"} | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |            .arg (tx_mode.isEmpty () || tx_mode == mode ? "" : '(' + tx_mode + ')')); | 
					
						
							| 
									
										
										
										
											2016-07-08 10:25:21 +00:00
										 |  |  |       frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f)); | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |       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)); | 
					
						
							| 
									
										
										
										
											2016-07-08 10:25:21 +00:00
										 |  |  |       report_label_->setText ("SNR: " + report); | 
					
						
							|  |  |  |       update_dynamic_property (frequency_label_, "transmitting", transmitting); | 
					
						
							|  |  |  |       auto_off_button_->setEnabled (tx_enabled); | 
					
						
							|  |  |  |       halt_tx_button_->setEnabled (transmitting); | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |       update_line_edit (configuration_line_edit_, configuration_name); | 
					
						
							|  |  |  |       update_dynamic_property (mode_line_edit_, "decoding", decoding); | 
					
						
							| 
									
										
										
										
											2016-07-08 10:25:21 +00:00
										 |  |  |       update_dynamic_property (tx_df_label_, "watchdog_timeout", watchdog_timeout); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/ | 
					
						
							|  |  |  |                                  , float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/ | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                                  , QString const& /*message*/, bool /*low_confidence*/, bool /*off_air*/) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-09-22 22:08:41 +00:00
										 |  |  |   if (client_id == id_ && !columns_resized_) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       decodes_stack_->setCurrentIndex (0); | 
					
						
							|  |  |  |       decodes_table_view_->resizeColumnsToContents (); | 
					
						
							| 
									
										
										
										
											2017-09-22 22:08:41 +00:00
										 |  |  |       columns_resized_ = true; | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-22 22:08:41 +00:00
										 |  |  |   decodes_table_view_->scrollToBottom (); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/ | 
					
						
							|  |  |  |                                       , float /*delta_time*/, Frequency /*delta_frequency*/, qint32 /*drift*/ | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                                       , QString const& /*callsign*/, QString const& /*grid*/, qint32 /*power*/ | 
					
						
							|  |  |  |                                       , bool /*off_air*/) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-09-22 22:08:41 +00:00
										 |  |  |   if (client_id == id_ && !columns_resized_) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       decodes_stack_->setCurrentIndex (1); | 
					
						
							|  |  |  |       beacons_table_view_->resizeColumnsToContents (); | 
					
						
							| 
									
										
										
										
											2017-09-22 22:08:41 +00:00
										 |  |  |       columns_resized_ = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   beacons_table_view_->scrollToBottom (); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  | void ClientWidget::decodes_cleared (QString const& client_id) | 
					
						
							| 
									
										
										
										
											2017-09-22 22:08:41 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   if (client_id == id_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       columns_resized_ = false; | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "moc_ClientWidget.cpp"
 |