Merge branch 'hotfix-2.0.0-rc3'

This commit is contained in:
Bill Somerville 2018-10-17 00:40:15 +01:00
commit 388fb94698
76 changed files with 4601 additions and 123523 deletions

View File

@ -257,10 +257,14 @@ set (wsjt_qt_CXXSRCS
MultiSettings.cpp MultiSettings.cpp
MaidenheadLocatorValidator.cpp MaidenheadLocatorValidator.cpp
CallsignValidator.cpp CallsignValidator.cpp
ExchangeValidator.cpp
SplashScreen.cpp SplashScreen.cpp
EqualizationToolsDialog.cpp EqualizationToolsDialog.cpp
DoubleClickablePushButton.cpp DoubleClickablePushButton.cpp
DoubleClickableRadioButton.cpp DoubleClickableRadioButton.cpp
LotWUsers.cpp
DecodeHighlightingModel.cpp
DecodeHighlightingListView.cpp
) )
set (wsjt_qtmm_CXXSRCS set (wsjt_qtmm_CXXSRCS
@ -308,6 +312,7 @@ set (wsjtx_CXXSRCS
main.cpp main.cpp
wsprnet.cpp wsprnet.cpp
WSPRBandHopping.cpp WSPRBandHopping.cpp
ExportCabrillo.cpp
) )
set (wsjt_CXXSRCS set (wsjt_CXXSRCS
@ -647,6 +652,7 @@ set (wsjtx_UISRCS
widegraph.ui widegraph.ui
logqso.ui logqso.ui
Configuration.ui Configuration.ui
ExportCabrillo.ui
) )
set (UDP_library_CXXSRCS set (UDP_library_CXXSRCS
@ -1427,7 +1433,6 @@ install (FILES
install (FILES install (FILES
contrib/Ephemeris/JPLEPH contrib/Ephemeris/JPLEPH
contrib/lotw-user-activity.csv
DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}
#COMPONENT runtime #COMPONENT runtime
) )

View File

@ -157,7 +157,6 @@
#include <QStandardPaths> #include <QStandardPaths>
#include <QFont> #include <QFont>
#include <QFontDialog> #include <QFontDialog>
#include <QColorDialog>
#include <QSerialPortInfo> #include <QSerialPortInfo>
#include <QScopedPointer> #include <QScopedPointer>
#include <QDebug> #include <QDebug>
@ -180,6 +179,9 @@
#include "MessageBox.hpp" #include "MessageBox.hpp"
#include "MaidenheadLocatorValidator.hpp" #include "MaidenheadLocatorValidator.hpp"
#include "CallsignValidator.hpp" #include "CallsignValidator.hpp"
#include "LotWUsers.hpp"
#include "ExchangeValidator.hpp"
#include "DecodeHighlightingModel.hpp"
#include "ui_Configuration.h" #include "ui_Configuration.h"
#include "moc_Configuration.cpp" #include "moc_Configuration.cpp"
@ -354,8 +356,11 @@ public:
using FrequencyDelta = Radio::FrequencyDelta; using FrequencyDelta = Radio::FrequencyDelta;
using port_type = Configuration::port_type; using port_type = Configuration::port_type;
explicit impl (Configuration * self, QDir const& temp_directory, explicit impl (Configuration * self
QSettings * settings, QWidget * parent); , QNetworkAccessManager * network_manager
, QDir const& temp_directory
, QSettings * settings
, QWidget * parent);
~impl (); ~impl ();
bool have_rig (); bool have_rig ();
@ -440,22 +445,19 @@ private:
Q_SLOT void on_calibration_slope_ppm_spin_box_valueChanged (double); Q_SLOT void on_calibration_slope_ppm_spin_box_valueChanged (double);
Q_SLOT void handle_transceiver_update (TransceiverState const&, unsigned sequence_number); Q_SLOT void handle_transceiver_update (TransceiverState const&, unsigned sequence_number);
Q_SLOT void handle_transceiver_failure (QString const& reason); Q_SLOT void handle_transceiver_failure (QString const& reason);
Q_SLOT void on_pbCQmsg_clicked(); Q_SLOT void on_reset_highlighting_to_defaults_push_button_clicked (bool);
Q_SLOT void on_pbMyCall_clicked(); Q_SLOT void on_LotW_CSV_fetch_push_button_clicked (bool);
Q_SLOT void on_pbTxMsg_clicked();
Q_SLOT void on_pbNewDXCC_clicked();
Q_SLOT void on_pbNewDXCCband_clicked();
Q_SLOT void on_pbNewCall_clicked();
Q_SLOT void on_pbNewCallBand_clicked();
Q_SLOT void on_pbNewGrid_clicked();
Q_SLOT void on_pbNewGridBand_clicked();
Q_SLOT void on_pbLoTW_clicked();
Q_SLOT void on_pbResetDefaults_clicked();
Q_SLOT void on_cbFox_clicked (bool); Q_SLOT void on_cbFox_clicked (bool);
Q_SLOT void on_cbHound_clicked (bool); Q_SLOT void on_cbHound_clicked (bool);
Q_SLOT void on_cbx2ToneSpacing_clicked(bool); Q_SLOT void on_cbx2ToneSpacing_clicked(bool);
Q_SLOT void on_cbx4ToneSpacing_clicked(bool); Q_SLOT void on_cbx4ToneSpacing_clicked(bool);
Q_SLOT void on_rbNone_toggled(bool); Q_SLOT void on_rbNone_toggled(bool);
Q_SLOT void on_rbFieldDay_toggled();
Q_SLOT void on_rbRTTYroundup_toggled();
Q_SLOT void on_FieldDay_Exchange_textChanged();
Q_SLOT void on_RTTY_Exchange_textChanged();
Q_SLOT void on_prompt_to_log_check_box_clicked(bool);
Q_SLOT void on_cbAutoLog_clicked(bool);
// typenames used as arguments must match registered type names :( // typenames used as arguments must match registered type names :(
Q_SIGNAL void start_transceiver (unsigned seqeunce_number) const; Q_SIGNAL void start_transceiver (unsigned seqeunce_number) const;
@ -471,6 +473,7 @@ private:
QScopedPointer<Ui::configuration_dialog> ui_; QScopedPointer<Ui::configuration_dialog> ui_;
QNetworkAccessManager * network_manager_;
QSettings * settings_; QSettings * settings_;
QDir doc_dir_; QDir doc_dir_;
@ -488,6 +491,8 @@ private:
QFont decoded_text_font_; QFont decoded_text_font_;
QFont next_decoded_text_font_; QFont next_decoded_text_font_;
LotWUsers lotw_users_;
bool restart_sound_input_device_; bool restart_sound_input_device_;
bool restart_sound_output_device_; bool restart_sound_output_device_;
@ -516,10 +521,14 @@ private:
QAction * reset_frequencies_action_; QAction * reset_frequencies_action_;
FrequencyDialog * frequency_dialog_; FrequencyDialog * frequency_dialog_;
QAction * station_delete_action_; QAction station_delete_action_;
QAction * station_insert_action_; QAction station_insert_action_;
StationDialog * station_dialog_; StationDialog * station_dialog_;
DecodeHighlightingModel decode_highlighing_model_;
DecodeHighlightingModel next_decode_highlighing_model_;
int LotW_days_since_upload_;
TransceiverFactory::ParameterPack rig_params_; TransceiverFactory::ParameterPack rig_params_;
TransceiverFactory::ParameterPack saved_rig_params_; TransceiverFactory::ParameterPack saved_rig_params_;
TransceiverFactory::Capabilities::PortType last_port_type_; TransceiverFactory::Capabilities::PortType last_port_type_;
@ -539,26 +548,6 @@ private:
QString my_grid_; QString my_grid_;
QString FD_exchange_; QString FD_exchange_;
QString RTTY_exchange_; QString RTTY_exchange_;
QColor color_CQ_;
QColor next_color_CQ_;
QColor color_MyCall_;
QColor next_color_MyCall_;
QColor color_TxMsg_;
QColor next_color_TxMsg_;
QColor color_DXCC_;
QColor next_color_DXCC_;
QColor color_DXCCband_;
QColor next_color_DXCCband_;
QColor color_NewCall_;
QColor next_color_NewCall_;
QColor color_NewCallBand_;
QColor next_color_NewCallBand_;
QColor color_NewGrid_;
QColor next_color_NewGrid_;
QColor color_NewGridBand_;
QColor next_color_NewGridBand_;
QColor color_LoTW_;
QColor next_color_LoTW_;
qint32 id_interval_; qint32 id_interval_;
qint32 ntrials_; qint32 ntrials_;
@ -574,6 +563,7 @@ private:
bool log_as_RTTY_; bool log_as_RTTY_;
bool report_in_comments_; bool report_in_comments_;
bool prompt_to_log_; bool prompt_to_log_;
bool autoLog_;
bool insert_blank_; bool insert_blank_;
bool DXCC_; bool DXCC_;
bool ppfx_; bool ppfx_;
@ -602,13 +592,9 @@ private:
QString opCall_; QString opCall_;
QString udp_server_name_; QString udp_server_name_;
port_type udp_server_port_; port_type udp_server_port_;
// QString n1mm_server_name () const;
QString n1mm_server_name_; QString n1mm_server_name_;
port_type n1mm_server_port_; port_type n1mm_server_port_;
bool broadcast_to_n1mm_; bool broadcast_to_n1mm_;
// port_type n1mm_server_port () const;
// bool valid_n1mm_info () const;
// bool broadcast_to_n1mm() const;
bool accept_udp_requests_; bool accept_udp_requests_;
bool udpWindowToFront_; bool udpWindowToFront_;
bool udpWindowRestore_; bool udpWindowRestore_;
@ -630,9 +616,9 @@ private:
// delegate to implementation class // delegate to implementation class
Configuration::Configuration (QDir const& temp_directory, Configuration::Configuration (QNetworkAccessManager * network_manager, QDir const& temp_directory,
QSettings * settings, QWidget * parent) QSettings * settings, QWidget * parent)
: m_ {this, temp_directory, settings, parent} : m_ {this, network_manager, temp_directory, settings, parent}
{ {
} }
@ -657,16 +643,6 @@ bool Configuration::restart_audio_input () const {return m_->restart_sound_input
bool Configuration::restart_audio_output () const {return m_->restart_sound_output_device_;} bool Configuration::restart_audio_output () const {return m_->restart_sound_output_device_;}
auto Configuration::type_2_msg_gen () const -> Type2MsgGen {return m_->type_2_msg_gen_;} auto Configuration::type_2_msg_gen () const -> Type2MsgGen {return m_->type_2_msg_gen_;}
QString Configuration::my_callsign () const {return m_->my_callsign_;} QString Configuration::my_callsign () const {return m_->my_callsign_;}
QColor Configuration::color_CQ () const {return m_->color_CQ_;}
QColor Configuration::color_MyCall () const {return m_->color_MyCall_;}
QColor Configuration::color_TxMsg () const {return m_->color_TxMsg_;}
QColor Configuration::color_DXCC () const {return m_->color_DXCC_;}
QColor Configuration::color_DXCCband() const {return m_->color_DXCCband_;}
QColor Configuration::color_NewCall () const {return m_->color_NewCall_;}
QColor Configuration::color_NewCallBand () const {return m_->color_NewCallBand_;}
QColor Configuration::color_NewGrid () const {return m_->color_NewGrid_;}
QColor Configuration::color_NewGridBand () const {return m_->color_NewGridBand_;}
QColor Configuration::color_LoTW() const {return m_->color_LoTW_;}
QFont Configuration::text_font () const {return m_->font_;} QFont Configuration::text_font () const {return m_->font_;}
QFont Configuration::decoded_text_font () const {return m_->decoded_text_font_;} QFont Configuration::decoded_text_font () const {return m_->decoded_text_font_;}
qint32 Configuration::id_interval () const {return m_->id_interval_;} qint32 Configuration::id_interval () const {return m_->id_interval_;}
@ -687,6 +663,7 @@ bool Configuration::monitor_last_used () const {return m_->rig_is_dummy_ || m_->
bool Configuration::log_as_RTTY () const {return m_->log_as_RTTY_;} bool Configuration::log_as_RTTY () const {return m_->log_as_RTTY_;}
bool Configuration::report_in_comments () const {return m_->report_in_comments_;} bool Configuration::report_in_comments () const {return m_->report_in_comments_;}
bool Configuration::prompt_to_log () const {return m_->prompt_to_log_;} bool Configuration::prompt_to_log () const {return m_->prompt_to_log_;}
bool Configuration::autoLog() const {return m_->autoLog_;}
bool Configuration::insert_blank () const {return m_->insert_blank_;} bool Configuration::insert_blank () const {return m_->insert_blank_;}
bool Configuration::DXCC () const {return m_->DXCC_;} bool Configuration::DXCC () const {return m_->DXCC_;}
bool Configuration::ppfx() const {return m_->ppfx_;} bool Configuration::ppfx() const {return m_->ppfx_;}
@ -735,6 +712,8 @@ QDir Configuration::azel_directory () const {return m_->azel_directory_;}
QString Configuration::rig_name () const {return m_->rig_params_.rig_name;} QString Configuration::rig_name () const {return m_->rig_params_.rig_name;}
bool Configuration::pwrBandTxMemory () const {return m_->pwrBandTxMemory_;} bool Configuration::pwrBandTxMemory () const {return m_->pwrBandTxMemory_;}
bool Configuration::pwrBandTuneMemory () const {return m_->pwrBandTuneMemory_;} bool Configuration::pwrBandTuneMemory () const {return m_->pwrBandTuneMemory_;}
LotWUsers const& Configuration::lotw_users () const {return m_->lotw_users_;}
DecodeHighlightingModel const& Configuration::decode_highlighting () const {return m_->decode_highlighing_model_;}
void Configuration::set_calibration (CalibrationParams params) void Configuration::set_calibration (CalibrationParams params)
{ {
@ -906,17 +885,19 @@ namespace
} }
} }
Configuration::impl::impl (Configuration * self, QDir const& temp_directory, Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network_manager
QSettings * settings, QWidget * parent) , QDir const& temp_directory, QSettings * settings, QWidget * parent)
: QDialog {parent} : QDialog {parent}
, self_ {self} , self_ {self}
, transceiver_thread_ {nullptr} , transceiver_thread_ {nullptr}
, ui_ {new Ui::configuration_dialog} , ui_ {new Ui::configuration_dialog}
, network_manager_ {network_manager}
, settings_ {settings} , settings_ {settings}
, doc_dir_ {doc_path ()} , doc_dir_ {doc_path ()}
, data_dir_ {data_path ()} , data_dir_ {data_path ()}
, temp_dir_ {temp_directory} , temp_dir_ {temp_directory}
, writeable_data_dir_ {QStandardPaths::writableLocation (QStandardPaths::DataLocation)} , writeable_data_dir_ {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}
, lotw_users_ {network_manager_}
, restart_sound_input_device_ {false} , restart_sound_input_device_ {false}
, restart_sound_output_device_ {false} , restart_sound_output_device_ {false}
, frequencies_ {&bands_} , frequencies_ {&bands_}
@ -926,7 +907,10 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
, current_offset_ {0} , current_offset_ {0}
, current_tx_offset_ {0} , current_tx_offset_ {0}
, frequency_dialog_ {new FrequencyDialog {&regions_, &modes_, this}} , frequency_dialog_ {new FrequencyDialog {&regions_, &modes_, this}}
, station_delete_action_ {tr ("&Delete"), nullptr}
, station_insert_action_ {tr ("&Insert ..."), nullptr}
, station_dialog_ {new StationDialog {&next_stations_, &bands_, this}} , station_dialog_ {new StationDialog {&next_stations_, &bands_, this}}
, LotW_days_since_upload_ {0}
, last_port_type_ {TransceiverFactory::Capabilities::none} , last_port_type_ {TransceiverFactory::Capabilities::none}
, rig_is_dummy_ {false} , rig_is_dummy_ {false}
, rig_active_ {false} , rig_active_ {false}
@ -997,12 +981,21 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
// this must be done after the default paths above are set // this must be done after the default paths above are set
read_settings (); read_settings ();
// conditionally load LotW users data
ui_->LotW_CSV_fetch_push_button->setEnabled (false);
connect (&lotw_users_, &LotWUsers::load_finished, [this] () {
ui_->LotW_CSV_fetch_push_button->setEnabled (true);
});
lotw_users_.set_local_file_path (writeable_data_dir_.absoluteFilePath ("lotw-user-activity.csv"));
lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text ());
// //
// validation // validation
//
ui_->callsign_line_edit->setValidator (new CallsignValidator {this}); ui_->callsign_line_edit->setValidator (new CallsignValidator {this});
ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {this}); ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {this});
ui_->add_macro_line_edit->setValidator (new QRegExpValidator {message_alphabet, this}); ui_->add_macro_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->FieldDay_Exchange->setValidator(new ExchangeValidator{this});
ui_->RTTY_Exchange->setValidator(new ExchangeValidator{this});
ui_->udp_server_port_spin_box->setMinimum (1); ui_->udp_server_port_spin_box->setMinimum (1);
ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ()); ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
@ -1115,29 +1108,30 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
ui_->frequencies_table_view->insertAction (nullptr, reset_frequencies_action_); ui_->frequencies_table_view->insertAction (nullptr, reset_frequencies_action_);
connect (reset_frequencies_action_, &QAction::triggered, this, &Configuration::impl::reset_frequencies); connect (reset_frequencies_action_, &QAction::triggered, this, &Configuration::impl::reset_frequencies);
// //
// setup stations table model & view // setup stations table model & view
// //
stations_.sort (StationList::band_column); stations_.sort (StationList::band_column);
ui_->stations_table_view->setModel (&next_stations_); ui_->stations_table_view->setModel (&next_stations_);
ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder); ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder);
// delegates // stations delegates
auto stations_item_delegate = new QStyledItemDelegate {this}; auto stations_item_delegate = new QStyledItemDelegate {this};
stations_item_delegate->setItemEditorFactory (item_editor_factory ()); stations_item_delegate->setItemEditorFactory (item_editor_factory ());
ui_->stations_table_view->setItemDelegate (stations_item_delegate); ui_->stations_table_view->setItemDelegate (stations_item_delegate);
ui_->stations_table_view->setItemDelegateForColumn (StationList::band_column, new ForeignKeyDelegate {&bands_, &next_stations_, 0, StationList::band_column, this}); ui_->stations_table_view->setItemDelegateForColumn (StationList::band_column, new ForeignKeyDelegate {&bands_, &next_stations_, 0, StationList::band_column, this});
// actions // stations actions
station_delete_action_ = new QAction {tr ("&Delete"), ui_->stations_table_view}; ui_->stations_table_view->addAction (&station_delete_action_);
ui_->stations_table_view->insertAction (nullptr, station_delete_action_); connect (&station_delete_action_, &QAction::triggered, this, &Configuration::impl::delete_stations);
connect (station_delete_action_, &QAction::triggered, this, &Configuration::impl::delete_stations);
station_insert_action_ = new QAction {tr ("&Insert ..."), ui_->stations_table_view}; ui_->stations_table_view->addAction (&station_insert_action_);
ui_->stations_table_view->insertAction (nullptr, station_insert_action_); connect (&station_insert_action_, &QAction::triggered, this, &Configuration::impl::insert_station);
connect (station_insert_action_, &QAction::triggered, this, &Configuration::impl::insert_station);
//
// colours and highlighting setup
//
ui_->highlighting_list_view->setModel (&next_decode_highlighing_model_);
// //
// load combo boxes with audio setup choices // load combo boxes with audio setup choices
@ -1181,16 +1175,6 @@ void Configuration::impl::initialize_models ()
ui_->callsign_line_edit->setText (my_callsign_); ui_->callsign_line_edit->setText (my_callsign_);
ui_->grid_line_edit->setText (my_grid_); ui_->grid_line_edit->setText (my_grid_);
ui_->use_dynamic_grid->setChecked(use_dynamic_grid_); ui_->use_dynamic_grid->setChecked(use_dynamic_grid_);
ui_->labCQ->setStyleSheet(QString("background: %1").arg(color_CQ_.name()));
ui_->labMyCall->setStyleSheet(QString("background: %1").arg(color_MyCall_.name()));
ui_->labTx->setStyleSheet(QString("background: %1").arg(color_TxMsg_.name()));
ui_->labDXCC->setStyleSheet(QString("background: %1").arg(color_DXCC_.name()));
ui_->labDXCCband->setStyleSheet(QString("background: %1").arg(color_DXCCband_.name()));
ui_->labNewCall->setStyleSheet(QString("background: %1").arg(color_NewCall_.name()));
ui_->labNewCallBand->setStyleSheet(QString("background: %1").arg(color_NewCallBand_.name()));
ui_->labNewGrid->setStyleSheet(QString("background: %1").arg(color_NewGrid_.name()));
ui_->labNewGridBand->setStyleSheet(QString("background: %1").arg(color_NewGridBand_.name()));
ui_->labLoTW->setStyleSheet(QString("color: %1").arg(color_LoTW_.name()));
ui_->CW_id_interval_spin_box->setValue (id_interval_); ui_->CW_id_interval_spin_box->setValue (id_interval_);
ui_->sbNtrials->setValue (ntrials_); ui_->sbNtrials->setValue (ntrials_);
ui_->sbTxDelay->setValue (txDelay_); ui_->sbTxDelay->setValue (txDelay_);
@ -1208,6 +1192,7 @@ void Configuration::impl::initialize_models ()
ui_->log_as_RTTY_check_box->setChecked (log_as_RTTY_); ui_->log_as_RTTY_check_box->setChecked (log_as_RTTY_);
ui_->report_in_comments_check_box->setChecked (report_in_comments_); ui_->report_in_comments_check_box->setChecked (report_in_comments_);
ui_->prompt_to_log_check_box->setChecked (prompt_to_log_); ui_->prompt_to_log_check_box->setChecked (prompt_to_log_);
ui_->cbAutoLog->setChecked(autoLog_);
ui_->insert_blank_check_box->setChecked (insert_blank_); ui_->insert_blank_check_box->setChecked (insert_blank_);
ui_->DXCC_check_box->setChecked (DXCC_); ui_->DXCC_check_box->setChecked (DXCC_);
ui_->ppfx_check_box->setChecked (ppfx_); ui_->ppfx_check_box->setChecked (ppfx_);
@ -1291,6 +1276,9 @@ void Configuration::impl::initialize_models ()
next_frequencies_.frequency_list (frequencies_.frequency_list ()); next_frequencies_.frequency_list (frequencies_.frequency_list ());
next_stations_.station_list (stations_.station_list ()); next_stations_.station_list (stations_.station_list ());
next_decode_highlighing_model_.items (decode_highlighing_model_.items ());
ui_->LotW_days_since_upload_spin_box->setValue (LotW_days_since_upload_);
set_rig_invariants (); set_rig_invariants ();
} }
@ -1314,16 +1302,6 @@ void Configuration::impl::read_settings ()
RTTY_exchange_ = settings_->value ("RTTYExchange",QString {}).toString (); RTTY_exchange_ = settings_->value ("RTTYExchange",QString {}).toString ();
ui_->FieldDay_Exchange->setText(FD_exchange_); ui_->FieldDay_Exchange->setText(FD_exchange_);
ui_->RTTY_Exchange->setText(RTTY_exchange_); ui_->RTTY_Exchange->setText(RTTY_exchange_);
next_color_CQ_ = color_CQ_ = settings_->value("colorCQ","#66ff66").toString();
next_color_MyCall_ = color_MyCall_ = settings_->value("colorMyCall","#ff6666").toString();
next_color_TxMsg_ = color_TxMsg_ = settings_->value("colorTxMsg","#ffff00").toString();
next_color_DXCC_ = color_DXCC_ = settings_->value("colorDXCC","#ff00ff").toString();
next_color_DXCCband_ = color_DXCCband_ = settings_->value("colorDXCCband","#ffaaff").toString();
next_color_NewCall_ = color_NewCall_ = settings_->value("colorNewCall","#66b2ff").toString();
next_color_NewCallBand_ = color_NewCallBand_ = settings_->value("colorNewCallBand","#99ffff").toString();
next_color_NewGrid_ = color_NewGrid_ = settings_->value("colorNewGrid","#ffaa00").toString();
next_color_NewGridBand_ = color_NewGridBand_ = settings_->value("colorNewGridBand","#ffcc99").toString();
next_color_LoTW_ = color_LoTW_ = settings_->value("colorLoTW","#990000").toString();
if (next_font_.fromString (settings_->value ("Font", QGuiApplication::font ().toString ()).toString ()) if (next_font_.fromString (settings_->value ("Font", QGuiApplication::font ().toString ()).toString ())
&& next_font_ != font_) && next_font_ != font_)
{ {
@ -1338,6 +1316,8 @@ void Configuration::impl::read_settings ()
&& next_decoded_text_font_ != decoded_text_font_) && next_decoded_text_font_ != decoded_text_font_)
{ {
decoded_text_font_ = next_decoded_text_font_; decoded_text_font_ = next_decoded_text_font_;
next_decode_highlighing_model_.set_font (decoded_text_font_);
ui_->highlighting_list_view->reset ();
Q_EMIT self_->decoded_text_font_changed (decoded_text_font_); Q_EMIT self_->decoded_text_font_changed (decoded_text_font_);
} }
else else
@ -1441,6 +1421,10 @@ void Configuration::impl::read_settings ()
stations_.station_list (settings_->value ("stations").value<StationList::Stations> ()); stations_.station_list (settings_->value ("stations").value<StationList::Stations> ());
decode_highlighing_model_.items (settings_->value ("DecodeHighlighting", QVariant::fromValue (DecodeHighlightingModel::default_items ())).value<DecodeHighlightingModel::HighlightItems> ());
LotW_days_since_upload_ = settings_->value ("LotWDaysSinceLastUpload", 365).toInt ();
lotw_users_.set_age_constraint (LotW_days_since_upload_);
log_as_RTTY_ = settings_->value ("toRTTY", false).toBool (); log_as_RTTY_ = settings_->value ("toRTTY", false).toBool ();
report_in_comments_ = settings_->value("dBtoComments", false).toBool (); report_in_comments_ = settings_->value("dBtoComments", false).toBool ();
rig_params_.rig_name = settings_->value ("Rig", TransceiverFactory::basic_transceiver_name_).toString (); rig_params_.rig_name = settings_->value ("Rig", TransceiverFactory::basic_transceiver_name_).toString ();
@ -1461,6 +1445,7 @@ void Configuration::impl::read_settings ()
rig_params_.ptt_port = settings_->value ("PTTport").toString (); rig_params_.ptt_port = settings_->value ("PTTport").toString ();
data_mode_ = settings_->value ("DataMode", QVariant::fromValue (data_mode_none)).value<Configuration::DataMode> (); data_mode_ = settings_->value ("DataMode", QVariant::fromValue (data_mode_none)).value<Configuration::DataMode> ();
prompt_to_log_ = settings_->value ("PromptToLog", false).toBool (); prompt_to_log_ = settings_->value ("PromptToLog", false).toBool ();
autoLog_ = settings_->value ("AutoLog", false).toBool ();
insert_blank_ = settings_->value ("InsertBlank", false).toBool (); insert_blank_ = settings_->value ("InsertBlank", false).toBool ();
DXCC_ = settings_->value ("DXCCEntity", false).toBool (); DXCC_ = settings_->value ("DXCCEntity", false).toBool ();
ppfx_ = settings_->value ("PrincipalPrefix", false).toBool (); ppfx_ = settings_->value ("PrincipalPrefix", false).toBool ();
@ -1510,16 +1495,6 @@ void Configuration::impl::write_settings ()
settings_->setValue ("MyGrid", my_grid_); settings_->setValue ("MyGrid", my_grid_);
settings_->setValue ("FieldDayExchange", FD_exchange_); settings_->setValue ("FieldDayExchange", FD_exchange_);
settings_->setValue ("RTTYExchange", RTTY_exchange_); settings_->setValue ("RTTYExchange", RTTY_exchange_);
settings_->setValue("colorCQ",color_CQ_);
settings_->setValue("colorMyCall",color_MyCall_);
settings_->setValue("colorTxMsg",color_TxMsg_);
settings_->setValue("colorDXCC",color_DXCC_);
settings_->setValue("colorDXCCband",color_DXCCband_);
settings_->setValue("colorNewCall",color_NewCall_);
settings_->setValue("colorNewCallBand",color_NewCallBand_);
settings_->setValue("colorNewGrid",color_NewGrid_);
settings_->setValue("colorNewGridBand",color_NewGridBand_);
settings_->setValue("colorLoTW",color_LoTW_);
settings_->setValue ("Font", font_.toString ()); settings_->setValue ("Font", font_.toString ());
settings_->setValue ("DecodedTextFont", decoded_text_font_.toString ()); settings_->setValue ("DecodedTextFont", decoded_text_font_.toString ());
settings_->setValue ("IDint", id_interval_); settings_->setValue ("IDint", id_interval_);
@ -1561,6 +1536,8 @@ void Configuration::impl::write_settings ()
settings_->setValue ("Macros", macros_.stringList ()); settings_->setValue ("Macros", macros_.stringList ());
settings_->setValue ("FrequenciesForRegionModes", QVariant::fromValue (frequencies_.frequency_list ())); settings_->setValue ("FrequenciesForRegionModes", QVariant::fromValue (frequencies_.frequency_list ()));
settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ())); settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ()));
settings_->setValue ("DecodeHighlighting", QVariant::fromValue (decode_highlighing_model_.items ()));
settings_->setValue ("LotWDaysSinceLastUpload", LotW_days_since_upload_);
settings_->setValue ("toRTTY", log_as_RTTY_); settings_->setValue ("toRTTY", log_as_RTTY_);
settings_->setValue ("dBtoComments", report_in_comments_); settings_->setValue ("dBtoComments", report_in_comments_);
settings_->setValue ("Rig", rig_params_.rig_name); settings_->setValue ("Rig", rig_params_.rig_name);
@ -1573,6 +1550,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("CATHandshake", QVariant::fromValue (rig_params_.handshake)); settings_->setValue ("CATHandshake", QVariant::fromValue (rig_params_.handshake));
settings_->setValue ("DataMode", QVariant::fromValue (data_mode_)); settings_->setValue ("DataMode", QVariant::fromValue (data_mode_));
settings_->setValue ("PromptToLog", prompt_to_log_); settings_->setValue ("PromptToLog", prompt_to_log_);
settings_->setValue ("AutoLog", autoLog_);
settings_->setValue ("InsertBlank", insert_blank_); settings_->setValue ("InsertBlank", insert_blank_);
settings_->setValue ("DXCCEntity", DXCC_); settings_->setValue ("DXCCEntity", DXCC_);
settings_->setValue ("PrincipalPrefix", ppfx_); settings_->setValue ("PrincipalPrefix", ppfx_);
@ -1883,20 +1861,11 @@ void Configuration::impl::accept ()
if (next_decoded_text_font_ != decoded_text_font_) if (next_decoded_text_font_ != decoded_text_font_)
{ {
decoded_text_font_ = next_decoded_text_font_; decoded_text_font_ = next_decoded_text_font_;
next_decode_highlighing_model_.set_font (decoded_text_font_);
ui_->highlighting_list_view->reset ();
Q_EMIT self_->decoded_text_font_changed (decoded_text_font_); Q_EMIT self_->decoded_text_font_changed (decoded_text_font_);
} }
color_CQ_ = next_color_CQ_;
color_MyCall_ = next_color_MyCall_;
color_TxMsg_ = next_color_TxMsg_;
color_DXCC_ = next_color_DXCC_;
color_DXCCband_ = next_color_DXCCband_;
color_NewCall_ = next_color_NewCall_;
color_NewCallBand_ = next_color_NewCallBand_;
color_NewGrid_ = next_color_NewGrid_;
color_NewGridBand_ = next_color_NewGridBand_;
color_LoTW_ = next_color_LoTW_;
rig_params_ = temp_rig_params; // now we can go live with the rig rig_params_ = temp_rig_params; // now we can go live with the rig
// related configuration parameters // related configuration parameters
rig_is_dummy_ = TransceiverFactory::basic_transceiver_name_ == rig_params_.rig_name; rig_is_dummy_ = TransceiverFactory::basic_transceiver_name_ == rig_params_.rig_name;
@ -1994,6 +1963,7 @@ void Configuration::impl::accept ()
log_as_RTTY_ = ui_->log_as_RTTY_check_box->isChecked (); log_as_RTTY_ = ui_->log_as_RTTY_check_box->isChecked ();
report_in_comments_ = ui_->report_in_comments_check_box->isChecked (); report_in_comments_ = ui_->report_in_comments_check_box->isChecked ();
prompt_to_log_ = ui_->prompt_to_log_check_box->isChecked (); prompt_to_log_ = ui_->prompt_to_log_check_box->isChecked ();
autoLog_ = ui_->cbAutoLog->isChecked();
insert_blank_ = ui_->insert_blank_check_box->isChecked (); insert_blank_ = ui_->insert_blank_check_box->isChecked ();
DXCC_ = ui_->DXCC_check_box->isChecked (); DXCC_ = ui_->DXCC_check_box->isChecked ();
ppfx_ = ui_->ppfx_check_box->isChecked (); ppfx_ = ui_->ppfx_check_box->isChecked ();
@ -2042,10 +2012,8 @@ void Configuration::impl::accept ()
} }
accept_udp_requests_ = ui_->accept_udp_requests_check_box->isChecked (); accept_udp_requests_ = ui_->accept_udp_requests_check_box->isChecked ();
auto new_n1mm_server = ui_->n1mm_server_name_line_edit->text (); n1mm_server_name_ = ui_->n1mm_server_name_line_edit->text ();
n1mm_server_name_ = new_n1mm_server; n1mm_server_port_ = ui_->n1mm_server_port_spin_box->value ();
auto new_n1mm_port = ui_->n1mm_server_port_spin_box->value ();
n1mm_server_port_ = new_n1mm_port;
broadcast_to_n1mm_ = ui_->enable_n1mm_broadcast_check_box->isChecked (); broadcast_to_n1mm_ = ui_->enable_n1mm_broadcast_check_box->isChecked ();
udpWindowToFront_ = ui_->udpWindowToFront->isChecked (); udpWindowToFront_ = ui_->udpWindowToFront->isChecked ();
@ -2066,10 +2034,18 @@ void Configuration::impl::accept ()
if (stations_.station_list () != next_stations_.station_list ()) if (stations_.station_list () != next_stations_.station_list ())
{ {
stations_.station_list(next_stations_.station_list ()); stations_.station_list (next_stations_.station_list ());
stations_.sort (StationList::band_column); stations_.sort (StationList::band_column);
} }
if (decode_highlighing_model_.items () != next_decode_highlighing_model_.items ())
{
decode_highlighing_model_.items (next_decode_highlighing_model_.items ());
Q_EMIT self_->decode_highlighting_changed (decode_highlighing_model_);
}
LotW_days_since_upload_ = ui_->LotW_days_since_upload_spin_box->value ();
lotw_users_.set_age_constraint (LotW_days_since_upload_);
if (ui_->use_dynamic_grid->isChecked() && !use_dynamic_grid_ ) if (ui_->use_dynamic_grid->isChecked() && !use_dynamic_grid_ )
{ {
// turning on so clear it so only the next location update gets used // turning on so clear it so only the next location update gets used
@ -2108,136 +2084,27 @@ void Configuration::impl::on_font_push_button_clicked ()
next_font_ = QFontDialog::getFont (0, next_font_, this); next_font_ = QFontDialog::getFont (0, next_font_, this);
} }
void Configuration::impl::on_pbCQmsg_clicked() void Configuration::impl::on_reset_highlighting_to_defaults_push_button_clicked (bool /*checked*/)
{ {
auto new_color = QColorDialog::getColor(next_color_CQ_, this, "CQ Messages Color"); if (MessageBox::Yes == MessageBox::query_message (this
if (new_color.isValid ()) , tr ("Reset Decode Highlighting")
, tr ("Reset all decode highlighting and priorities to default values")))
{ {
next_color_CQ_ = new_color; next_decode_highlighing_model_.items (DecodeHighlightingModel::default_items ());
ui_->labCQ->setStyleSheet(QString("background: %1").arg(next_color_CQ_.name()));
} }
} }
void Configuration::impl::on_pbMyCall_clicked() void Configuration::impl::on_LotW_CSV_fetch_push_button_clicked (bool /*checked*/)
{ {
auto new_color = QColorDialog::getColor(next_color_MyCall_, this, "My Call Messages Color"); lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text (), true);
if (new_color.isValid ()) ui_->LotW_CSV_fetch_push_button->setEnabled (false);
{
next_color_MyCall_ = new_color;
ui_->labMyCall->setStyleSheet(QString("background: %1").arg(next_color_MyCall_.name()));
}
}
void Configuration::impl::on_pbTxMsg_clicked()
{
auto new_color = QColorDialog::getColor(next_color_TxMsg_, this, "Tx Messages Color");
if (new_color.isValid ())
{
next_color_TxMsg_ = new_color;
ui_->labTx->setStyleSheet(QString("background: %1").arg(next_color_TxMsg_.name()));
}
}
void Configuration::impl::on_pbNewDXCC_clicked()
{
auto new_color = QColorDialog::getColor(next_color_DXCC_, this, "New DXCC Messages Color");
if (new_color.isValid ())
{
next_color_DXCC_ = new_color;
ui_->labDXCC->setStyleSheet(QString("background: %1").arg(next_color_DXCC_.name()));
}
}
void Configuration::impl::on_pbNewDXCCband_clicked()
{
auto new_color = QColorDialog::getColor(next_color_DXCCband_, this, "New DXCCband Color");
if (new_color.isValid ())
{
next_color_DXCCband_ = new_color;
ui_->labDXCCband->setStyleSheet(QString("background: %1").arg(next_color_DXCCband_.name()));
}
}
void Configuration::impl::on_pbNewCall_clicked()
{
auto new_color = QColorDialog::getColor(next_color_NewCall_, this, "New Call Messages Color");
if (new_color.isValid ())
{
next_color_NewCall_ = new_color;
ui_->labNewCall->setStyleSheet(QString("background: %1").arg(next_color_NewCall_.name()));
}
}
void Configuration::impl::on_pbNewCallBand_clicked()
{
auto new_color = QColorDialog::getColor(next_color_NewCallBand_, this, "New CallBand Color");
if (new_color.isValid ())
{
next_color_NewCallBand_ = new_color;
ui_->labNewCallBand->setStyleSheet(QString("background: %1").arg(next_color_NewCallBand_.name()));
}
}
void Configuration::impl::on_pbNewGrid_clicked()
{
auto new_color = QColorDialog::getColor(next_color_NewGrid_, this, "New Grid Messages Color");
if (new_color.isValid ())
{
next_color_NewGrid_ = new_color;
ui_->labNewGrid->setStyleSheet(QString("background: %1").arg(next_color_NewGrid_.name()));
}
}
void Configuration::impl::on_pbNewGridBand_clicked()
{
auto new_color = QColorDialog::getColor(next_color_NewGridBand_, this, "New GridBand Messages Color");
if (new_color.isValid ())
{
next_color_NewGridBand_ = new_color;
ui_->labNewGridBand->setStyleSheet(QString("background: %1").arg(next_color_NewGridBand_.name()));
}
}
void Configuration::impl::on_pbLoTW_clicked()
{
auto new_color = QColorDialog::getColor(next_color_LoTW_, this, "Not in LoTW Color");
if (new_color.isValid ()) {
next_color_LoTW_ = new_color;
ui_->labLoTW->setStyleSheet(QString("color: %1").arg(next_color_LoTW_.name()));
}
}
void Configuration::impl::on_pbResetDefaults_clicked()
{
next_color_CQ_ = color_CQ_ = "#66ff66";
next_color_MyCall_ = color_MyCall_ = "#ff6666";
next_color_TxMsg_ = color_TxMsg_ = "#ffff00";
next_color_DXCC_ = color_DXCC_ = "#ff00ff";
next_color_DXCCband_ = color_DXCCband_ = "#ffaaff";
next_color_NewCall_ = color_NewCall_ = "#66b2ff";
next_color_NewCallBand_ = color_NewCallBand_ = "#99ffff";
next_color_NewGrid_ = color_NewGrid_ = "#ffaa00";
next_color_NewGridBand_ = color_NewGridBand_ = "#ffcc99";
next_color_LoTW_ = color_LoTW_ = "#5500ff";
ui_->labCQ->setStyleSheet(QString("background: %1").arg(next_color_CQ_.name()));
ui_->labMyCall->setStyleSheet(QString("background: %1").arg(next_color_MyCall_.name()));
ui_->labTx->setStyleSheet(QString("background: %1").arg(next_color_TxMsg_.name()));
ui_->labDXCC->setStyleSheet(QString("background: %1").arg(next_color_DXCC_.name()));
ui_->labDXCCband->setStyleSheet(QString("background: %1").arg(next_color_DXCCband_.name()));
ui_->labNewCall->setStyleSheet(QString("background: %1").arg(next_color_NewCall_.name()));
ui_->labNewCallBand->setStyleSheet(QString("background: %1").arg(next_color_NewCallBand_.name()));
ui_->labNewGrid->setStyleSheet(QString("background: %1").arg(next_color_NewGrid_.name()));
ui_->labNewGridBand->setStyleSheet(QString("background: %1").arg(next_color_NewGridBand_.name()));
ui_->labLoTW->setStyleSheet(QString("color: %1").arg(next_color_LoTW_.name()));
} }
void Configuration::impl::on_decoded_text_font_push_button_clicked () void Configuration::impl::on_decoded_text_font_push_button_clicked ()
{ {
next_decoded_text_font_ = QFontDialog::getFont (0, decoded_text_font_ , this next_decoded_text_font_ = QFontDialog::getFont (0, decoded_text_font_ , this
, tr ("WSJT-X Decoded Text Font Chooser") , tr ("WSJT-X Decoded Text Font Chooser")
#if QT_VERSION >= 0x050201
, QFontDialog::MonospacedFonts , QFontDialog::MonospacedFonts
#endif
); );
} }
@ -2347,6 +2214,20 @@ void Configuration::impl::on_add_macro_line_edit_editingFinished ()
ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ()); ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ());
} }
void Configuration::impl::on_FieldDay_Exchange_textChanged()
{
bool b=ui_->FieldDay_Exchange->hasAcceptableInput() or !ui_->rbFieldDay->isChecked();
if(b) ui_->FieldDay_Exchange->setStyleSheet("color: black");
if(!b) ui_->FieldDay_Exchange->setStyleSheet("color: red");
}
void Configuration::impl::on_RTTY_Exchange_textChanged()
{
bool b=ui_->RTTY_Exchange->hasAcceptableInput() or !ui_->rbRTTYroundup->isChecked();
if(b) ui_->RTTY_Exchange->setStyleSheet("color: black");
if(!b) ui_->RTTY_Exchange->setStyleSheet("color: red");
}
void Configuration::impl::on_delete_macro_push_button_clicked (bool /* checked */) void Configuration::impl::on_delete_macro_push_button_clicked (bool /* checked */)
{ {
auto selection_model = ui_->macros_list_view->selectionModel (); auto selection_model = ui_->macros_list_view->selectionModel ();
@ -2577,6 +2458,16 @@ void Configuration::impl::on_calibration_slope_ppm_spin_box_valueChanged (double
rig_active_ = false; // force reset rig_active_ = false; // force reset
} }
void Configuration::impl::on_prompt_to_log_check_box_clicked(bool checked)
{
if(checked) ui_->cbAutoLog->setChecked(false);
}
void Configuration::impl::on_cbAutoLog_clicked(bool checked)
{
if(checked) ui_->prompt_to_log_check_box->setChecked(false);
}
void Configuration::impl::on_cbFox_clicked (bool checked) void Configuration::impl::on_cbFox_clicked (bool checked)
{ {
if(checked) { if(checked) {
@ -2598,11 +2489,10 @@ void Configuration::impl::on_cbHound_clicked (bool checked)
void Configuration::impl::chk77() void Configuration::impl::chk77()
{ {
bool b77OK = !ui_->cbFox->isChecked() and !ui_->cbHound->isChecked(); bool b77OK = !ui_->cbFox->isChecked() and !ui_->cbHound->isChecked();
ui_->groupBox_8->setEnabled(b77OK);
ui_->groupBox_9->setEnabled(b77OK); ui_->groupBox_9->setEnabled(b77OK);
if(!b77OK) { if(!b77OK) {
ui_->cbGenerate77->setChecked(false); ui_->cbGenerate77->setChecked(true);
ui_->cbDecode77->setChecked(false); ui_->cbDecode77->setChecked(true);
} }
} }
@ -2611,6 +2501,16 @@ void Configuration::impl::on_rbNone_toggled(bool b)
if(!b) ui_->cbGenerate77->setChecked(true); if(!b) ui_->cbGenerate77->setChecked(true);
} }
void Configuration::impl::on_rbFieldDay_toggled()
{
on_FieldDay_Exchange_textChanged();
}
void Configuration::impl::on_rbRTTYroundup_toggled()
{
on_RTTY_Exchange_textChanged();
}
void Configuration::impl::on_cbx2ToneSpacing_clicked(bool b) void Configuration::impl::on_cbx2ToneSpacing_clicked(bool b)
{ {
if(b) ui_->cbx4ToneSpacing->setChecked(false); if(b) ui_->cbx4ToneSpacing->setChecked(false);
@ -3021,11 +2921,6 @@ auto Configuration::impl::remove_calibration (Frequency f) const -> Frequency
/ (1. + calibration_.slope_ppm / 1.e6)); / (1. + calibration_.slope_ppm / 1.e6));
} }
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (Configuration, DataMode);
ENUM_QDEBUG_OPS_IMPL (Configuration, Type2MsgGen);
#endif
ENUM_QDATASTREAM_OPS_IMPL (Configuration, DataMode); ENUM_QDATASTREAM_OPS_IMPL (Configuration, DataMode);
ENUM_QDATASTREAM_OPS_IMPL (Configuration, Type2MsgGen); ENUM_QDATASTREAM_OPS_IMPL (Configuration, Type2MsgGen);

View File

@ -16,11 +16,14 @@ class QWidget;
class QAudioDeviceInfo; class QAudioDeviceInfo;
class QString; class QString;
class QDir; class QDir;
class QNetworkAccessManager;
class Bands; class Bands;
class FrequencyList_v2; class FrequencyList_v2;
class StationList; class StationList;
class QStringListModel; class QStringListModel;
class QHostAddress; class QHostAddress;
class LotWUsers;
class DecodeHighlightingModel;
// //
// Class Configuration // Class Configuration
@ -56,7 +59,6 @@ class Configuration final
: public QObject : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS (DataMode Type2MsgGen)
public: public:
using MODE = Transceiver::MODE; using MODE = Transceiver::MODE;
@ -69,7 +71,7 @@ public:
enum Type2MsgGen {type_2_msg_1_full, type_2_msg_3_full, type_2_msg_5_only}; enum Type2MsgGen {type_2_msg_1_full, type_2_msg_3_full, type_2_msg_5_only};
Q_ENUM (Type2MsgGen) Q_ENUM (Type2MsgGen)
explicit Configuration (QDir const& temp_directory, QSettings * settings, explicit Configuration (QNetworkAccessManager *, QDir const& temp_directory, QSettings * settings,
QWidget * parent = nullptr); QWidget * parent = nullptr);
~Configuration (); ~Configuration ();
@ -115,6 +117,7 @@ public:
bool log_as_RTTY () const; bool log_as_RTTY () const;
bool report_in_comments () const; bool report_in_comments () const;
bool prompt_to_log () const; bool prompt_to_log () const;
bool autoLog() const;
bool insert_blank () const; bool insert_blank () const;
bool DXCC () const; bool DXCC () const;
bool ppfx() const; bool ppfx() const;
@ -169,18 +172,10 @@ public:
QDir azel_directory () const; QDir azel_directory () const;
QString rig_name () const; QString rig_name () const;
Type2MsgGen type_2_msg_gen () const; Type2MsgGen type_2_msg_gen () const;
QColor color_CQ () const;
QColor color_MyCall () const;
QColor color_TxMsg () const;
QColor color_DXCC () const;
QColor color_DXCCband () const;
QColor color_NewCall () const;
QColor color_NewCallBand () const;
QColor color_NewGrid () const;
QColor color_NewGridBand () const;
QColor color_LoTW() const;
bool pwrBandTxMemory () const; bool pwrBandTxMemory () const;
bool pwrBandTuneMemory () const; bool pwrBandTuneMemory () const;
LotWUsers const& lotw_users () const;
DecodeHighlightingModel const& decode_highlighting () const;
struct CalibrationParams struct CalibrationParams
{ {
@ -239,8 +234,6 @@ public:
Q_SLOT void transceiver_tx_frequency (Frequency = 0u); Q_SLOT void transceiver_tx_frequency (Frequency = 0u);
// Set transceiver mode. // Set transceiver mode.
//
// Rationalise means ensure TX uses same mode as RX.
Q_SLOT void transceiver_mode (MODE); Q_SLOT void transceiver_mode (MODE);
// Set/unset PTT. // Set/unset PTT.
@ -265,15 +258,17 @@ public:
// These signals indicate a font has been selected and accepted for // These signals indicate a font has been selected and accepted for
// the application text and decoded text respectively. // the application text and decoded text respectively.
// //
Q_SIGNAL void text_font_changed (QFont); Q_SIGNAL void text_font_changed (QFont) const;
Q_SIGNAL void decoded_text_font_changed (QFont); Q_SIGNAL void decoded_text_font_changed (QFont) const;
// //
// This signal is emitted when the UDP server changes // This signal is emitted when the UDP server changes
// //
Q_SIGNAL void udp_server_changed (QString const& udp_server); Q_SIGNAL void udp_server_changed (QString const& udp_server) const;
Q_SIGNAL void udp_server_port_changed (port_type server_port); Q_SIGNAL void udp_server_port_changed (port_type server_port) const;
// signal updates to decode highlighting
Q_SIGNAL void decode_highlighting_changed (DecodeHighlightingModel const&) const;
// //
// These signals are emitted and reflect transceiver state changes // These signals are emitted and reflect transceiver state changes
@ -295,16 +290,6 @@ private:
pimpl<impl> m_; pimpl<impl> m_;
}; };
#if QT_VERSION < 0x050500
Q_DECLARE_METATYPE (Configuration::DataMode);
Q_DECLARE_METATYPE (Configuration::Type2MsgGen);
#endif
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_DECL (Configuration, DataMode);
ENUM_QDEBUG_OPS_DECL (Configuration, Type2MsgGen);
#endif
ENUM_QDATASTREAM_OPS_DECL (Configuration, DataMode); ENUM_QDATASTREAM_OPS_DECL (Configuration, DataMode);
ENUM_QDATASTREAM_OPS_DECL (Configuration, Type2MsgGen); ENUM_QDATASTREAM_OPS_DECL (Configuration, Type2MsgGen);

View File

@ -74,7 +74,7 @@
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLineEdit" name="grid_line_edit"> <widget class="QLineEdit" name="grid_line_edit">
<property name="toolTip"> <property name="toolTip">
<string>Maidenhead locator (only the first four characters are required).</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maidenhead locator, preferably 6 characters.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -103,7 +103,11 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QComboBox" name="region_combo_box"/> <widget class="QComboBox" name="region_combo_box">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select your IARU region.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
@ -1700,26 +1704,12 @@ QListView::item:hover {
<property name="text"> <property name="text">
<string>Op Call:</string> <string>Op Call:</string>
</property> </property>
</widget> <property name="buddy">
</item> <cstring>opCallEntry</cstring>
<item row="0" column="3">
<widget class="QLineEdit" name="opCallEntry">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The callsign of the operator, if different from the station callsign.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="3" column="0">
<widget class="QCheckBox" name="log_as_RTTY_check_box">
<property name="toolTip">
<string>Some logging programs will not accept JT-65 or JT9 as a recognized mode.</string>
</property>
<property name="text">
<string>Con&amp;vert mode to RTTY</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="report_in_comments_check_box"> <widget class="QCheckBox" name="report_in_comments_check_box">
<property name="toolTip"> <property name="toolTip">
<string>Some logging programs will not accept the type of reports <string>Some logging programs will not accept the type of reports
@ -1732,7 +1722,7 @@ comments field.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="2"> <item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="clear_DX_check_box"> <widget class="QCheckBox" name="clear_DX_check_box">
<property name="toolTip"> <property name="toolTip">
<string>Check this option to force the clearing of the DX Call <string>Check this option to force the clearing of the DX Call
@ -1743,6 +1733,33 @@ and DX Grid fields when a 73 or free text message is sent.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QCheckBox" name="log_as_RTTY_check_box">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Some logging programs will not accept WSJT-X mode names.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Con&amp;vert mode to RTTY</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="opCallEntry">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The callsign of the operator, if different from the station callsign.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="cbAutoLog">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check to have QSOs logged automatically, when complete.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Log automatically</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -1895,6 +1912,9 @@ for assessing propagation and system performance.</string>
<property name="text"> <property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;N1MM Server name or IP address:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;N1MM Server name or IP address:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="buddy">
<cstring>n1mm_server_name_line_edit</cstring>
</property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
@ -1909,6 +1929,9 @@ for assessing propagation and system performance.</string>
<property name="text"> <property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;N1MM Server port number:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;N1MM Server port number:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="buddy">
<cstring>n1mm_server_port_spin_box</cstring>
</property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
@ -2152,8 +2175,158 @@ Right click for insert and delete options.</string>
<attribute name="title"> <attribute name="title">
<string>Colors</string> <string>Colors</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_5" rowstretch="1,0,0" columnstretch="1,0,0"> <layout class="QVBoxLayout" name="verticalLayout_7">
<item row="0" column="1"> <item>
<widget class="QGroupBox" name="groupBox_12">
<property name="title">
<string>Decode Highlightling</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="DecodeHighlightingListView" name="highlighting_list_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable using the check boxes and right-click an item to change the foreground color, background color, or reset the item to default values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="reset_highlighting_to_defaults_push_button">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Push to reset all highlight items above to default values and priorities.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Reset Highlighting</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_11">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Controls for Logbook of the World user lookup.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="title">
<string>Logbook of the World User Validation</string>
</property>
<layout class="QFormLayout" name="formLayout_18">
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Age of last upload less than:</string>
</property>
<property name="buddy">
<cstring>LotW_days_since_upload_spin_box</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="LotW_days_since_upload_spin_box">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Adjust this spin box to set the age threshold of LotW user's last upload date that is accepted as a current LotW user.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="suffix">
<string> days</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>365</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Users CSV file URL:</string>
</property>
<property name="buddy">
<cstring>LotW_CSV_URL_line_edit</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_20">
<item>
<widget class="QLineEdit" name="LotW_CSV_URL_line_edit">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;URL of the ARRL LotW user's last upload dates and times data file which is used to highlight decodes from stations that are known to upload their log file to LotW.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>https://lotw.arrl.org/lotw-user-activity.csv</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="LotW_CSV_fetch_push_button">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Push this button to fetch the latest LotW user's upload date and time data file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Fetch Now</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<spacer name="horizontalSpacer_8"> <spacer name="horizontalSpacer_8">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -2166,317 +2339,6 @@ Right click for insert and delete options.</string>
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_13">
<item row="9" column="1">
<widget class="QLabel" name="labLoTW">
<property name="styleSheet">
<string notr="true">QLabel{color: #990000}</string>
</property>
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="pbMyCall">
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>My Call in message</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QPushButton" name="pbNewDXCCband">
<property name="text">
<string>New DXCC on Band</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="labDXCCband">
<property name="styleSheet">
<string notr="true">QLabel{background-color: #ffaaff}
</string>
</property>
<property name="text">
<string notr="true">K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="pbCQmsg">
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>CQ in message</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="labTx">
<property name="minimumSize">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QLabel{background-color: yellow}</string>
</property>
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="pbTxMsg">
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Transmitted message</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="labMyCall">
<property name="minimumSize">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QLabel{background-color: #ff6666}</string>
</property>
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="labCQ">
<property name="minimumSize">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QLabel{background-color: #66ff66}</string>
</property>
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="labDXCC">
<property name="minimumSize">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QLabel{background-color: #ff00ff}</string>
</property>
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QPushButton" name="pbResetDefaults">
<property name="text">
<string>Reset Defaults</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="pbNewDXCC">
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>New DXCC</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="labNewGrid">
<property name="styleSheet">
<string notr="true">QLabel{background-color: #ff8000}</string>
</property>
<property name="text">
<string notr="true">K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="labNewGridBand">
<property name="styleSheet">
<string notr="true">QLabel{background-color: #ffcc99}</string>
</property>
<property name="text">
<string notr="true">K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="labNewCall">
<property name="minimumSize">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QLabel{background-color: #00ffff}</string>
</property>
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="pbNewGrid">
<property name="text">
<string>New grid</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="pbNewGridBand">
<property name="text">
<string>New Grid on Band</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="labNewCallBand">
<property name="styleSheet">
<string notr="true">QLabel{background-color: #99ffff}</string>
</property>
<property name="text">
<string notr="true">K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QPushButton" name="pbNewCall">
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>New Call</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QPushButton" name="pbNewCallBand">
<property name="text">
<string>New Call on Band</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QPushButton" name="pbLoTW">
<property name="text">
<string>LoTW</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer_10">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>120</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>150</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="advanced_tab"> <widget class="QWidget" name="advanced_tab">
@ -2560,6 +2422,9 @@ Right click for insert and delete options.</string>
<layout class="QHBoxLayout" name="horizontalLayout_15"> <layout class="QHBoxLayout" name="horizontalLayout_15">
<item> <item>
<widget class="QCheckBox" name="cbGenerate77"> <widget class="QCheckBox" name="cbGenerate77">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;By default, early candidate releases of WSJT-X 2.0 generate 75-bit messages if the message content allows it.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>Always generate 77-bit messages</string> <string>Always generate 77-bit messages</string>
</property> </property>
@ -2567,6 +2432,9 @@ Right click for insert and delete options.</string>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="cbDecode77"> <widget class="QCheckBox" name="cbDecode77">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check this box to ignore FT8 transmissions using the older 75-bit protocol.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>Decode only 77-bit messages</string> <string>Decode only 77-bit messages</string>
</property> </property>
@ -2759,6 +2627,9 @@ Right click for insert and delete options.</string>
<layout class="QGridLayout" name="gridLayout_15" columnstretch="1,2,1,0"> <layout class="QGridLayout" name="gridLayout_15" columnstretch="1,2,1,0">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QRadioButton" name="rbNone"> <widget class="QRadioButton" name="rbNone">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For normal operating&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>None</string> <string>None</string>
</property> </property>
@ -2775,6 +2646,9 @@ Right click for insert and delete options.</string>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;European VHF+ contests requiring a signal report, serial number, and 6-character locator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>EU VHF Contest</string> <string>EU VHF Contest</string>
</property> </property>
@ -2784,6 +2658,9 @@ Right click for insert and delete options.</string>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="2,1,1"> <layout class="QHBoxLayout" name="horizontalLayout_18" stretch="2,1,1">
<item> <item>
<widget class="QRadioButton" name="rbRTTYroundup"> <widget class="QRadioButton" name="rbRTTYroundup">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>ARRL RTTY Roundup</string> <string>ARRL RTTY Roundup</string>
</property> </property>
@ -2805,7 +2682,7 @@ Right click for insert and delete options.</string>
<item> <item>
<layout class="QFormLayout" name="formLayout_17"> <layout class="QFormLayout" name="formLayout_17">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_15"> <widget class="QLabel" name="labRTTY">
<property name="text"> <property name="text">
<string>Exch:</string> <string>Exch:</string>
</property> </property>
@ -2822,6 +2699,9 @@ Right click for insert and delete options.</string>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>NJ</string> <string>NJ</string>
</property> </property>
@ -2838,6 +2718,9 @@ Right click for insert and delete options.</string>
<layout class="QHBoxLayout" name="horizontalLayout_17" stretch="2,1,1"> <layout class="QHBoxLayout" name="horizontalLayout_17" stretch="2,1,1">
<item> <item>
<widget class="QRadioButton" name="rbFieldDay"> <widget class="QRadioButton" name="rbFieldDay">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL Field Day exchange: number of transmitters, Class, and ARRL/RAC section or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>ARRL Field Day</string> <string>ARRL Field Day</string>
</property> </property>
@ -2859,7 +2742,7 @@ Right click for insert and delete options.</string>
<item> <item>
<layout class="QFormLayout" name="formLayout_16"> <layout class="QFormLayout" name="formLayout_16">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_14"> <widget class="QLabel" name="labFD">
<property name="text"> <property name="text">
<string>Exch:</string> <string>Exch:</string>
</property> </property>
@ -2876,6 +2759,9 @@ Right click for insert and delete options.</string>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL Field Day exchange: number of transmitters, Class, and ARRL/RAC section or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>6A SNJ</string> <string>6A SNJ</string>
</property> </property>
@ -2896,6 +2782,9 @@ Right click for insert and delete options.</string>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>NA VHF Contest</string> <string>NA VHF Contest</string>
</property> </property>
@ -2937,9 +2826,7 @@ Right click for insert and delete options.</string>
<item> <item>
<widget class="QDialogButtonBox" name="configuration_dialog_button_box"> <widget class="QDialogButtonBox" name="configuration_dialog_button_box">
<property name="toolTip"> <property name="toolTip">
<string>Discard or apply configuration changes including <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Discard (Cancel) or apply (OK) configuration changes including&lt;/p&gt;&lt;p&gt;resetting the radio interface and applying any soundcard changes&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
resetting the radio interface and applying any
soundcard changes</string>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -2951,36 +2838,49 @@ soundcard changes</string>
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>DecodeHighlightingListView</class>
<extends>QListView</extends>
<header>DecodehigHlightingListView.hpp</header>
</customwidget>
</customwidgets>
<tabstops> <tabstops>
<tabstop>configuration_tabs</tabstop> <tabstop>configuration_tabs</tabstop>
<tabstop>callsign_line_edit</tabstop> <tabstop>callsign_line_edit</tabstop>
<tabstop>grid_line_edit</tabstop> <tabstop>grid_line_edit</tabstop>
<tabstop>use_dynamic_grid</tabstop>
<tabstop>region_combo_box</tabstop> <tabstop>region_combo_box</tabstop>
<tabstop>type_2_msg_gen_combo_box</tabstop> <tabstop>type_2_msg_gen_combo_box</tabstop>
<tabstop>insert_blank_check_box</tabstop> <tabstop>insert_blank_check_box</tabstop>
<tabstop>miles_check_box</tabstop> <tabstop>miles_check_box</tabstop>
<tabstop>TX_messages_check_box</tabstop> <tabstop>TX_messages_check_box</tabstop>
<tabstop>DXCC_check_box</tabstop> <tabstop>DXCC_check_box</tabstop>
<tabstop>ppfx_check_box</tabstop>
<tabstop>font_push_button</tabstop> <tabstop>font_push_button</tabstop>
<tabstop>decoded_text_font_push_button</tabstop> <tabstop>decoded_text_font_push_button</tabstop>
<tabstop>monitor_off_check_box</tabstop> <tabstop>monitor_off_check_box</tabstop>
<tabstop>monitor_last_used_check_box</tabstop> <tabstop>monitor_last_used_check_box</tabstop>
<tabstop>quick_call_check_box</tabstop> <tabstop>quick_call_check_box</tabstop>
<tabstop>tx_watchdog_spin_box</tabstop> <tabstop>disable_TX_on_73_check_box</tabstop>
<tabstop>CW_id_after_73_check_box</tabstop> <tabstop>CW_id_after_73_check_box</tabstop>
<tabstop>enable_VHF_features_check_box</tabstop> <tabstop>enable_VHF_features_check_box</tabstop>
<tabstop>tx_QSY_check_box</tabstop> <tabstop>tx_QSY_check_box</tabstop>
<tabstop>single_decode_check_box</tabstop> <tabstop>single_decode_check_box</tabstop>
<tabstop>decode_at_52s_check_box</tabstop> <tabstop>decode_at_52s_check_box</tabstop>
<tabstop>tx_watchdog_spin_box</tabstop>
<tabstop>CW_id_interval_spin_box</tabstop> <tabstop>CW_id_interval_spin_box</tabstop>
<tabstop>rig_combo_box</tabstop> <tabstop>rig_combo_box</tabstop>
<tabstop>CAT_poll_interval_spin_box</tabstop> <tabstop>CAT_poll_interval_spin_box</tabstop>
<tabstop>CAT_port_combo_box</tabstop> <tabstop>CAT_port_combo_box</tabstop>
<tabstop>CAT_serial_baud_combo_box</tabstop> <tabstop>CAT_serial_baud_combo_box</tabstop>
<tabstop>CAT_default_bit_radio_button</tabstop>
<tabstop>CAT_7_bit_radio_button</tabstop> <tabstop>CAT_7_bit_radio_button</tabstop>
<tabstop>CAT_8_bit_radio_button</tabstop> <tabstop>CAT_8_bit_radio_button</tabstop>
<tabstop>CAT_default_stop_bit_radio_button</tabstop>
<tabstop>CAT_one_stop_bit_radio_button</tabstop> <tabstop>CAT_one_stop_bit_radio_button</tabstop>
<tabstop>CAT_two_stop_bit_radio_button</tabstop> <tabstop>CAT_two_stop_bit_radio_button</tabstop>
<tabstop>CAT_handshake_default_radio_button</tabstop>
<tabstop>CAT_handshake_none_radio_button</tabstop> <tabstop>CAT_handshake_none_radio_button</tabstop>
<tabstop>CAT_handshake_xon_radio_button</tabstop> <tabstop>CAT_handshake_xon_radio_button</tabstop>
<tabstop>CAT_handshake_hardware_radio_button</tabstop> <tabstop>CAT_handshake_hardware_radio_button</tabstop>
@ -3014,29 +2914,48 @@ soundcard changes</string>
<tabstop>delete_macro_push_button</tabstop> <tabstop>delete_macro_push_button</tabstop>
<tabstop>macros_list_view</tabstop> <tabstop>macros_list_view</tabstop>
<tabstop>prompt_to_log_check_box</tabstop> <tabstop>prompt_to_log_check_box</tabstop>
<tabstop>cbAutoLog</tabstop>
<tabstop>log_as_RTTY_check_box</tabstop> <tabstop>log_as_RTTY_check_box</tabstop>
<tabstop>report_in_comments_check_box</tabstop> <tabstop>report_in_comments_check_box</tabstop>
<tabstop>clear_DX_check_box</tabstop> <tabstop>clear_DX_check_box</tabstop>
<tabstop>opCallEntry</tabstop>
<tabstop>psk_reporter_check_box</tabstop> <tabstop>psk_reporter_check_box</tabstop>
<tabstop>udp_server_line_edit</tabstop> <tabstop>udp_server_line_edit</tabstop>
<tabstop>udp_server_port_spin_box</tabstop> <tabstop>udp_server_port_spin_box</tabstop>
<tabstop>accept_udp_requests_check_box</tabstop> <tabstop>accept_udp_requests_check_box</tabstop>
<tabstop>udpWindowToFront</tabstop> <tabstop>udpWindowToFront</tabstop>
<tabstop>udpWindowRestore</tabstop> <tabstop>udpWindowRestore</tabstop>
<tabstop>enable_n1mm_broadcast_check_box</tabstop>
<tabstop>n1mm_server_name_line_edit</tabstop>
<tabstop>n1mm_server_port_spin_box</tabstop>
<tabstop>calibration_slope_ppm_spin_box</tabstop> <tabstop>calibration_slope_ppm_spin_box</tabstop>
<tabstop>calibration_intercept_spin_box</tabstop> <tabstop>calibration_intercept_spin_box</tabstop>
<tabstop>frequencies_table_view</tabstop> <tabstop>frequencies_table_view</tabstop>
<tabstop>stations_table_view</tabstop> <tabstop>stations_table_view</tabstop>
<tabstop>pbCQmsg</tabstop> <tabstop>highlighting_list_view</tabstop>
<tabstop>pbMyCall</tabstop> <tabstop>reset_highlighting_to_defaults_push_button</tabstop>
<tabstop>pbTxMsg</tabstop> <tabstop>LotW_CSV_URL_line_edit</tabstop>
<tabstop>pbNewDXCC</tabstop> <tabstop>LotW_CSV_fetch_push_button</tabstop>
<tabstop>LotW_days_since_upload_spin_box</tabstop>
<tabstop>sbNtrials</tabstop> <tabstop>sbNtrials</tabstop>
<tabstop>sbAggressive</tabstop> <tabstop>sbAggressive</tabstop>
<tabstop>cbTwoPass</tabstop> <tabstop>cbTwoPass</tabstop>
<tabstop>sbDegrade</tabstop> <tabstop>sbDegrade</tabstop>
<tabstop>sbBandwidth</tabstop> <tabstop>sbBandwidth</tabstop>
<tabstop>sbTxDelay</tabstop> <tabstop>sbTxDelay</tabstop>
<tabstop>cbx2ToneSpacing</tabstop>
<tabstop>cbx4ToneSpacing</tabstop>
<tabstop>cbFox</tabstop>
<tabstop>cbHound</tabstop>
<tabstop>cbGenerate77</tabstop>
<tabstop>cbDecode77</tabstop>
<tabstop>rbNone</tabstop>
<tabstop>rbNA_VHF_Contest</tabstop>
<tabstop>rbEU_VHF_Contest</tabstop>
<tabstop>rbFieldDay</tabstop>
<tabstop>FieldDay_Exchange</tabstop>
<tabstop>rbRTTYroundup</tabstop>
<tabstop>RTTY_Exchange</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections> <connections>
@ -3106,12 +3025,12 @@ soundcard changes</string>
</connection> </connection>
</connections> </connections>
<buttongroups> <buttongroups>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="split_mode_button_group"/> <buttongroup name="split_mode_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/> <buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="PTT_method_button_group"/> <buttongroup name="PTT_method_button_group"/>
</buttongroups> </buttongroups>
</ui> </ui>

View File

@ -0,0 +1,77 @@
#include "DecodeHighlightingListView.hpp"
#include <QAction>
#include <QColorDialog>
#include "DecodeHighlightingModel.hpp"
#include "MessageBox.hpp"
#include "pimpl_impl.hpp"
class DecodeHighlightingListView::impl final
{
public:
impl ()
: fg_colour_action_ {tr ("&Foreground color ..."), nullptr}
, bg_colour_action_ {tr ("&Background color ..."), nullptr}
, defaults_action_ {tr ("&Reset this item to defaults"), nullptr}
{
}
DecodeHighlightingListView * self_;
QAction fg_colour_action_;
QAction bg_colour_action_;
QAction defaults_action_;
};
DecodeHighlightingListView::DecodeHighlightingListView (QWidget * parent)
: QListView {parent}
{
addAction (&m_->fg_colour_action_);
addAction (&m_->bg_colour_action_);
addAction (&m_->defaults_action_);
connect (&m_->fg_colour_action_, &QAction::triggered, [this] (bool /*checked*/) {
auto const& index = currentIndex ();
auto colour = QColorDialog::getColor (model ()->data (index, Qt::ForegroundRole).value<QBrush> ().color ()
, this
, tr ("Choose %1 Foreground Color")
.arg (model ()->data (index).toString ()));
if (colour.isValid ())
{
model ()->setData (index, colour, Qt::ForegroundRole);
}
});
connect (&m_->bg_colour_action_, &QAction::triggered, [this] (bool /*checked*/) {
auto const& index = currentIndex ();
auto colour = QColorDialog::getColor (model ()->data (index, Qt::BackgroundRole).value<QBrush> ().color ()
, this
, tr ("Choose %1 Background Color")
.arg (model ()->data (index).toString ()));
if (colour.isValid ())
{
model ()->setData (index, colour, Qt::BackgroundRole);
}
});
connect (&m_->defaults_action_, &QAction::triggered, [this] (bool /*checked*/) {
auto const& index = currentIndex ();
model ()->setData (index, model ()->data (index, DecodeHighlightingModel::EnabledDefaultRole).toBool () ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
model ()->setData (index, model ()->data (index, DecodeHighlightingModel::ForegroundDefaultRole), Qt::ForegroundRole);
model ()->setData (index, model ()->data (index, DecodeHighlightingModel::BackgroundDefaultRole), Qt::BackgroundRole);
});
}
DecodeHighlightingListView::~DecodeHighlightingListView ()
{
}
QSize DecodeHighlightingListView::sizeHint () const
{
auto item_height = sizeHintForRow (0);
if (item_height >= 0)
{
// set the height hint to exactly the space required for all the
// items
return {width (), (model ()->rowCount () * (item_height + 2 * spacing ())) + 2 * frameWidth ()};
}
return QListView::sizeHint ();
}

View File

@ -0,0 +1,32 @@
#ifndef DECODE_HIGHLIGHTING_LIST_VIEW_HPP_
#define DECODE_HIGHLIGHTING_LIST_VIEW_HPP_
#include <QListView>
#include "pimpl_h.hpp"
class QWidget;
// Class Decode Highlighting List View
//
// Sub-class of a QListView that adds a context menu to adjust the
// foreground and background colour roles of the the underlying model
// item that lies at the context menu right-click position. It also
// constrains the vertical size hint to limit the height to exactly
// that of the sum of the items.
//
class DecodeHighlightingListView final
: public QListView
{
public:
explicit DecodeHighlightingListView (QWidget * parent = nullptr);
~DecodeHighlightingListView ();
private:
QSize sizeHint () const override;
class impl;
pimpl<impl> m_;
};
#endif

319
DecodeHighlightingModel.cpp Normal file
View File

@ -0,0 +1,319 @@
#include "DecodeHighlightingModel.hpp"
#include <QString>
#include <QVariant>
#include <QList>
#include <QBrush>
#include <QFont>
#include <QMap>
#include <QVector>
#include <QDataStream>
#include <QMetaType>
#include <QDebug>
#include "pimpl_impl.hpp"
#include "moc_DecodeHighlightingModel.cpp"
class DecodeHighlightingModel::impl final
{
public:
explicit impl ()
: data_ {defaults_}
{
}
HighlightItems static const defaults_;
HighlightItems data_;
QFont font_;
};
QList<DecodeHighlightingModel::HighlightInfo> const DecodeHighlightingModel::impl::defaults_ = {
{Highlight::CQ, true, {}, {{0x66, 0xff, 0x66}}}
, {Highlight::MyCall, true, {}, {{0xff, 0x66, 0x66}}}
, {Highlight::Tx, true, {}, {{Qt::yellow}}}
, {Highlight::DXCC, true, {}, {{0xff, 0x00, 0xff}}}
, {Highlight::DXCCBand, true, {}, {{0xff, 0xaa, 0xff}}}
, {Highlight::Grid, false, {}, {{0xff, 0x80, 0x00}}}
, {Highlight::GridBand, false, {}, {{0xff, 0xcc, 0x99}}}
, {Highlight::Call, false, {}, {{0x00, 0xff, 0xff}}}
, {Highlight::CallBand, false, {}, {{0x99, 0xff, 0xff}}}
, {Highlight::LotW, false, {{0x99, 0x00, 0x00}}, {}}
};
bool operator == (DecodeHighlightingModel::HighlightInfo const& lhs, DecodeHighlightingModel::HighlightInfo const& rhs)
{
return lhs.type_ == rhs.type_
&& lhs.enabled_ == rhs.enabled_
&& lhs.foreground_ == rhs.foreground_
&& lhs.background_ == rhs.background_;
}
QDataStream& operator << (QDataStream& os, DecodeHighlightingModel::HighlightInfo const& item)
{
return os << item.type_
<< item.enabled_
<< item.foreground_
<< item.background_;
}
QDataStream& operator >> (QDataStream& is, DecodeHighlightingModel::HighlightInfo& item)
{
return is >> item.type_
>> item.enabled_
>> item.foreground_
>> item.background_;
}
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug debug, DecodeHighlightingModel::HighlightInfo const& item)
{
QDebugStateSaver save {debug};
debug.nospace () << "HighlightInfo("
<< item.type_ << ", "
<< item.enabled_ << ", "
<< item.foreground_ << ", "
<< item.background_ << ')';
return debug;
}
#endif
ENUM_QDATASTREAM_OPS_IMPL (DecodeHighlightingModel, Highlight);
ENUM_CONVERSION_OPS_IMPL (DecodeHighlightingModel, Highlight);
DecodeHighlightingModel::DecodeHighlightingModel (QObject * parent)
: QAbstractListModel {parent}
{
}
DecodeHighlightingModel::~DecodeHighlightingModel ()
{
}
QString DecodeHighlightingModel::highlight_name (Highlight h)
{
switch (h)
{
case Highlight::CQ: return "CQ in message";
case Highlight::MyCall: return "My Call in message";
case Highlight::Tx: return "Transmitted message";
case Highlight::DXCC: return "New DXCC";
case Highlight::DXCCBand: return "New DXCC on Band";
case Highlight::Grid: return "New Grid";
case Highlight::GridBand: return "New Grid on Band";
case Highlight::Call: return "New Call";
case Highlight::CallBand: return "New Call on Band";
case Highlight::LotW: return "LotW User";
}
return "Unknown";
}
auto DecodeHighlightingModel::default_items () -> HighlightItems const&
{
return impl::defaults_;
}
auto DecodeHighlightingModel::items () const -> HighlightItems const&
{
return m_->data_;
}
void DecodeHighlightingModel::items (HighlightItems const& items)
{
m_->data_ = items;
QVector<int> roles;
roles << Qt::CheckStateRole << Qt::ForegroundRole << Qt::BackgroundRole;
Q_EMIT dataChanged (index (0, 0), index (rowCount () - 1, 0), roles);
}
void DecodeHighlightingModel::set_font (QFont const& font)
{
m_->font_ = font;
}
int DecodeHighlightingModel::rowCount (const QModelIndex& parent) const
{
return parent.isValid () ? 0 : m_->data_.size ();
}
QVariant DecodeHighlightingModel::data (const QModelIndex& index, int role) const
{
QVariant result;
if (index.isValid () && index.row () < rowCount ())
{
auto const& item = m_->data_[index.row ()];
switch (role)
{
case Qt::CheckStateRole:
result = item.enabled_ ? Qt::Checked : Qt::Unchecked;
break;
case Qt::DisplayRole:
result = highlight_name (item.type_);
break;
case Qt::ForegroundRole:
if (Qt::NoBrush != item.foreground_.style ())
{
result = item.foreground_;
}
break;
case Qt::BackgroundRole:
if (Qt::NoBrush != item.background_.style ())
{
result = item.background_;
}
break;
case Qt::FontRole:
result = m_->font_;
break;
case TypeRole:
result = static_cast<int> (item.type_);
break;
case EnabledDefaultRole:
for (auto const& default_item : impl::defaults_)
{
if (default_item.type_ == item.type_)
{
result = default_item.enabled_ ? Qt::Checked : Qt::Unchecked;
}
}
break;
case ForegroundDefaultRole:
for (auto const& default_item : impl::defaults_)
{
if (default_item.type_ == item.type_)
{
result = default_item.foreground_;
}
}
break;
case BackgroundDefaultRole:
for (auto const& default_item : impl::defaults_)
{
if (default_item.type_ == item.type_)
{
result = default_item.background_;
}
}
break;
}
}
return result;
}
// Override QAbstractItemModel::itemData() as it is used by the
// default mime encode routine used in drag'n'drop operations and we
// want to transport the type role, this is because the display role
// is derived from the type role.
QMap<int, QVariant> DecodeHighlightingModel::itemData (QModelIndex const& index) const
{
auto roles = QAbstractListModel::itemData (index);
QVariant variantData = data (index, TypeRole);
if (variantData.isValid ())
{
roles.insert (TypeRole, variantData);
}
return roles;
}
QVariant DecodeHighlightingModel::headerData (int /*section*/, Qt::Orientation orientation, int role) const
{
QVariant header;
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
{
header = tr ("Highlight Type");
}
return header;
}
Qt::ItemFlags DecodeHighlightingModel::flags (QModelIndex const& index) const
{
auto flags = QAbstractListModel::flags (index) | Qt::ItemIsDragEnabled;
if (index.isValid ())
{
flags |= Qt::ItemIsUserCheckable;
}
else
{
flags |= Qt::ItemIsDropEnabled;
}
return flags;
}
bool DecodeHighlightingModel::setData (QModelIndex const& index, QVariant const& value, int role)
{
bool ok {false};
if (index.isValid () && index.row () < rowCount ())
{
auto& item = m_->data_[index.row ()];
QVector<int> roles;
roles << role;
switch (role)
{
case Qt::DisplayRole:
case Qt::FontRole:
ok = true;
break;
case Qt::CheckStateRole:
if (item.enabled_ != (Qt::Checked == value))
{
item.enabled_ = Qt::Checked == value;
Q_EMIT dataChanged (index, index, roles);
}
ok = true;
break;
case Qt::ForegroundRole:
if (item.foreground_ != value.value<QBrush> ())
{
item.foreground_ = value.value<QBrush> ();
Q_EMIT dataChanged (index, index, roles);
}
ok = true;
break;
case Qt::BackgroundRole:
if (item.background_ != value.value<QBrush> ())
{
item.background_ = value.value<QBrush> ();
Q_EMIT dataChanged (index, index, roles);
}
ok = true;
break;
case TypeRole:
if (item.type_ != static_cast<Highlight> (value.toInt ()))
{
item.type_ = static_cast<Highlight> (value.toInt ());
roles << Qt::DisplayRole;
Q_EMIT dataChanged (index, index, roles);
}
ok = true;
break;
}
}
return ok;
}
Qt::DropActions DecodeHighlightingModel::supportedDropActions () const
{
return Qt::MoveAction;
}
bool DecodeHighlightingModel::insertRows (int row, int count, QModelIndex const& parent)
{
beginInsertRows (parent, row, row + count - 1);
for (int index = 0; index < count; ++index)
{
m_->data_.insert (row, HighlightInfo {Highlight::CQ, false, {}, {}});
}
endInsertRows ();
return true;
}
bool DecodeHighlightingModel::removeRows (int row, int count, QModelIndex const& parent)
{
beginRemoveRows (parent, row, row + count - 1);
for (int index = 0; index < count; ++index)
{
m_->data_.removeAt (row);
}
endRemoveRows ();
return true;
}

View File

@ -0,0 +1,77 @@
#ifndef DECODE_HIGHLIGHTING_MODEL_HPP_
#define DECODE_HIGHLIGHTING_MODEL_HPP_
#include <QAbstractListModel>
#include <QBrush>
#include <QList>
#include "qt_helpers.hpp"
#include "pimpl_h.hpp"
class QObject;
class QFont;
class QDataStream;
class QDebug;
class DecodeHighlightingModel final
: public QAbstractListModel
{
Q_OBJECT
public:
enum class Highlight : char {CQ, MyCall, Tx, DXCC, DXCCBand, Grid, GridBand, Call, CallBand, LotW};
Q_ENUM (Highlight)
static QString highlight_name (Highlight h);
struct HighlightInfo final
{
Highlight type_;
bool enabled_;
QBrush foreground_;
QBrush background_;
};
using HighlightItems = QList<HighlightInfo>;
explicit DecodeHighlightingModel (QObject * parent = 0);
~DecodeHighlightingModel();
// access to raw items nd default items
static HighlightItems const& default_items ();
HighlightItems const& items () const;
void items (HighlightItems const&);
void set_font (QFont const&);
enum DefaultRoles {TypeRole = Qt::UserRole, EnabledDefaultRole, ForegroundDefaultRole, BackgroundDefaultRole};
private:
// implement the QAbstractListModel interface
int rowCount (QModelIndex const& parent = QModelIndex()) const override;
QVariant data (QModelIndex const&, int role) const override;
QVariant headerData (int section, Qt::Orientation, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags (QModelIndex const&) const override;
bool setData (QModelIndex const& index, QVariant const& value, int role) override;
Qt::DropActions supportedDropActions () const override;
bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override;
bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override;
QMap<int, QVariant> itemData (QModelIndex const&) const override;
class impl;
pimpl<impl> m_;
};
bool operator == (DecodeHighlightingModel::HighlightInfo const&, DecodeHighlightingModel::HighlightInfo const&);
QDataStream& operator << (QDataStream&, DecodeHighlightingModel::HighlightInfo const&);
QDataStream& operator >> (QDataStream&, DecodeHighlightingModel::HighlightInfo&);
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug, DecodeHighlightingModel::HighlightInfo const&);
#endif
ENUM_QDATASTREAM_OPS_DECL (DecodeHighlightingModel, Highlight);
ENUM_CONVERSION_OPS_DECL (DecodeHighlightingModel, Highlight);
Q_DECLARE_METATYPE (DecodeHighlightingModel::HighlightInfo);
Q_DECLARE_METATYPE (DecodeHighlightingModel::HighlightItems);
#endif

65
ExchangeValidator.cpp Normal file
View File

@ -0,0 +1,65 @@
#include <QDebug>
#include "ExchangeValidator.hpp"
ExchangeValidator::ExchangeValidator (QObject * parent)
: QValidator {parent}
{
}
auto ExchangeValidator::validate (QString& input, int& length) const -> State
{
bool ok=false;
QStringList w=input.split(" ");
int nwords=w.size();
length=input.size();
input = input.toUpper ();
if(nwords==1 and length<=3) {
//ARRL RTTY Roundup
// ntype=4;
// ok=exch_valid_(&ntype, const_cast<char *>(input.toLatin1().constData()),length);
QStringList states;
states << "AL" << "AK" << "AZ" << "AR" << "CA" << "CO"
<< "CT" << "DE" << "FL" << "GA" << "HI" << "ID"
<< "IL" << "IN" << "IA" << "KS" << "KY" << "LA"
<< "ME" << "MD" << "MA" << "MI" << "MN" << "MS"
<< "MO" << "MT" << "NE" << "NV" << "NH" << "NJ"
<< "NM" << "NY" << "NC" << "ND" << "OH" << "OK"
<< "OR" << "PA" << "RI" << "SC" << "SD" << "TN"
<< "TX" << "UT" << "VT" << "VA" << "WA" << "WV"
<< "WI" << "WY" << "NB" << "NS" << "QC" << "ON"
<< "MB" << "SK" << "AB" << "BC" << "NWT" << "NF"
<< "LB" << "NU" << "YT" << "PEI" << "DC" << "DX";
if(states.contains(input)) ok=true;
}
if(nwords==2 and w.at(1).size()<=3) {
//ARRL Field Day
int n=w.at(0).size();
if(n>3) goto done;
int ntx=w.at(0).left(n-1).toInt();
if(ntx<1 or ntx>32) goto done;
QString c1=w.at(0).right(1);
if(c1<"A" or c1>"F") goto done;
QStringList sections;
sections << "AB" << "AK" << "AL" << "AR" << "AZ" << "BC"
<< "CO" << "CT" << "DE" << "EB" << "EMA" << "ENY"
<< "EPA" << "EWA" << "GA" << "GTA" << "IA" << "ID"
<< "IL" << "IN" << "KS" << "KY" << "LA" << "LAX"
<< "MAR" << "MB" << "MDC" << "ME" << "MI" << "MN"
<< "MO" << "MS" << "MT" << "NC" << "ND" << "NE"
<< "NFL" << "NH" << "NL" << "NLI" << "NM" << "NNJ"
<< "NNY" << "NT" << "NTX" << "NV" << "OH" << "OK"
<< "ONE" << "ONN" << "ONS" << "OR" << "ORG" << "PAC"
<< "PR" << "QC" << "RI" << "SB" << "SC" << "SCV"
<< "SD" << "SDG" << "SF" << "SFL" << "SJV" << "SK"
<< "SNJ" << "STX" << "SV" << "TN" << "UT" << "VA"
<< "VI" << "VT" << "WCF" << "WI" << "WMA" << "WNY"
<< "WPA" << "WTX" << "WV" << "WWA" << "WY" << "DX";
if(sections.contains(w.at(1))) ok=true;
}
done:
if(ok) return Acceptable;
return Intermediate;
}

19
ExchangeValidator.hpp Normal file
View File

@ -0,0 +1,19 @@
#ifndef EXCHANGE_VALIDATOR_HPP__
#define EXCHANGE_VALIDATOR_HPP__
#include <QValidator>
// ExchangeValidator - QValidator for Field Day and RTTY Roundup exchanges
class ExchangeValidator final
: public QValidator
{
public:
ExchangeValidator (QObject * parent = nullptr);
// QValidator implementation
State validate (QString& input, int& length) const override;
};
#endif

126
ExportCabrillo.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "ExportCabrillo.h"
#include "SettingsGroup.hpp"
#include "MessageBox.hpp"
#include <QApplication>
#include <QDebug>
#include <QFileDialog>
#include "ui_ExportCabrillo.h"
#include "moc_ExportCabrillo.cpp"
ExportCabrillo::ExportCabrillo(QSettings *settings, QWidget *parent) :
QDialog(parent),
settings_ {settings},
ui(new Ui::ExportCabrillo)
{
ui->setupUi(this);
read_settings();
setWindowTitle(QApplication::applicationName() + " - Export Cabrillo");
}
ExportCabrillo::~ExportCabrillo()
{
if(isVisible()) write_settings();
delete ui;
}
void ExportCabrillo::closeEvent (QCloseEvent * e)
{
write_settings();
QWidget::closeEvent(e);
}
void ExportCabrillo::read_settings ()
{
SettingsGroup group {settings_, "ExportCabrillo"};
restoreGeometry (settings_->value("window/geometry").toByteArray());
ui->lineEdit_1->setText(settings_->value("Location").toString());
ui->lineEdit_2->setText(settings_->value("Contest").toString());
ui->lineEdit_3->setText(settings_->value("Callsign").toString());
ui->lineEdit_4->setText(settings_->value("Category-Operator").toString());
ui->lineEdit_5->setText(settings_->value("Category-Transmitter").toString());
ui->lineEdit_6->setText(settings_->value("Category-Power").toString());
ui->lineEdit_7->setText(settings_->value("Category-Assisted").toString());
ui->lineEdit_8->setText(settings_->value("Category-Band").toString());
ui->lineEdit_9->setText(settings_->value("Claimed-Score").toString());
ui->lineEdit_10->setText(settings_->value("Operators").toString());
ui->lineEdit_11->setText(settings_->value("Club").toString());
ui->lineEdit_12->setText(settings_->value("Name").toString());
ui->lineEdit_13->setText(settings_->value("Address1").toString());
ui->lineEdit_14->setText(settings_->value("Address2").toString());
}
void ExportCabrillo::write_settings ()
{
SettingsGroup group {settings_, "ExportCabrillo"};
settings_->setValue ("window/geometry", saveGeometry ());
settings_->setValue("Location",ui->lineEdit_1->text());
settings_->setValue("Contest",ui->lineEdit_2->text());
settings_->setValue("Callsign",ui->lineEdit_3->text());
settings_->setValue("Category-Operator",ui->lineEdit_4->text());
settings_->setValue("Category-Transmitter",ui->lineEdit_5->text());
settings_->setValue("Category-Power",ui->lineEdit_6->text());
settings_->setValue("Category-Assisted",ui->lineEdit_7->text());
settings_->setValue("Category-Band",ui->lineEdit_8->text());
settings_->setValue("Claimed-Score",ui->lineEdit_9->text());
settings_->setValue("Operators",ui->lineEdit_10->text());
settings_->setValue("Club",ui->lineEdit_11->text());
settings_->setValue("Name",ui->lineEdit_12->text());
settings_->setValue("Address1",ui->lineEdit_13->text());
settings_->setValue("Address2",ui->lineEdit_14->text());
}
void ExportCabrillo::setFile(QString t)
{
m_CabLog=t;
}
void ExportCabrillo::on_pbSaveAs_clicked()
{
QString fname;
QFileDialog saveAs(this);
saveAs.setFileMode(QFileDialog::AnyFile);
fname=saveAs.getSaveFileName(this, "Save File", "","Cabrillo Log (*.log)");
QFile f {fname};
if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&f);
out << "START-OF-LOG:3.0" << endl
<< "LOCATION: " << ui->lineEdit_1->text() << endl
<< "CONTEST: " << ui->lineEdit_2->text() << endl
<< "CALLSIGN: " << ui->lineEdit_3->text() << endl
<< "CATEGORY-OPERATOR: " << ui->lineEdit_4->text() << endl
<< "CATEGORY-TRANSMITTER: " << ui->lineEdit_5->text() << endl
<< "CATEGORY-POWER: " << ui->lineEdit_6->text() << endl
<< "CATEGORY-ASSISTED: " << ui->lineEdit_7->text() << endl
<< "CATEGORY-BAND: " << ui->lineEdit_8->text() << endl
<< "CLAIMED-SCORE: " << ui->lineEdit_9->text() << endl
<< "OPERATORS: " << ui->lineEdit_10->text() << endl
<< "CLUB: " << ui->lineEdit_11->text() << endl
<< "NAME: " << ui->lineEdit_12->text() << endl
<< "ADDRESS: " << ui->lineEdit_13->text() << endl
<< "ADDRESS: " << ui->lineEdit_14->text() << endl;
QFile f2(m_CabLog);
if(f2.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream s(&f2);
QString t=s.readAll();
out << t << "END-OF-LOG:" << endl;
f2.close();
}
f.close();
} else {
auto const& message = tr ("Cannot open \"%1\" for writing: %2")
.arg (f.fileName ()).arg (f.errorString ());
MessageBox::warning_message (this, tr ("Export Cabrillo File Error"), message);
}
write_settings();
}
void ExportCabrillo::accept()
{
write_settings();
QDialog::accept();
}

37
ExportCabrillo.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef EXPORTCABRILLO_H
#define EXPORTCABRILLO_H
#include <QDialog>
#include <QSettings>
namespace Ui {
class ExportCabrillo;
}
class ExportCabrillo : public QDialog
{
Q_OBJECT
public:
explicit ExportCabrillo(QSettings *settings, QWidget *parent = 0);
void setFile(QString t);
~ExportCabrillo();
public slots:
void accept();
protected:
void closeEvent (QCloseEvent *) override;
private slots:
void on_pbSaveAs_clicked();
private:
QSettings * settings_;
QString m_CabLog;
void read_settings();
void write_settings();
Ui::ExportCabrillo *ui;
};
#endif // EXPORTCABRILLO_H

304
ExportCabrillo.ui Normal file
View File

@ -0,0 +1,304 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportCabrillo</class>
<widget class="QDialog" name="ExportCabrillo">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>330</width>
<height>407</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Location:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_1">
<property name="text">
<string>SNJ</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Contest:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_2">
<property name="text">
<string>ARRL-RTTY</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Callsign:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_3">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Category-Operator: </string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_4">
<property name="text">
<string>SINGLE-OP</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Category-Transmitter:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEdit_5">
<property name="text">
<string>ONE</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Category-Power:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineEdit_6">
<property name="text">
<string>LOW</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Category-Assisted:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="lineEdit_7">
<property name="text">
<string>NON-ASSISTED</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Category-Band:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="lineEdit_8">
<property name="text">
<string>ALL</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Claimed-Score:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="lineEdit_9">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Operators:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="lineEdit_10">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Club:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLineEdit" name="lineEdit_11">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLineEdit" name="lineEdit_12">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLineEdit" name="lineEdit_13">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLineEdit" name="lineEdit_14">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="pbSaveAs">
<property name="text">
<string>Save As</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ExportCabrillo</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ExportCabrillo</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -261,12 +261,7 @@ HamlibTransceiver::HamlibTransceiver (int model_number, TransceiverFactory::Para
// //
// user defined Hamlib settings // user defined Hamlib settings
// //
auto settings_file_name = QStandardPaths::locate ( auto settings_file_name = QStandardPaths::locate (QStandardPaths::AppConfigLocation
#if QT_VERSION >= 0x050500
QStandardPaths::AppConfigLocation
#else
QStandardPaths::ConfigLocation
#endif
, "hamlib_settings.json"); , "hamlib_settings.json");
if (!settings_file_name.isEmpty ()) if (!settings_file_name.isEmpty ())
{ {

View File

@ -47,7 +47,7 @@ protected:
void stepBy (int steps) override; void stepBy (int steps) override;
private: private:
std::vector<int> values_; values_type values_;
}; };
#endif #endif

View File

@ -92,9 +92,5 @@ QVariant IARURegions::headerData (int section, Qt::Orientation orientation, int
return result; return result;
} }
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (IARURegions, Region);
#endif
ENUM_QDATASTREAM_OPS_IMPL (IARURegions, Region); ENUM_QDATASTREAM_OPS_IMPL (IARURegions, Region);
ENUM_CONVERSION_OPS_IMPL (IARURegions, Region); ENUM_CONVERSION_OPS_IMPL (IARURegions, Region);

View File

@ -29,8 +29,6 @@ class IARURegions final
: public QAbstractListModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS (Region)
public: public:
// //
// This enumeration contains the supported regions, to complement // This enumeration contains the supported regions, to complement
@ -62,19 +60,6 @@ public:
QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override;
}; };
// Qt boilerplate to make the IARURegions::region enumeration a type
// that can be streamed and queued as a signal argument as well as
// showing the human readable string when output to debug streams.
#if QT_VERSION < 0x050500
// Qt 5.5 introduces the Q_ENUM macro which automatically registers
// the meta-type
Q_DECLARE_METATYPE (IARURegions::Region);
#endif
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_DECL (IARURegions, Region);
#endif
ENUM_QDATASTREAM_OPS_DECL (IARURegions, Region); ENUM_QDATASTREAM_OPS_DECL (IARURegions, Region);
ENUM_CONVERSION_OPS_DECL (IARURegions, Region); ENUM_CONVERSION_OPS_DECL (IARURegions, Region);

280
LotWUsers.cpp Normal file
View File

@ -0,0 +1,280 @@
#include "LotWUsers.hpp"
#include <future>
#include <QHash>
#include <QString>
#include <QDate>
#include <QFile>
#include <QTextStream>
#include <QDir>
#include <QFileInfo>
#include <QPointer>
#include <QSaveFile>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QDebug>
#include "pimpl_impl.hpp"
#include "moc_LotWUsers.cpp"
namespace
{
// Dictionary mapping call sign to date of last upload to LotW
using dictionary = QHash<QString, QDate>;
}
class LotWUsers::impl final
: public QObject
{
Q_OBJECT
public:
impl (LotWUsers * self, QNetworkAccessManager * network_manager)
: self_ {self}
, network_manager_ {network_manager}
, url_valid_ {false}
, redirect_count_ {0}
, age_constraint_ {365}
{
}
void load (QString const& url, bool forced_fetch)
{
auto csv_file_name = csv_file_.fileName ();
abort (); // abort any active download
if (!QFileInfo::exists (csv_file_name) || forced_fetch)
{
current_url_.setUrl (url);
redirect_count_ = 0;
download (current_url_);
}
else
{
// load the database asynchronously
future_load_ = std::async (std::launch::async, &LotWUsers::impl::load_dictionary, this, csv_file_name);
}
}
void download (QUrl url)
{
if (QNetworkAccessManager::Accessible != network_manager_->networkAccessible ())
{
// try and recover network access for QNAM
network_manager_->setNetworkAccessible (QNetworkAccessManager::Accessible);
}
if (url.isValid () && !QSslSocket::supportsSsl ())
{
url.setScheme ("http");
}
QNetworkRequest request {url};
request.setRawHeader ("User-Agent", "WSJT LotW User Downloader");
request.setOriginatingObject (this);
// this blocks for a second or two the first time it is used on
// Windows - annoying
if (!url_valid_)
{
reply_ = network_manager_->head (request);
}
else
{
reply_ = network_manager_->get (request);
}
connect (reply_.data (), &QNetworkReply::finished, this, &LotWUsers::impl::reply_finished);
connect (reply_.data (), &QNetworkReply::readyRead, this, &LotWUsers::impl::store);
}
void reply_finished ()
{
if (!reply_)
{
Q_EMIT self_->load_finished ();
return; // we probably deleted it in an earlier call
}
QUrl redirect_url {reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ()};
if (reply_->error () == QNetworkReply::NoError && !redirect_url.isEmpty ())
{
if (++redirect_count_ < 10) // maintain sanity
{
// follow redirect
download (reply_->url ().resolved (redirect_url));
}
else
{
Q_EMIT self_->LotW_users_error (tr ("Network Error - Too many redirects:\n\'%1\'")
.arg (redirect_url.toDisplayString ()));
url_valid_ = false; // reset
Q_EMIT self_->load_finished ();
}
}
else if (reply_->error () != QNetworkReply::NoError)
{
csv_file_.cancelWriting ();
csv_file_.commit ();
url_valid_ = false; // reset
// report errors that are not due to abort
if (QNetworkReply::OperationCanceledError != reply_->error ())
{
Q_EMIT self_->LotW_users_error (tr ("Network Error:\n%1")
.arg (reply_->errorString ()));
}
Q_EMIT self_->load_finished ();
}
else
{
if (url_valid_ && !csv_file_.commit ())
{
Q_EMIT self_->LotW_users_error (tr ("File System Error - Cannot commit changes to:\n\"%1\"")
.arg (csv_file_.fileName ()));
url_valid_ = false; // reset
Q_EMIT self_->load_finished ();
}
else
{
if (!url_valid_)
{
// now get the body content
url_valid_ = true;
download (reply_->url ().resolved (redirect_url));
}
else
{
url_valid_ = false; // reset
// load the database asynchronously
future_load_ = std::async (std::launch::async, &LotWUsers::impl::load_dictionary, this, csv_file_.fileName ());
}
}
}
if (reply_ && reply_->isFinished ())
{
reply_->deleteLater ();
}
}
void store ()
{
if (url_valid_)
{
if (!csv_file_.isOpen ())
{
// create temporary file in the final location
if (!csv_file_.open (QSaveFile::WriteOnly))
{
abort ();
Q_EMIT self_->LotW_users_error (tr ("File System Error - Cannot open file:\n\"%1\"\nError(%2): %3")
.arg (csv_file_.fileName ())
.arg (csv_file_.error ())
.arg (csv_file_.errorString ()));
}
}
if (csv_file_.write (reply_->read (reply_->bytesAvailable ())) < 0)
{
abort ();
Q_EMIT self_->LotW_users_error (tr ("File System Error - Cannot write to file:\n\"%1\"\nError(%2): %3")
.arg (csv_file_.fileName ())
.arg (csv_file_.error ())
.arg (csv_file_.errorString ()));
}
}
}
void abort ()
{
if (reply_ && reply_->isRunning ())
{
reply_->abort ();
}
}
// Load the database from the given file name
//
// Expects the file to be in CSV format with no header with one
// record per line. Record fields are call sign followed by upload
// date in yyyy-MM-dd format followed by upload time (ignored)
dictionary load_dictionary (QString const& lotw_csv_file)
{
dictionary result;
QFile f {lotw_csv_file};
if (f.open (QFile::ReadOnly | QFile::Text))
{
QTextStream s {&f};
for (auto l = s.readLine (); !l.isNull (); l = s.readLine ())
{
auto pos = l.indexOf (',');
result[l.left (pos)] = QDate::fromString (l.mid (pos + 1, l.indexOf (',', pos + 1) - pos - 1), "yyyy-MM-dd");
}
// qDebug () << "LotW User Data Loaded";
}
else
{
throw std::runtime_error {QObject::tr ("Failed to open LotW users CSV file: '%1'").arg (f.fileName ()).toStdString ()};
}
return result;
}
LotWUsers * self_;
QNetworkAccessManager * network_manager_;
QSaveFile csv_file_;
bool url_valid_;
QUrl current_url_; // may be a redirect
int redirect_count_;
QPointer<QNetworkReply> reply_;
std::future<dictionary> future_load_;
dictionary last_uploaded_;
qint64 age_constraint_; // days
};
#include "LotWUsers.moc"
LotWUsers::LotWUsers (QNetworkAccessManager * network_manager, QObject * parent)
: QObject {parent}
, m_ {this, network_manager}
{
}
LotWUsers::~LotWUsers ()
{
}
void LotWUsers::set_local_file_path (QString const& path)
{
m_->csv_file_.setFileName (path);
}
void LotWUsers::load (QString const& url, bool force_download)
{
m_->load (url, force_download);
}
void LotWUsers::set_age_constraint (qint64 uploaded_since_days)
{
m_->age_constraint_ = uploaded_since_days;
}
bool LotWUsers::user (QString const& call) const
{
if (m_->future_load_.valid ())
{
try
{
// wait for the load to finish if necessary
const_cast<dictionary&> (m_->last_uploaded_) = const_cast<std::future<dictionary>&> (m_->future_load_).get ();
}
catch (std::exception const& e)
{
Q_EMIT LotW_users_error (e.what ());
}
Q_EMIT load_finished ();
}
auto p = m_->last_uploaded_.constFind (call);
if (p != m_->last_uploaded_.end ())
{
return p.value ().daysTo (QDate::currentDate ()) <= m_->age_constraint_;
}
return false;
}

41
LotWUsers.hpp Normal file
View File

@ -0,0 +1,41 @@
#ifndef LOTW_USERS_HPP_
#define LOTW_USERS_HPP_
#include <boost/core/noncopyable.hpp>
#include <QObject>
#include "pimpl_h.hpp"
class QString;
class QDate;
class QNetworkAccessManager;
//
// LotWUsers - Lookup Logbook of the World users
//
class LotWUsers final
: public QObject
{
Q_OBJECT
public:
explicit LotWUsers (QNetworkAccessManager *, QObject * parent = 0);
~LotWUsers ();
void set_local_file_path (QString const&);
Q_SLOT void load (QString const& url, bool force_download = false);
Q_SLOT void set_age_constraint (qint64 uploaded_since_days);
// returns true if the specified call sign 'call' has uploaded their
// log to LotW in the last 'age_constraint_days' days
bool user (QString const& call) const;
Q_SIGNAL void LotW_users_error (QString const& reason) const;
Q_SIGNAL void load_finished () const;
private:
class impl;
pimpl<impl> m_;
};
#endif

View File

@ -334,7 +334,7 @@ MessageClient::MessageClient (QString const& id, QString const& version, QString
connect (&*m_, static_cast<void (impl::*) (impl::SocketError)> (&impl::error) connect (&*m_, static_cast<void (impl::*) (impl::SocketError)> (&impl::error)
, [this] (impl::SocketError e) , [this] (impl::SocketError e)
{ {
#if defined (Q_OS_WIN) && QT_VERSION >= 0x050500 #if defined (Q_OS_WIN)
if (e != impl::NetworkError // take this out when Qt 5.5 if (e != impl::NetworkError // take this out when Qt 5.5
// stops doing this // stops doing this
// spuriously // spuriously

View File

@ -13,7 +13,7 @@
#include "TransceiverFactory.hpp" #include "TransceiverFactory.hpp"
#include "WFPalette.hpp" #include "WFPalette.hpp"
#include "IARURegions.hpp" #include "IARURegions.hpp"
#include "DecodeHighlightingModel.hpp"
#include "FrequencyLineEdit.hpp" #include "FrequencyLineEdit.hpp"
QItemEditorFactory * item_editor_factory () QItemEditorFactory * item_editor_factory ()
@ -47,10 +47,6 @@ void register_types ()
qRegisterMetaType<AudioDevice::Channel> ("AudioDevice::Channel"); qRegisterMetaType<AudioDevice::Channel> ("AudioDevice::Channel");
// Configuration // Configuration
#if QT_VERSION < 0x050500
qRegisterMetaType<Configuration::DataMode> ("Configuration::DataMode");
qRegisterMetaType<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen");
#endif
qRegisterMetaTypeStreamOperators<Configuration::DataMode> ("Configuration::DataMode"); qRegisterMetaTypeStreamOperators<Configuration::DataMode> ("Configuration::DataMode");
qRegisterMetaTypeStreamOperators<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen"); qRegisterMetaTypeStreamOperators<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen");
@ -62,17 +58,8 @@ void register_types ()
// Transceiver // Transceiver
qRegisterMetaType<Transceiver::TransceiverState> ("Transceiver::TransceiverState"); qRegisterMetaType<Transceiver::TransceiverState> ("Transceiver::TransceiverState");
qRegisterMetaType<Transceiver::MODE> ("Transceiver::MODE");
// Transceiver factory // Transceiver factory
#if QT_VERSION < 0x050500
qRegisterMetaType<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits");
qRegisterMetaType<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits");
qRegisterMetaType<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake");
qRegisterMetaType<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod");
qRegisterMetaType<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource");
qRegisterMetaType<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode");
#endif
qRegisterMetaTypeStreamOperators<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits"); qRegisterMetaTypeStreamOperators<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits");
qRegisterMetaTypeStreamOperators<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits"); qRegisterMetaTypeStreamOperators<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits");
qRegisterMetaTypeStreamOperators<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake"); qRegisterMetaTypeStreamOperators<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake");
@ -84,8 +71,9 @@ void register_types ()
qRegisterMetaTypeStreamOperators<WFPalette::Colours> ("Colours"); qRegisterMetaTypeStreamOperators<WFPalette::Colours> ("Colours");
// IARURegions // IARURegions
#if QT_VERSION < 0x050500
qRegisterMetaType<IARURegions::Region> ("IARURegions::Region");
#endif
qRegisterMetaTypeStreamOperators<IARURegions::Region> ("IARURegions::Region"); qRegisterMetaTypeStreamOperators<IARURegions::Region> ("IARURegions::Region");
// DecodeHighlightingModel
qRegisterMetaTypeStreamOperators<DecodeHighlightingModel::HighlightInfo> ("HighlightInfo");
qRegisterMetaTypeStreamOperators<DecodeHighlightingModel::HighlightItems> ("HighlightItems");
} }

View File

@ -98,9 +98,5 @@ QVariant Modes::headerData (int section, Qt::Orientation orientation, int role)
return result; return result;
} }
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (Modes, Mode);
#endif
ENUM_QDATASTREAM_OPS_IMPL (Modes, Mode); ENUM_QDATASTREAM_OPS_IMPL (Modes, Mode);
ENUM_CONVERSION_OPS_IMPL (Modes, Mode); ENUM_CONVERSION_OPS_IMPL (Modes, Mode);

View File

@ -29,7 +29,6 @@ class Modes final
: public QAbstractListModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS (Mode)
public: public:
// //
@ -69,19 +68,6 @@ public:
QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override;
}; };
// Qt boilerplate to make the Modes::Mode enumeration a type that can
// be streamed and queued as a signal argument as well as showing the
// human readable string when output to debug streams.
#if QT_VERSION < 0x050500
// Qt 5.5 introduces the Q_ENUM macro which automatically registers
// the meta-type
Q_DECLARE_METATYPE (Modes::Mode);
#endif
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_DECL (Modes, Mode);
#endif
ENUM_QDATASTREAM_OPS_DECL (Modes, Mode); ENUM_QDATASTREAM_OPS_DECL (Modes, Mode);
ENUM_CONVERSION_OPS_DECL (Modes, Mode); ENUM_CONVERSION_OPS_DECL (Modes, Mode);

View File

@ -1,2 +1,471 @@
The content of this file has been moved to the NEWS file, please add __ __ ______ _____ ________ __ __
release note updates to that file. | \ _ | \ / \ | \| \ | \ | \
| $$ / \ | $$| $$$$$$\ \$$$$$ \$$$$$$$$ | $$ | $$
| $$/ $\| $$| $$___\$$ | $$ | $$ ______ \$$\/ $$
| $$ $$$\ $$ \$$ \ __ | $$ | $$| \ >$$ $$
| $$ $$\$$\$$ _\$$$$$$\| \ | $$ | $$ \$$$$$$/ $$$$\
| $$$$ \$$$$| \__| $$| $$__| $$ | $$ | $$ \$$\
| $$$ \$$$ \$$ $$ \$$ $$ | $$ | $$ | $$
\$$ \$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$
Copyright 2001 - 2018 by Joe Taylor, K1JT.
Release: WSJT-X 2.0-rc3
October 15, 2018
-----------------------
Changes from WSJT-X Version 2.0.0-rc1 include the following:
- Improved SNR calculation for FT8
- Test grid4 (not grid6) for matches in ADIF log
- Auto-generate 77-bit messages for callsigns with /R or /P
- Fix auto-sequencing for "CQ ABC ...", "CQ ABCD ...", etc.
- Fix the "CQ RU RU ..." bug
- Implement AP decoding for contest messages and for Hound
- Check Field Day and RTTY Roundup exchanges for validity
- Implement "Select next caller" and use of "TU; ..." messages
- Option to "auto log" in contests
- Real-time display of contest log
- Contest exchanges sent to ADIF log and N1MM+
- Function to export Cabrillo log
- Convert DXpedition mode to always use 77-bit messages
- Fix bug associated with opening "houndcallers.txt"
- Remove end-of-line numbers from MSK144 decodes
- Finish MSK144 encoding/decoding for Sh msgs and nonstandard calls
- Halt Tx before resetting power after Tune
- Auto update of LoTW info, and faster program startup
Release: WSJT-X 2.0-rc2
September 25, 2018
-----------------------
Changes from WSJT-X Version 2.0.0-rc1 include the following:
- Corrected a flaw that encoded a message's first callsign as
hexadecimal telemetry data if the call consisted only of letters
A-F and digits 0-9.
- Corrected program logic that failed to identify certain callsigns
as "nonstandard".
- Fixed a bug that color-highlighted bare CQ messages (no grid
locator) as "New DXCC".
- Fixed a bug that failed to log Report Sent if MyCall is a
nonstandard call.
- Fixed a bug that generated incorrect MSK144 tones for certain
messages and caused a "memory" effect on stations receiving the
incorrect tones.
- Fixed several bugs that could cause certain Tx messages to crash
the program.
- Suppressed the display of certain illogical false decodes.
Release: WSJT-X 2.0-rc1
September 17, 2018
-----------------------
This is the first candidate release on WSJT-X 2.0, intended for
beta-level testing. For details see:
http://physics.princeton.edu/pulsar/k1jt/New_Features_WSJT-X_2.0.txt
http://physics.princeton.edu/pulsar/k1jt/Quick_Start_WSJT-X_2.0.pdf
http://physics.princeton.edu/pulsar/k1jt/77bit.txt
Release: WSJT-X Version 1.9.1
May 31, 2018
-----------------------------
This release is a critical bug fix release that removes an unintended
restriction of FT8 DXpedition mode.
Release: WSJT-X Version 1.9.0
May 28, 2018
-----------------------------
Changes from WSJT-X Version 1.9.0-rc4 include the following:
- Display in the right text window of MSK144 messages addressed to
"MyCall" has been restored.
- Fox is not allowed to transmit in any of the default FT8 sub-bands.
- Fox can now work Hounds using compound callsigns.
- Fox can now transmit free-text messages (and any standard FT8 message)
by using Tab 1 or Tab 2.
- Added a checkbox to enable more frequent programmed CQs by Fox.
Default is OFF.
- Alt+N keyboard shortcut has been restored.
- MacOS program crash on unexpected decode request has been fixed.
- Several minor bug fixes and added convenience features.
- Hamlib, support for TRXManger added.
- Hamlib, improved support for flrig.
Release: WSJT-X Version 1.9.0-rc4
April 30, 2018
---------------------------------
Changes from WSJT-X Version 1.9.0-rc3 include the following:
- Corrected a number of flaws in Fox and Hound behavior, FT8
DXpedition Mode
- Decoded CQ calls where a prefix has been used as a suffix should
have the DXCC entity name assigned correctly in almost all cases
- Improved AFC capability for the wider JT65 sub-modes to help with
drifting signals
- Better support for macOS using hi-DPI Retina displays
- New UDP message that allows external applications to highlight
decoded callsigns
- Main-screen geometry and state of the "splitter" setting between its
two text windows is now properly restored after program restart.
- New simulator jt49sim[.exe] replaces jt4sim and jt9sim
- Correct S/N measurements for the JT9 slow/wide submodes
- Other minor bug fixes
- Updated copy of cty.dat
Release: WSJT-X Version 1.9.0-rc3
March 18, 2018
---------------------------------
Changes from WSJT-X Version 1.9.0-rc2 include the following:
- Corrected a number of flaws in Fox behavior, FT8 DXpedition Mode
- Allow Hounds to use compound callsigns
- Write debugging information to FoxQSO.txt.
- Fix the "Blue Decode Button" bug
- Allow partial processing of incoming UDP Reply messages so that
non-CQ/QRZ decodes can be processed. The processing is the same as
double-clicking the same decoded message within WSJT-X except that
"Enable Tx" will not be enabled.
- Send DX grid locator to wsjt_status.txt, for use by applications like
PstRotatorAZ
- Correct the display of DXCC status of KG4 calls
- Updated copy of cty.dat
- Updates to documentation
- Other minor bug fixes
- This release contains updated Hamlib functionality including changes
to the Yaesu FT-817 back end that allows the uBITx kit transceiver
to be CAT controlled by WSJT-X.
Release: WSJT-X Version 1.9.0-rc2
February 26, 2018
---------------------------------
Changes from WSJT-X Version 1.8.0 include the following:
- New FT8 DXpedition Mode to facilitate high QSO rates in pileup
situations
- Decoding improvements for JT65 mode, including a priori (AP)
decoding when VHF/UHF/Microwave features are enabled
- Optional Auto-Sequencing in JT4, JT9, and JT65 when
VHF/UHF/Microwave features are enabled
- Better suppression of low-confidence false decodes generated by AP
decoding in FT8 mode
- Improved decoding performance for WSPR mode, especially effective at
LF and MF
- Minor adjustments to auto-sequencing behavior
- More flexible Doppler control features for EME
- Improved waterfall sensitivity for very weak signals
- Automatic real-time forwarding of logged information to N1MM Logger+
- Expanded and improved UDP messages sent to companion programs
- Bug fixes and other minor tweaks to user interface
A primary purpose of this beta release is to allow field testing of
FT8 DXpedition Mode. Instructions for this mode are posted here:
http://physics.princeton.edu/pulsar/k1jt/FT8_DXpedition_Mode.pdf
Contacts in FT8 DXpedition Mode must use WSJT-X v1.9.0 at both ends of
the QSO. Please report any anomalous behavior to email list
wsjt-devel@lists.sourceforge.net. You must be a subscriber in order
to post there.
Release: WSJT-X Version 1.8.0
October 27, 2017
-----------------------------
This is the full General Availability release of WSJT-X Version 1.8.0.
Changes from WSJT-X Version 1.8.0-rc3 are very minor:
- Right-click on the Wide Graph now pops up a Context Menu. Select
the item *Set Rx & Tx Offset* to complete a one-handed setting of
both red and green frequency markers.
- Several clarifications and additions to Tool Tips and the User Guide.
We recommend that all users should upgrade to WSJT-X Version 1.8.0.
If you upgrade from v1.8.0-rc1 it may be necessary to do a one-time
reset of the default list of suggested operating frequencies. Go to
*File->Settings->Frequencies*, right click on the table and select
*Reset*.
Release: WSJT-X Version 1.8.0-rc3
October 16, 2017
---------------------------------
Most (but not all) changes since Version 1.8.0-rc2 involve user
control of the increasingly popular FT8 mode. The "RC3" release also
includes minor bug fixes and updates to the WSJT-X User Guide.
The following list includes all of the more important changes:
- New optimization of GUI for simplex and split behavior in FT8 mode.
1. Checkbox "Lock Tx Freq" on main window is relabeled "Hold Tx Freq".
2. Double-clicking on decoded messages that do not contain your own
call moves both Rx and Tx frequencies. If the first callsign is
your own call, only Rx freq moves.
3. Double-clicking on decoded messages moves the Rx frequency. If
"Hold Tx Freq" is checked, Tx frequency is moved only if CTRL was
held down.
4. Clicking on the waterfall moves Rx and Tx frequencies as
before: Rx only on a simple click, Tx only on SHIFT-click, and
both on CTRL-click. This happens even if "Hold Tx Freq" is
checked.
- Add a semi-automated "FreqCal" procedure: see *Solve for calibration
parameters* on the Tools menu.
- Improv auto-sequencing behavior: stop and on-frequency
transmission if a called station comes back to someone else.
- Improve S/N estimation in some situations involving QRM.
- Fix an initialization issue with user-modified application fonts.
- Fix an issue with Tx5 message generation with Type 2 compound calls.
- Enhance and improve the ADIF parser of logbook records. Update
the band limits as per ADIF 3.0.6 specification.
- Increase the FT8 DT range to +/- 2.5 s.
- Do not allow window manager events to close the astronomical data
window.
- Add an "Erase" item to the context (right-click) menu for decoded
text.
- Extend UDP messages with an "off air" boolean field indicating that
the decode was derived from a .WAV file playback rather than an on air
reception.
- Extend reference applications to use the new off air decode message
field.
- Improve performance of FT8 decoder, especially for overlapping
signals.
- Allow specialized use of "x2 Tone Spacing" in FT8 and slow JT9
modes.
- Move "NA VHF Contest Mode" checkbox to main screen. Query the
operator if d > 10000 km.
- Adjust UI to improve portability with font size changes and between
platforms.
- Extend UDP Reply message to support keyboard modifiers. This allows
UDP servers to emulate keyboard modified double-clicks on decoded
messages, e.g. ALT+double-click for replying to a CQ or QRZ call
without changing ones Tx frequency offset.
- Update the cty.dat file (21st Sept 2017).
- Ensure that Fast Graph is properly initialized.
- Better handling of worked before and country name display. Appended
text is added at a fixed column unless the message overlaps in which
case the appended information floats to the right.
- Restore printing of MSK144 decode quality information.
- Display Echo Graph automatically when Echo mode is started.
- Fix a bug that prevented double-click on a JT65 EME-style "OOO"
message from populating the Tx message boxes.
- Fixed behavior with double-click on 'CQ <AA-ZZ> <call> <grid>.'
- Update the "blank line" divider with band ID at 4*TRperiod/5.
- Fix cty.dat lookups that were not honouring exact match flags
- Add some further Copyright protections.
- Fix a bug involving "firstcall contains mycall" but not equal to mycall.
- Fix an issue with editing IARU regions in the working frequencies table.
Release: WSJT-X Version 1.8.0-rc2
September 2, 2017
---------------------------------
Implementation of FT8 and its auto-sequencing feature is now more
capable and more polished. The decoder is faster and better: it now
includes signal subtraction, multi-pass decoding, and the use of
accumulated "a priori" information as a QSO progresses. Sensitivity
extends downward as far as -24 dB in some circumstances. Overlapping
signals 2 and 3 deep are frequently decoded at essentially the same
frequency. On a crowded band we sometimes see more than 30 decodes in
a single 15-second interval, over a 2 kHz window. The North American
VHF Contesting Mode has been extended to include both FT8 and MSK144
modes.
The "RC2" release also includes many minor bug fixes and an
extensively updated WSJT-X User Guide.
Depending on what code revision you upgrade from, it may be necessary
to do a one-time reset of the default list of suggested operating
frequencies. Go to *File->Settings->Frequencies*, right click on
the table and select *Reset*.
Release: WSJT-X Version 1.8.0
-----------------------------
NEW FEATURES IN WSJT-X Version 1.8.0
------------------------------------
1. New mode called FT8: sensitivity down to -20 dB on the AWGN
channel; QSOs 4 times faster than JT65 or JT9; auto-sequencing
includes an option to respond automatically to first decoded
reply to your CQ.
2. New mode for accurate Frequency Calibration of your radio.
3. Improved performance of decoders for JT65, QRA64, and MSK144.
MSK144 includes facilities for amplitide and phase equalization
and an "SWL" mode for short-format messages.
4. Options to minimize screen space used by Main and Wide Graph
windows.
5. Enhanced management scheme for table of operating frequencies, and
a new set of default frequencies specific to the three IARU
Regions.
6. Improved CAT control for many rigs, including those controlled
through Commander or OmniRig.
7. New keyboard shortcuts to set "Tx even/1st" ON or OFF.
8. A number of (mostly minor) bug fixes and tweaks to the user
interface. For example: new behavior for the audio level slider;
correctly logged QSO start times in certain situations; correct
control of FT-891/991 and some other radios via rigctld.
At the time of the v1.8.0-rc1 release the following tasks are yet to
be completed:
1. Updates to WSJT-X User Guide.
2. Sample files for FT8.
3. Enhanced decoding using AP ("a priori") information.
4. Signal subtraction and multi-pass decoding.
5. Option to Auto-respond to the weakest responder to your CQ.
Installation packages for Windows, Linux, OS X, and Raspbian can be
downloaded from the WSJT web site:
http://physics.princeton.edu/pulsar/K1JT/wsjtx.html
Please send bug reports to either wsjtgroup@yahoogroups.com or
wsjt-devel@lists.sourceforge.net. Such reports should include a full
prescription of steps to reproduce the undesired behavior. You must
be a subscriber to post to either of these lists.
Brief Description of the FT8 Protocol
-------------------------------------
WSJT-X Version 1.8.0 includes a new mode called FT8, developed by K9AN
and K1JT. The mode name "FT8" stands for "Franke and Taylor, 8-FSK
modulation". FT8 uses 15-second T/R sequences and provides 50% or
better decoding probability down to -20 dB on an AWGN channel. An
auto-sequencing facility includes an option to respond automatically
to the first decoded reply to your CQ. FT8 QSOs are 4 times faster
than those made with JT65 or JT9. FT8 is an excellent mode for HF
DXing and for situations like multi-hop E_s on 6 meters, where deep
QSB may make fast and reliable completion of QSOs desirable.
Some important characteristics of FT8:
- T/R sequence length: 15 s
- Message length: 75 bits + 12-bit CRC
- FEC code: LDPC(174,87)
- Modulation: 8-FSK, tone spacing 6.25 Hz
- Constant-envelope waveform
- Occupied bandwidth: 50 Hz
- Synchronization: 7x7 Costas arrays at start, middle, and end
- Transmission duration: 79*1920/12000 = 12.64 s
- Decoding threshold: -20 dB; several dB lower with AP decoding
- Multi-decoder finds and decodes all FT8 signals in passband
- Optional auto-sequencing and auto-reply to a CQ response
- Operational behavior similar to JT9, JT65
We plan to implement signal subtraction, two-pass decoding, and use of
a priori (AP) information in the decoder. These features are not yet
activated in v1.8.0.
We haven't yet finalized what the three extra bits in the message
payload will be used for. Suggestions are welcome!
-- Joe, K1JT, for the WSJT Development Team

View File

@ -34,12 +34,15 @@ void RemoteFile::local_file_path (QString const& name)
QFile file {local_file_.absoluteFilePath ()}; QFile file {local_file_.absoluteFilePath ()};
if (!file.rename (new_file.absoluteFilePath ())) if (!file.rename (new_file.absoluteFilePath ()))
{ {
listener_->error (tr ("File System Error") if (listener_)
, tr ("Cannot rename file:\n\"%1\"\nto: \"%2\"\nError(%3): %4") {
.arg (file.fileName ()) listener_->error (tr ("File System Error")
.arg (new_file.absoluteFilePath ()) , tr ("Cannot rename file:\n\"%1\"\nto: \"%2\"\nError(%3): %4")
.arg (file.error ()) .arg (file.fileName ())
.arg (file.errorString ())); .arg (new_file.absoluteFilePath ())
.arg (file.error ())
.arg (file.errorString ()));
}
} }
} }
std::swap (local_file_, new_file); std::swap (local_file_, new_file);
@ -49,15 +52,18 @@ void RemoteFile::local_file_path (QString const& name)
bool RemoteFile::local () const bool RemoteFile::local () const
{ {
auto is_local = (reply_ && !reply_->isFinished ()) || local_file_.exists (); auto is_local = (reply_ && !reply_->isFinished ()) || local_file_.exists ();
if (is_local) if (listener_)
{ {
auto size = local_file_.size (); if (is_local)
listener_->download_progress (size, size); {
listener_->download_finished (true); auto size = local_file_.size ();
} listener_->download_progress (size, size);
else listener_->download_finished (true);
{ }
listener_->download_progress (-1, 0); else
{
listener_->download_progress (-1, 0);
}
} }
return is_local; return is_local;
} }
@ -92,13 +98,19 @@ bool RemoteFile::sync (QUrl const& url, bool local, bool force)
auto path = local_file_.absoluteDir (); auto path = local_file_.absoluteDir ();
if (path.remove (local_file_.fileName ())) if (path.remove (local_file_.fileName ()))
{ {
listener_->download_progress (-1, 0); if (listener_)
{
listener_->download_progress (-1, 0);
}
} }
else else
{ {
listener_->error (tr ("File System Error") if (listener_)
, tr ("Cannot delete file:\n\"%1\"") {
.arg (local_file_.absoluteFilePath ())); listener_->error (tr ("File System Error")
, tr ("Cannot delete file:\n\"%1\"")
.arg (local_file_.absoluteFilePath ()));
}
return false; return false;
} }
path.rmpath ("."); path.rmpath (".");
@ -137,10 +149,13 @@ void RemoteFile::download (QUrl url)
connect (reply_.data (), &QNetworkReply::readyRead, this, &RemoteFile::store); connect (reply_.data (), &QNetworkReply::readyRead, this, &RemoteFile::store);
connect (reply_.data (), &QNetworkReply::downloadProgress connect (reply_.data (), &QNetworkReply::downloadProgress
, [this] (qint64 bytes_received, qint64 total_bytes) { , [this] (qint64 bytes_received, qint64 total_bytes) {
// report progress of wanted file if (listener_)
if (is_valid_)
{ {
listener_->download_progress (bytes_received, total_bytes); // report progress of wanted file
if (is_valid_)
{
listener_->download_progress (bytes_received, total_bytes);
}
} }
}); });
} }
@ -160,7 +175,7 @@ void RemoteFile::reply_finished ()
QUrl redirect_url {reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ()}; QUrl redirect_url {reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ()};
if (reply_->error () == QNetworkReply::NoError && !redirect_url.isEmpty ()) if (reply_->error () == QNetworkReply::NoError && !redirect_url.isEmpty ())
{ {
if (listener_->redirect_request (redirect_url)) if (!listener_ || listener_->redirect_request (redirect_url))
{ {
if (++redirect_count_ < 10) // maintain sanity if (++redirect_count_ < 10) // maintain sanity
{ {
@ -169,19 +184,25 @@ void RemoteFile::reply_finished ()
} }
else else
{ {
listener_->download_finished (false); if (listener_)
listener_->error (tr ("Network Error") {
, tr ("Too many redirects: %1") listener_->download_finished (false);
.arg (redirect_url.toDisplayString ())); listener_->error (tr ("Network Error")
, tr ("Too many redirects: %1")
.arg (redirect_url.toDisplayString ()));
}
is_valid_ = false; // reset is_valid_ = false; // reset
} }
} }
else else
{ {
listener_->download_finished (false); if (listener_)
listener_->error (tr ("Network Error") {
, tr ("Redirect not followed: %1") listener_->download_finished (false);
.arg (redirect_url.toDisplayString ())); listener_->error (tr ("Network Error")
, tr ("Redirect not followed: %1")
.arg (redirect_url.toDisplayString ()));
}
is_valid_ = false; // reset is_valid_ = false; // reset
} }
} }
@ -189,10 +210,13 @@ void RemoteFile::reply_finished ()
{ {
file_.cancelWriting (); file_.cancelWriting ();
file_.commit (); file_.commit ();
listener_->download_finished (false); if (listener_)
{
listener_->download_finished (false);
}
is_valid_ = false; // reset is_valid_ = false; // reset
// report errors that are not due to abort // report errors that are not due to abort
if (QNetworkReply::OperationCanceledError != reply_->error ()) if (listener_ && QNetworkReply::OperationCanceledError != reply_->error ())
{ {
listener_->error (tr ("Network Error"), reply_->errorString ()); listener_->error (tr ("Network Error"), reply_->errorString ());
} }
@ -202,11 +226,17 @@ void RemoteFile::reply_finished ()
auto path = QFileInfo {file_.fileName ()}.absoluteDir (); auto path = QFileInfo {file_.fileName ()}.absoluteDir ();
if (is_valid_ && !file_.commit ()) if (is_valid_ && !file_.commit ())
{ {
listener_->error (tr ("File System Error") if (listener_)
, tr ("Cannot commit changes to:\n\"%1\"") {
.arg (file_.fileName ())); listener_->error (tr ("File System Error")
, tr ("Cannot commit changes to:\n\"%1\"")
.arg (file_.fileName ()));
}
path.rmpath ("."); // tidy empty directories path.rmpath ("."); // tidy empty directories
listener_->download_finished (false); if (listener_)
{
listener_->download_finished (false);
}
is_valid_ = false; // reset is_valid_ = false; // reset
} }
else else
@ -219,7 +249,10 @@ void RemoteFile::reply_finished ()
} }
else else
{ {
listener_->download_finished (true); if (listener_)
{
listener_->download_finished (true);
}
is_valid_ = false; // reset is_valid_ = false; // reset
} }
} }
@ -243,29 +276,38 @@ void RemoteFile::store ()
if (!file_.open (QSaveFile::WriteOnly)) if (!file_.open (QSaveFile::WriteOnly))
{ {
abort (); abort ();
listener_->error (tr ("File System Error") if (listener_)
, tr ("Cannot open file:\n\"%1\"\nError(%2): %3") {
.arg (path.path ()) listener_->error (tr ("File System Error")
.arg (file_.error ()) , tr ("Cannot open file:\n\"%1\"\nError(%2): %3")
.arg (file_.errorString ())); .arg (path.path ())
.arg (file_.error ())
.arg (file_.errorString ()));
}
} }
} }
else else
{ {
abort (); abort ();
listener_->error (tr ("File System Error") if (listener_)
, tr ("Cannot make path:\n\"%1\"") {
.arg (path.path ())); listener_->error (tr ("File System Error")
, tr ("Cannot make path:\n\"%1\"")
.arg (path.path ()));
}
} }
} }
if (file_.write (reply_->read (reply_->bytesAvailable ())) < 0) if (file_.write (reply_->read (reply_->bytesAvailable ())) < 0)
{ {
abort (); abort ();
listener_->error (tr ("File System Error") if (listener_)
, tr ("Cannot write to file:\n\"%1\"\nError(%2): %3") {
.arg (file_.fileName ()) listener_->error (tr ("File System Error")
.arg (file_.error ()) , tr ("Cannot write to file:\n\"%1\"\nError(%2): %3")
.arg (file_.errorString ())); .arg (file_.fileName ())
.arg (file_.error ())
.arg (file_.errorString ()));
}
} }
} }
} }

View File

@ -6,18 +6,9 @@
#include <QString> #include <QString>
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
#include <QMessageLogContext>
#include <QDateTime>
#include <QMutex>
#include <QMutexLocker>
#include "pimpl_impl.hpp" #include "pimpl_impl.hpp"
namespace
{
QMutex lock;
}
class TraceFile::impl class TraceFile::impl
{ {
public: public:
@ -81,35 +72,8 @@ TraceFile::impl::~impl ()
// write Qt messages to the diagnostic log file // write Qt messages to the diagnostic log file
void TraceFile::impl::message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg) void TraceFile::impl::message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg)
{ {
char const * severity; Q_ASSERT_X (current_stream_, "TraceFile:message_handler", "no stream to write to");
switch (type) *current_stream_ << qFormatLogMessage (type, context, msg) << endl;
{
case QtDebugMsg:
severity = "Debug";
break;
case QtWarningMsg:
severity = "Warning";
break;
case QtFatalMsg:
severity = "Fatal";
break;
default:
severity = "Critical";
break;
}
{
// guard against multiple threads with overlapping messages
QMutexLocker guard (&lock);
Q_ASSERT_X (current_stream_, "TraceFile:message_handler", "no stream to write to");
*current_stream_
<< QDateTime::currentDateTimeUtc ().toString ("yyyy-MM-ddTHH:mm:ss.zzzZ")
<< '(' << context.file << ':' << context.line /* << ", " << context.function */ << ')'
<< severity << ": " << msg.trimmed () << endl;
}
if (QtFatalMsg == type) if (QtFatalMsg == type)
{ {

View File

@ -3,9 +3,6 @@
#include "moc_Transceiver.cpp" #include "moc_Transceiver.cpp"
#if !defined (QT_NO_DEBUG_STREAM) #if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (Transceiver, MODE);
QDebug operator << (QDebug d, Transceiver::TransceiverState const& s) QDebug operator << (QDebug d, Transceiver::TransceiverState const& s)
{ {
d.nospace () d.nospace ()
@ -16,7 +13,6 @@ QDebug operator << (QDebug d, Transceiver::TransceiverState const& s)
<< ')'; << ')';
return d.space (); return d.space ();
} }
#endif #endif
ENUM_QDATASTREAM_OPS_IMPL (Transceiver, MODE); ENUM_QDATASTREAM_OPS_IMPL (Transceiver, MODE);

View File

@ -52,7 +52,6 @@ class Transceiver
: public QObject : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS (MODE)
public: public:
using Frequency = Radio::Frequency; using Frequency = Radio::Frequency;
@ -154,13 +153,8 @@ public:
}; };
Q_DECLARE_METATYPE (Transceiver::TransceiverState); Q_DECLARE_METATYPE (Transceiver::TransceiverState);
#if QT_VERSION < 0x050500
Q_DECLARE_METATYPE (Transceiver::MODE);
#endif
#if !defined (QT_NO_DEBUG_STREAM) #if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_DECL (Transceiver, MODE);
QDebug operator << (QDebug, Transceiver::TransceiverState const&); QDebug operator << (QDebug, Transceiver::TransceiverState const&);
#endif #endif

View File

@ -197,15 +197,6 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
return result; return result;
} }
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, DataBits);
ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, StopBits);
ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, Handshake);
ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, PTTMethod);
ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, TXAudioSource);
ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, SplitMode);
#endif
ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, DataBits); ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, DataBits);
ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, StopBits); ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, StopBits);
ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, Handshake); ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, Handshake);

View File

@ -21,7 +21,6 @@ class TransceiverFactory
: public QObject : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS (DataBits StopBits Handshake PTTMethod TXAudioSource SplitMode)
public: public:
// //
@ -161,28 +160,6 @@ bool operator != (TransceiverFactory::ParameterPack const& lhs, TransceiverFacto
return !(lhs == rhs); return !(lhs == rhs);
} }
//
// boilerplate routines to make enum types useable and debuggable in
// Qt
//
#if QT_VERSION < 0x050500
Q_DECLARE_METATYPE (TransceiverFactory::DataBits);
Q_DECLARE_METATYPE (TransceiverFactory::StopBits);
Q_DECLARE_METATYPE (TransceiverFactory::Handshake);
Q_DECLARE_METATYPE (TransceiverFactory::PTTMethod);
Q_DECLARE_METATYPE (TransceiverFactory::TXAudioSource);
Q_DECLARE_METATYPE (TransceiverFactory::SplitMode);
#endif
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, DataBits);
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, StopBits);
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, Handshake);
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, PTTMethod);
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, TXAudioSource);
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, SplitMode);
#endif
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, DataBits); ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, DataBits);
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, StopBits); ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, StopBits);
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, Handshake); ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, Handshake);

View File

@ -2,5 +2,5 @@
set (WSJTX_VERSION_MAJOR 2) set (WSJTX_VERSION_MAJOR 2)
set (WSJTX_VERSION_MINOR 0) set (WSJTX_VERSION_MINOR 0)
set (WSJTX_VERSION_PATCH 0) set (WSJTX_VERSION_PATCH 0)
set (WSJTX_RC 2) # release candidate number, comment out or zero for development versions set (WSJTX_RC 3) # release candidate number, comment out or zero for development versions
set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build

View File

@ -1,23 +1,28 @@
#include "colorhighlighting.h" #include "colorhighlighting.h"
#include "ui_colorhighlighting.h"
#include "SettingsGroup.hpp"
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
ColorHighlighting::ColorHighlighting(QSettings *settings, QWidget *parent) : #include "SettingsGroup.hpp"
QDialog(parent), #include "DecodeHighlightingModel.hpp"
settings_ {settings},
ui(new Ui::ColorHighlighting) #include "ui_colorhighlighting.h"
#include "moc_colorhighlighting.cpp"
ColorHighlighting::ColorHighlighting (QSettings * settings, DecodeHighlightingModel const& highlight_model, QWidget * parent)
: QDialog {parent}
, ui {new Ui::ColorHighlighting}
, settings_ {settings}
{ {
ui->setupUi(this); ui->setupUi(this);
setWindowTitle (QApplication::applicationName () + " - Colors");
read_settings (); read_settings ();
set_items (highlight_model);
} }
ColorHighlighting::~ColorHighlighting() ColorHighlighting::~ColorHighlighting()
{ {
if (isVisible ()) write_settings (); if (isVisible ()) write_settings ();
delete ui;
} }
void ColorHighlighting::read_settings () void ColorHighlighting::read_settings ()
@ -32,21 +37,68 @@ void ColorHighlighting::write_settings ()
settings_->setValue ("window/geometry", saveGeometry ()); settings_->setValue ("window/geometry", saveGeometry ());
} }
void ColorHighlighting::set_items (DecodeHighlightingModel const& highlighting_model)
void ColorHighlighting::colorHighlightlingSetup(QColor color_CQ,QColor color_MyCall,
QColor color_DXCC,QColor color_DXCCband,QColor color_NewCall,
QColor color_NewCallBand,QColor color_NewGrid,QColor color_NewGridBand,
QColor color_TxMsg,QColor color_LoTW)
{ {
setWindowTitle(QApplication::applicationName() + " - Colors"); int index {0};
ui->label->setStyleSheet(QString("background: %1").arg(color_CQ.name())); for (auto const& item : highlighting_model.items ())
ui->label_3->setStyleSheet(QString("background: %1").arg(color_MyCall.name())); {
ui->label_5->setStyleSheet(QString("background: %1").arg(color_TxMsg.name())); QLabel * example;
ui->label_7->setStyleSheet(QString("background: %1").arg(color_DXCC.name())); QLabel * label;
ui->label_9->setStyleSheet(QString("background: %1").arg(color_DXCCband.name())); switch (index++)
ui->label_11->setStyleSheet(QString("background: %1").arg(color_NewCall.name())); {
ui->label_13->setStyleSheet(QString("background: %1").arg(color_NewCallBand.name())); case 0:
ui->label_15->setStyleSheet(QString("background: %1").arg(color_NewGrid.name())); example = ui->example1_label;
ui->label_17->setStyleSheet(QString("background: %1").arg(color_NewGridBand.name())); label = ui->p1_label;
ui->label_19->setStyleSheet(QString("color: %1").arg(color_LoTW.name())); break;
case 1:
example = ui->example2_label;
label = ui->p2_label;
break;
case 2:
example = ui->example3_label;
label = ui->p3_label;
break;
case 3:
example = ui->example4_label;
label = ui->p4_label;
break;
case 4:
example = ui->example5_label;
label = ui->p5_label;
break;
case 5:
example = ui->example6_label;
label = ui->p6_label;
break;
case 6:
example = ui->example7_label;
label = ui->p7_label;
break;
case 7:
example = ui->example8_label;
label = ui->p8_label;
break;
case 8:
example = ui->example9_label;
label = ui->p9_label;
break;
case 9:
example = ui->example10_label;
label = ui->p10_label;
break;
}
auto palette = example->parentWidget ()->palette ();
if (Qt::NoBrush != item.background_.style ())
{
palette.setColor (QPalette::Window, item.background_.color ());
}
if (Qt::NoBrush != item.foreground_.style ())
{
palette.setColor (QPalette::WindowText, item.foreground_.color ());
}
example->setPalette (palette);
example->setEnabled (item.enabled_);
label->setText (DecodeHighlightingModel::highlight_name (item.type_));
label->setEnabled (item.enabled_);
}
} }

View File

@ -1,30 +1,33 @@
#ifndef COLORHIGHLIGHTING_H #ifndef COLORHIGHLIGHTING_H_
#define COLORHIGHLIGHTING_H #define COLORHIGHLIGHTING_H_
#include <QDialog> #include <QDialog>
#include <QSettings> #include <QScopedPointer>
class QSettings;
class DecodeHighlightingModel;
namespace Ui { namespace Ui {
class ColorHighlighting; class ColorHighlighting;
} }
class ColorHighlighting : public QDialog class ColorHighlighting final
: public QDialog
{ {
Q_OBJECT Q_OBJECT;
public: public:
explicit ColorHighlighting(QSettings *, QWidget *parent = 0); explicit ColorHighlighting(QSettings *, DecodeHighlightingModel const&, QWidget * parent = nullptr);
~ColorHighlighting(); ~ColorHighlighting ();
void colorHighlightlingSetup(QColor color_CQ, QColor color_MyCall,
QColor color_DXCC, QColor color_DXCCband, QColor color_NewCall,
QColor color_NewCallBand, QColor color_NewGrid, QColor color_NewGridBand,
QColor color_TxMsg, QColor color_LoTW);
private: Q_SLOT void set_items (DecodeHighlightingModel const&);
QSettings * settings_;
private:
void read_settings (); void read_settings ();
void write_settings (); void write_settings ();
Ui::ColorHighlighting *ui;
QScopedPointer<Ui::ColorHighlighting> ui;
QSettings * settings_;
}; };
#endif // COLORHIGHLIGHTING_H #endif

View File

@ -10,183 +10,206 @@
<height>253</height> <height>253</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <layout class="QGridLayout" name="gridLayout">
<string>Dialog</string> <item row="0" column="0">
</property> <widget class="QLabel" name="example1_label">
<layout class="QVBoxLayout" name="verticalLayout"> <property name="autoFillBackground">
<item> <bool>true</bool>
<layout class="QGridLayout" name="gridLayout"> </property>
<item row="6" column="0"> <property name="text">
<widget class="QLabel" name="label_17"> <string>K1ABC</string>
<property name="text"> </property>
<string>K1ABC</string> <property name="alignment">
</property> <set>Qt::AlignCenter</set>
<property name="alignment"> </property>
<set>Qt::AlignCenter</set> </widget>
</property> </item>
</widget> <item row="0" column="1">
</item> <widget class="QLabel" name="p1_label">
<item row="8" column="0"> <property name="text">
<widget class="QLabel" name="label_13"> <string>CQ in message</string>
<property name="text"> </property>
<string>K1ABC</string> </widget>
</property> </item>
<property name="alignment"> <item row="1" column="0">
<set>Qt::AlignCenter</set> <widget class="QLabel" name="example2_label">
</property> <property name="autoFillBackground">
</widget> <bool>true</bool>
</item> </property>
<item row="7" column="0"> <property name="text">
<widget class="QLabel" name="label_11"> <string>K1ABC</string>
<property name="text"> </property>
<string>K1ABC</string> <property name="alignment">
</property> <set>Qt::AlignCenter</set>
<property name="alignment"> </property>
<set>Qt::AlignCenter</set> </widget>
</property> </item>
</widget> <item row="1" column="1">
</item> <widget class="QLabel" name="p2_label">
<item row="5" column="0"> <property name="text">
<widget class="QLabel" name="label_15"> <string>My Call in message</string>
<property name="text"> </property>
<string>K1ABC</string> </widget>
</property> </item>
<property name="alignment"> <item row="2" column="0">
<set>Qt::AlignCenter</set> <widget class="QLabel" name="example3_label">
</property> <property name="autoFillBackground">
</widget> <bool>true</bool>
</item> </property>
<item row="2" column="1"> <property name="text">
<widget class="QLabel" name="label_6"> <string>K1ABC</string>
<property name="text"> </property>
<string>Transmitted message</string> <property name="alignment">
</property> <set>Qt::AlignCenter</set>
</widget> </property>
</item> </widget>
<item row="8" column="1"> </item>
<widget class="QLabel" name="label_14"> <item row="2" column="1">
<property name="text"> <widget class="QLabel" name="p3_label">
<string>New Call on Band</string> <property name="text">
</property> <string>Transmitted message</string>
</widget> </property>
</item> </widget>
<item row="7" column="1"> </item>
<widget class="QLabel" name="label_12"> <item row="3" column="0">
<property name="text"> <widget class="QLabel" name="example4_label">
<string>New Call</string> <property name="autoFillBackground">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="text">
<item row="5" column="1"> <string>K1ABC</string>
<widget class="QLabel" name="label_16"> </property>
<property name="text"> <property name="alignment">
<string>New Grid</string> <set>Qt::AlignCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="3" column="1">
<widget class="QLabel" name="label_18"> <widget class="QLabel" name="p4_label">
<property name="text"> <property name="text">
<string>New Grid on Band</string> <string>New DXCC</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="example5_label">
<property name="text"> <property name="autoFillBackground">
<string>K1ABC</string> <bool>true</bool>
</property> </property>
<property name="alignment"> <property name="text">
<set>Qt::AlignCenter</set> <string>K1ABC</string>
</property> </property>
</widget> <property name="alignment">
</item> <set>Qt::AlignCenter</set>
<item row="0" column="0"> </property>
<widget class="QLabel" name="label"> </widget>
<property name="text"> </item>
<string>K1ABC</string> <item row="4" column="1">
</property> <widget class="QLabel" name="p5_label">
<property name="alignment"> <property name="text">
<set>Qt::AlignCenter</set> <string>New DXCC on Band</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="5" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="example6_label">
<property name="text"> <property name="autoFillBackground">
<string>K1ABC</string> <bool>true</bool>
</property> </property>
<property name="alignment"> <property name="text">
<set>Qt::AlignCenter</set> <string>K1ABC</string>
</property> </property>
</widget> <property name="alignment">
</item> <set>Qt::AlignCenter</set>
<item row="4" column="0"> </property>
<widget class="QLabel" name="label_9"> </widget>
<property name="text"> </item>
<string>K1ABC</string> <item row="5" column="1">
</property> <widget class="QLabel" name="p6_label">
<property name="alignment"> <property name="text">
<set>Qt::AlignCenter</set> <string>New Grid</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="6" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="example7_label">
<property name="text"> <property name="autoFillBackground">
<string>CQ in message</string> <bool>true</bool>
</property> </property>
</widget> <property name="text">
</item> <string>K1ABC</string>
<item row="1" column="1"> </property>
<widget class="QLabel" name="label_4"> <property name="alignment">
<property name="text"> <set>Qt::AlignCenter</set>
<string>My Call in message</string> </property>
</property> </widget>
</widget> </item>
</item> <item row="6" column="1">
<item row="3" column="0"> <widget class="QLabel" name="p7_label">
<widget class="QLabel" name="label_7"> <property name="text">
<property name="text"> <string>New Grid on Band</string>
<string>K1ABC</string> </property>
</property> </widget>
<property name="alignment"> </item>
<set>Qt::AlignCenter</set> <item row="7" column="0">
</property> <widget class="QLabel" name="example8_label">
</widget> <property name="autoFillBackground">
</item> <bool>true</bool>
<item row="4" column="1"> </property>
<widget class="QLabel" name="label_10"> <property name="text">
<property name="text"> <string>K1ABC</string>
<string>New DXCC on Band</string> </property>
</property> <property name="alignment">
</widget> <set>Qt::AlignCenter</set>
</item> </property>
<item row="3" column="1"> </widget>
<widget class="QLabel" name="label_8"> </item>
<property name="text"> <item row="7" column="1">
<string>New DXCC</string> <widget class="QLabel" name="p8_label">
</property> <property name="text">
</widget> <string>New Call</string>
</item> </property>
<item row="9" column="0"> </widget>
<widget class="QLabel" name="label_19"> </item>
<property name="text"> <item row="8" column="0">
<string>K1ABC</string> <widget class="QLabel" name="example9_label">
</property> <property name="autoFillBackground">
<property name="alignment"> <bool>true</bool>
<set>Qt::AlignCenter</set> </property>
</property> <property name="text">
</widget> <string>K1ABC</string>
</item> </property>
<item row="9" column="1"> <property name="alignment">
<widget class="QLabel" name="label_20"> <set>Qt::AlignCenter</set>
<property name="text"> </property>
<string>Not in LoTW</string> </widget>
</property> </item>
</widget> <item row="8" column="1">
</item> <widget class="QLabel" name="p9_label">
</layout> <property name="text">
<string>New Call on Band</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="example10_label">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="p10_label">
<property name="text">
<string>Uploads to LotW</string>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>

File diff suppressed because it is too large Load Diff

1849
cty.dat

File diff suppressed because it is too large Load Diff

View File

@ -64,7 +64,7 @@ QStringList DecodedText::messageWords () const
QString DecodedText::CQersCall() const QString DecodedText::CQersCall() const
{ {
QRegularExpression callsign_re {R"(^(CQ|DE|QRZ)(\s?DX|\s([A-Z]{2}|\d{3}))?\s(?<callsign>[A-Z0-9/]{2,})(\s[A-R]{2}[0-9]{2})?)"}; QRegularExpression callsign_re {R"(^(CQ|DE|QRZ)(\s?DX|\s([A-Z]{2,4}|\d{3}))?\s(?<callsign>[A-Z0-9/]{2,})(\s[A-R]{2}[0-9]{2})?)"};
return callsign_re.match (message_).captured ("callsign"); return callsign_re.match (message_).captured ("callsign");
} }

View File

@ -12,11 +12,11 @@ JT65 111010000000111000010000000000001
JT65/VHF 111110010000111110101100010000000 JT65/VHF 111110010000111110101100010000000
QRA64 111110010110111110000000001000000 QRA64 111110010110111110000000001000000
ISCAT 100111000000000110000000000000000 ISCAT 100111000000000110000000000000000
MSK144 101111110100000000010001000010000 MSK144 101111110100000000010001000000000
WSPR 000000000000000001010000000000000 WSPR 000000000000000001010000000000000
Echo 000000000000000000000010000000000 Echo 000000000000000000000010000000000
FCal 001101000000000000000000000001000 FCal 001101000000000000000000000001000
FT8 111010000100111000010000100100001 FT8 111010000100111000010000100110001
FT8/VHF 111010000100111000010000100110001 FT8/VHF 111010000100111000010000100110001
FT8/Fox 111010000100111000010000000000100 FT8/Fox 111010000100111000010000000000100
FT8/Hound 111010000100111000010000000000110 FT8/Hound 111010000100111000010000000000110
@ -55,7 +55,7 @@ Mapping of column numbers to widgets
25. AP JT65 25. AP JT65
26. AP DX Call 26. AP DX Call
27. cbFirst 27. cbFirst
28. cbVHFcontest 28. labNextCall
29. measure_check_box 29. measure_check_box
30. labDXped 30. labDXped
31. cbRxAll 31. cbRxAll

View File

@ -1,5 +1,4 @@
#include "displaytext.h" #include "displaytext.h"
#include "mainwindow.h"
#include <QMouseEvent> #include <QMouseEvent>
#include <QDateTime> #include <QDateTime>
#include <QTextCharFormat> #include <QTextCharFormat>
@ -8,12 +7,16 @@
#include <QMenu> #include <QMenu>
#include <QAction> #include <QAction>
#include "qt_helpers.hpp" #include "Configuration.hpp"
#include "LotWUsers.hpp"
#include "DecodeHighlightingModel.hpp"
#include "qt_helpers.hpp"
#include "moc_displaytext.cpp" #include "moc_displaytext.cpp"
DisplayText::DisplayText(QWidget *parent) DisplayText::DisplayText(QWidget *parent)
: QTextEdit(parent) : QTextEdit(parent)
, m_config {nullptr}
, erase_action_ {new QAction {tr ("&Erase"), this}} , erase_action_ {new QAction {tr ("&Erase"), this}}
{ {
setReadOnly (true); setReadOnly (true);
@ -73,13 +76,53 @@ void DisplayText::insertLineSpacer(QString const& line)
appendText (line, "#d3d3d3"); appendText (line, "#d3d3d3");
} }
void DisplayText::appendText(QString const& text, QColor bg, namespace
QString const& call1, QString const& call2) {
void set_colours (Configuration const * config, QColor * bg, QColor * fg, DecodeHighlightingModel::Highlight type)
{
if (config)
{
for (auto const& item : config->decode_highlighting ().items ())
{
if (type == item.type_ && item.enabled_)
{
if (item.background_.style () != Qt::NoBrush)
{
*bg = item.background_.color ();
}
if (item.foreground_.style () != Qt::NoBrush)
{
*fg = item.foreground_.color ();
}
break;
}
}
}
}
}
void DisplayText::appendText(QString const& text, QColor bg, QColor fg
, QString const& call1, QString const& call2)
{ {
auto cursor = textCursor (); auto cursor = textCursor ();
cursor.movePosition (QTextCursor::End); cursor.movePosition (QTextCursor::End);
auto block_format = cursor.blockFormat (); auto block_format = cursor.blockFormat ();
block_format.setBackground (bg); if (bg.isValid ())
{
block_format.setBackground (bg);
}
else
{
block_format.clearBackground ();
}
if (fg.isValid ())
{
block_format.setForeground (fg);
}
else
{
block_format.clearForeground ();
}
if (0 == cursor.position ()) if (0 == cursor.position ())
{ {
cursor.setBlockFormat (block_format); cursor.setBlockFormat (block_format);
@ -90,10 +133,13 @@ void DisplayText::appendText(QString const& text, QColor bg,
else else
{ {
cursor.insertBlock (block_format); cursor.insertBlock (block_format);
auto char_format = cursor.charFormat ();
char_format.clearBackground ();
char_format.clearForeground ();
cursor.setCharFormat (char_format);
} }
QTextCharFormat format = cursor.charFormat(); QTextCharFormat format = cursor.charFormat();
format.clearBackground();
int text_index {0}; int text_index {0};
if (call1.size ()) if (call1.size ())
{ {
@ -126,7 +172,7 @@ void DisplayText::appendText(QString const& text, QColor bg,
if (pos != highlighted_calls_.end ()) if (pos != highlighted_calls_.end ())
{ {
format.setBackground (bg); format.setBackground (bg);
format.clearForeground (); format.setForeground (fg);
cursor.insertText(text.mid (text_index, call_index - text_index), format); cursor.insertText(text.mid (text_index, call_index - text_index), format);
if (pos.value ().second.isValid ()) if (pos.value ().second.isValid ())
{ {
@ -141,11 +187,14 @@ void DisplayText::appendText(QString const& text, QColor bg,
} }
} }
} }
format.setBackground (bg); if (call2.size () && m_config && m_config->lotw_users ().user (call2))
format.clearForeground (); {
if(call2.size()>0 and !m_LoTW.contains(call2)) { QColor bg;
format.setForeground(m_color_LoTW); //Mark LoTW non-users QColor fg;
} set_colours (m_config, &bg, &fg, DecodeHighlightingModel::Highlight::LotW);
if (bg.isValid ()) format.setBackground (bg);
if (fg.isValid ()) format.setForeground (fg);
}
cursor.insertText(text.mid (text_index), format); cursor.insertText(text.mid (text_index), format);
// position so viewport scrolled to left // position so viewport scrolled to left
@ -156,7 +205,7 @@ void DisplayText::appendText(QString const& text, QColor bg,
} }
QString DisplayText::appendWorkedB4(QString message, QString const& callsign, QString grid, QString DisplayText::appendWorkedB4(QString message, QString const& callsign, QString grid,
QColor * bg, LogBook const& logBook, QString currentBand) QColor * bg, QColor * fg, LogBook const& logBook, QString currentBand)
{ {
// allow for seconds // allow for seconds
int padding {message.indexOf (" ") > 4 ? 2 : 0}; int padding {message.indexOf (" ") > 4 ? 2 : 0};
@ -191,29 +240,29 @@ QString DisplayText::appendWorkedB4(QString message, QString const& callsign, QS
if (!countryWorkedBefore) { if (!countryWorkedBefore) {
// therefore not worked call either // therefore not worked call either
// appendage += "!"; // appendage += "!";
*bg = m_color_DXCC; set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::CQ);
} else { } else {
if(!countryB4onBand) { if(!countryB4onBand) {
*bg = m_color_DXCCband; set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::DXCCBand);
} else { } else {
if(!gridB4) { if(!gridB4) {
*bg = m_color_NewGrid; set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::Grid);
} else { } else {
if(!gridB4onBand) { if(!gridB4onBand) {
*bg = m_color_NewGridBand; set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::GridBand);
} else { } else {
if (!callWorkedBefore) { if (!callWorkedBefore) {
// but have worked the country // but have worked the country
// appendage += "~"; // appendage += "~";
*bg = m_color_NewCall; set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::Call);
} else { } else {
if(!callB4onBand) { if(!callB4onBand) {
// appendage += "~"; // appendage += "~";
*bg = m_color_NewCallBand; set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::CallBand);
} else { } else {
// appendage += " "; // have worked this call before // appendage += " "; // have worked this call before
*bg = m_color_CQ; set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::CQ);
} }
} }
} }
@ -266,14 +315,15 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
QString currentBand, bool ppfx, bool bCQonly) QString currentBand, bool ppfx, bool bCQonly)
{ {
m_bPrincipalPrefix=ppfx; m_bPrincipalPrefix=ppfx;
QColor bg {Qt::transparent}; QColor bg;
QColor fg;
bool CQcall = false; bool CQcall = false;
if (decodedText.string ().contains (" CQ ") if (decodedText.string ().contains (" CQ ")
|| decodedText.string ().contains (" CQDX ") || decodedText.string ().contains (" CQDX ")
|| decodedText.string ().contains (" QRZ ")) || decodedText.string ().contains (" QRZ "))
{ {
CQcall = true; CQcall = true;
bg = m_color_CQ; set_colours (m_config, &bg, &fg, DecodeHighlightingModel::Highlight::CQ);
} }
if(bCQonly and !CQcall) return; if(bCQonly and !CQcall) return;
if (myCall != "" and (decodedText.indexOf (" " + myCall + " ") >= 0 if (myCall != "" and (decodedText.indexOf (" " + myCall + " ") >= 0
@ -284,7 +334,7 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
or decodedText.indexOf ("<" + myCall + " ") >= 0 or decodedText.indexOf ("<" + myCall + " ") >= 0
or decodedText.indexOf ("<" + myCall + ">") >= 0 or decodedText.indexOf ("<" + myCall + ">") >= 0
or decodedText.indexOf (" " + myCall + ">") >= 0)) { or decodedText.indexOf (" " + myCall + ">") >= 0)) {
bg = m_color_MyCall; set_colours (m_config, &bg, &fg, DecodeHighlightingModel::Highlight::MyCall);
} }
auto message = decodedText.string(); auto message = decodedText.string();
QString dxCall; QString dxCall;
@ -296,8 +346,8 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
if (displayDXCCEntity && CQcall) if (displayDXCCEntity && CQcall)
// if enabled add the DXCC entity and B4 status to the end of the // if enabled add the DXCC entity and B4 status to the end of the
// preformated text line t1 // preformated text line t1
message = appendWorkedB4 (message, decodedText.CQersCall(), dxGrid, &bg, logBook, currentBand); message = appendWorkedB4 (message, decodedText.CQersCall(), dxGrid, &bg, &fg, logBook, currentBand);
appendText (message.trimmed (), bg, decodedText.call (), dxCall); appendText (message.trimmed (), bg, fg, decodedText.call (), dxCall);
} }
@ -321,7 +371,10 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx
t = QDateTime::currentDateTimeUtc().toString("hhmm") + \ t = QDateTime::currentDateTimeUtc().toString("hhmm") + \
" Tx " + t2 + t1 + text; " Tx " + t2 + t1 + text;
} }
appendText (t, m_color_TxMsg); QColor bg;
QColor fg;
set_colours (m_config, &bg, &fg, DecodeHighlightingModel::Highlight::Tx);
appendText (t, bg, fg);
} }
void DisplayText::displayQSY(QString text) void DisplayText::displayQSY(QString text)
@ -330,9 +383,9 @@ void DisplayText::displayQSY(QString text)
appendText (t, "hotpink"); appendText (t, "hotpink");
} }
void DisplayText::displayFoxToBeCalled(QString t, QColor bg) void DisplayText::displayFoxToBeCalled(QString t, QColor bg, QColor fg)
{ {
appendText(t,bg); appendText (t, bg, fg);
} }
namespace namespace
@ -428,20 +481,3 @@ void DisplayText::highlight_callsign (QString const& callsign, QColor const& bg,
} }
setCurrentCharFormat (old_format); setCurrentCharFormat (old_format);
} }
void DisplayText::setDecodedTextColors(QColor color_CQ, QColor color_MyCall,
QColor color_DXCC, QColor color_DXCCband,QColor color_NewCall,QColor color_NewCallBand,
QColor color_NewGrid, QColor color_NewGridBand,QColor color_TxMsg,QColor color_LoTW)
{
// Save the color highlighting scheme selected by the user.
m_color_CQ=color_CQ;
m_color_DXCC=color_DXCC;
m_color_DXCCband=color_DXCCband;
m_color_MyCall=color_MyCall;
m_color_NewCall=color_NewCall;
m_color_NewCallBand=color_NewCallBand;
m_color_NewGrid=color_NewGrid;
m_color_NewGridBand=color_NewGridBand;
m_color_TxMsg=color_TxMsg;
m_color_LoTW=color_LoTW;
}

View File

@ -12,6 +12,7 @@
#include "decodedtext.h" #include "decodedtext.h"
class QAction; class QAction;
class Configuration;
class DisplayText class DisplayText
: public QTextEdit : public QTextEdit
@ -19,7 +20,7 @@ class DisplayText
Q_OBJECT Q_OBJECT
public: public:
explicit DisplayText(QWidget *parent = 0); explicit DisplayText(QWidget *parent = 0);
void set_configuration (Configuration const * configuration) {m_config = configuration;}
void setContentFont (QFont const&); void setContentFont (QFont const&);
void insertLineSpacer(QString const&); void insertLineSpacer(QString const&);
void displayDecodedText(DecodedText const& decodedText, QString const& myCall, void displayDecodedText(DecodedText const& decodedText, QString const& myCall,
@ -27,16 +28,12 @@ public:
QString currentBand="", bool ppfx=false, bool bCQonly=false); QString currentBand="", bool ppfx=false, bool bCQonly=false);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode); void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode);
void displayQSY(QString text); void displayQSY(QString text);
void displayFoxToBeCalled(QString t, QColor bg); void displayFoxToBeCalled(QString t, QColor bg = QColor {}, QColor fg = QColor {});
void setDecodedTextColors(QColor color_CQ, QColor color_MyCall, QColor color_DXCC,
QColor color_DXCCband, QColor color_NewCall, QColor color_NewCallBand,
QColor color_NewGrid, QColor color_NewGridBand, QColor color_TxMsg,
QColor color_LoTW);
Q_SIGNAL void selectCallsign (Qt::KeyboardModifiers); Q_SIGNAL void selectCallsign (Qt::KeyboardModifiers);
Q_SIGNAL void erased (); Q_SIGNAL void erased ();
Q_SLOT void appendText (QString const& text, QColor bg = Qt::white Q_SLOT void appendText (QString const& text, QColor bg = QColor {}, QColor fg = QColor {}
, QString const& call1 = QString {}, QString const& call2 = QString {}); , QString const& call1 = QString {}, QString const& call2 = QString {});
Q_SLOT void erase (); Q_SLOT void erase ();
Q_SLOT void highlight_callsign (QString const& callsign, QColor const& bg, QColor const& fg, bool last_only); Q_SLOT void highlight_callsign (QString const& callsign, QColor const& bg, QColor const& fg, bool last_only);
@ -45,22 +42,14 @@ protected:
void mouseDoubleClickEvent(QMouseEvent *e); void mouseDoubleClickEvent(QMouseEvent *e);
private: private:
Configuration const * m_config;
bool m_bPrincipalPrefix; bool m_bPrincipalPrefix;
QString appendWorkedB4(QString message, QString const& callsign, QString grid, QColor * bg, QString appendWorkedB4(QString message, QString const& callsign
LogBook const& logBook, QString currentBand); , QString grid, QColor * bg, QColor * fg
, LogBook const& logBook, QString currentBand);
QFont char_font_; QFont char_font_;
QAction * erase_action_; QAction * erase_action_;
QHash<QString, QPair<QColor, QColor>> highlighted_calls_; QHash<QString, QPair<QColor, QColor>> highlighted_calls_;
QColor m_color_CQ;
QColor m_color_MyCall;
QColor m_color_DXCC;
QColor m_color_DXCCband;
QColor m_color_NewCall;
QColor m_color_NewCallBand;
QColor m_color_NewGrid;
QColor m_color_NewGridBand;
QColor m_color_LoTW;
QColor m_color_TxMsg;
}; };
extern QHash<QString,int> m_LoTW; extern QHash<QString,int> m_LoTW;

View File

@ -37,12 +37,14 @@ information:
7. All features of FT8 DXpedition mode, as in WSJT-X v1.9.1 7. All features of FT8 DXpedition mode, as in WSJT-X v1.9.1
Enhancements to the FT8 decoder ensure that in most situations Conveying more information in the same bandwidth, using the same
decoding sensitivity is slightly better than for the old protocol. modulation scheme, necessarily means a higher code rate and less
Symbol rates and occupied bandwidths are the same as before, and energy per information bit. Nevertheless, the decoding threshold S/N
false-decode rates are significantly lower. The decoding threshold for the new FT8 is slightly lower than for the old version, because of
for MSK144 is a fraction of a dB higher than before, owing to the improvements in the decoding algorithm. Decoding threshold for MSK144
slightly larger message payload and higher code rate. is a fraction of a dB higher than before. Symbol rates and occupied
bandwidths for both modes are the same as before, and false-decode
rates are significantly lower.
OTHER PROGRAM ENHANCEMENTS: WSJT-X 2.0 has several other new features OTHER PROGRAM ENHANCEMENTS: WSJT-X 2.0 has several other new features
and capabilities. The WSPR decoder has significantly better and capabilities. The WSPR decoder has significantly better

View File

@ -1,6 +1,6 @@
gfortran -c ../packjt.f90 gfortran -c ../packjt.f90
gfortran -c packjt77.f90 gfortran -c packjt77.f90
gfortran -o encode77 -fbounds-check -Wall -Wno-conversion -Wno-real-q-constant \ gfortran -o encode77 -fbounds-check -Wall -Wno-conversion \
encode77.f90 ../deg2grid.f90 ../grid2deg.f90 ../fix_contest_msg.f90 \ encode77.f90 ../deg2grid.f90 ../grid2deg.f90 ../fix_contest_msg.f90 \
../to_contest_msg.f90 ../fmtmsg.f90 ../azdist.f90 ../geodist.f90 \ ../to_contest_msg.f90 ../fmtmsg.f90 ../azdist.f90 ../geodist.f90 \
packjt.o packjt77.o packjt.o packjt77.o

View File

@ -17,10 +17,7 @@ subroutine hash10(n10,c13)
do i=1,nzhash do i=1,nzhash
if(ihash10(i).eq.n10) then if(ihash10(i).eq.n10) then
c13=callsign(i) c13=callsign(i)
if(c13(1:1).ne.'<') then c13='<'//trim(c13)//'>'//' '
n=len(trim(c13))
c13='<'//trim(c13)//'>'//' '
endif
go to 900 go to 900
endif endif
enddo enddo
@ -36,10 +33,7 @@ subroutine hash12(n12,c13)
do i=1,nzhash do i=1,nzhash
if(ihash12(i).eq.n12) then if(ihash12(i).eq.n12) then
c13=callsign(i) c13=callsign(i)
if(c13(1:1).ne.'<') then c13='<'//trim(c13)//'>'//' '
n=len(trim(c13))
c13='<'//trim(c13)//'>'//' '
endif
go to 900 go to 900
endif endif
enddo enddo
@ -56,10 +50,7 @@ subroutine hash22(n22,c13)
do i=1,nzhash do i=1,nzhash
if(ihash22(i).eq.n22) then if(ihash22(i).eq.n22) then
c13=callsign(i) c13=callsign(i)
if(c13(1:1).ne.'<') then c13='<'//trim(c13)//'>'//' '
n=len(trim(c13))
c13='<'//trim(c13)//'>'//' '
endif
go to 900 go to 900
endif endif
enddo enddo
@ -71,17 +62,13 @@ end subroutine hash22
integer function ihashcall(c0,m) integer function ihashcall(c0,m)
integer*8 n8 integer*8 n8
character*13 c0,c1 character*13 c0
character*38 c character*38 c
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/ data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
c1=c0
if(c1(1:1).eq.'<') c1=c1(2:)
i=index(c1,'>')
if(i.gt.0) c1(i:)=' '
n8=0 n8=0
do i=1,11 do i=1,11
j=index(c,c1(i:i)) - 1 j=index(c,c0(i:i)) - 1
n8=38*n8 + j n8=38*n8 + j
enddo enddo
ihashcall=ishft(47055833459_8*n8,m-64) ihashcall=ishft(47055833459_8*n8,m-64)
@ -91,7 +78,7 @@ end function ihashcall
subroutine save_hash_call(c13,n10,n12,n22) subroutine save_hash_call(c13,n10,n12,n22)
character*13 c13 character*13 c13,cw
logical first logical first
data first/.true./ data first/.true./
save first save first
@ -105,11 +92,15 @@ subroutine save_hash_call(c13,n10,n12,n22)
first=.false. first=.false.
endif endif
if(c13(1:1).eq.' ' .or. c13(1:5).eq.'<...>') return cw=c13
if(cw(1:1).eq.' ' .or. cw(1:5).eq.'<...>') return
if(cw(1:1).eq.'<') cw=cw(2:)
i=index(cw,'>')
if(i.gt.0) cw(i:)=' '
n10=ihashcall(c13,10) n10=ihashcall(cw,10)
n12=ihashcall(c13,12) n12=ihashcall(cw,12)
n22=ihashcall(c13,22) n22=ihashcall(cw,22)
do i=1,nzhash do i=1,nzhash
if(ihash22(i).eq.n22) go to 900 !This one is already in the table if(ihash22(i).eq.n22) go to 900 !This one is already in the table
enddo enddo
@ -124,7 +115,7 @@ subroutine save_hash_call(c13,n10,n12,n22)
ihash10(1)=n10 ihash10(1)=n10
ihash12(1)=n12 ihash12(1)=n12
ihash22(1)=n22 ihash22(1)=n22
callsign(1)=c13 callsign(1)=cw
if(nzhash.lt.MAXHASH) nzhash=nzhash+1 if(nzhash.lt.MAXHASH) nzhash=nzhash+1
900 return 900 return
@ -236,7 +227,7 @@ subroutine unpack77(c77,msg,unpk77_success)
"NM ","NY ","NC ","ND ","OH ","OK ","OR ","PA ","RI ","SC ", & "NM ","NY ","NC ","ND ","OH ","OK ","OR ","PA ","RI ","SC ", &
"SD ","TN ","TX ","UT ","VT ","VA ","WA ","WV ","WI ","WY ", & "SD ","TN ","TX ","UT ","VT ","VA ","WA ","WV ","WI ","WY ", &
"NB ","NS ","QC ","ON ","MB ","SK ","AB ","BC ","NWT","NF ", & "NB ","NS ","QC ","ON ","MB ","SK ","AB ","BC ","NWT","NF ", &
"LB ","NU ","VT ","PEI","DC "/ "LB ","NU ","YT ","PEI","DC "/
unpk77_success=.true. unpk77_success=.true.
@ -448,9 +439,11 @@ subroutine unpack77(c77,msg,unpk77_success)
if(iflip.eq.0) then if(iflip.eq.0) then
call_1=call_3 call_1=call_3
call_2=adjustl(c11)//' ' call_2=adjustl(c11)//' '
call add_call_to_recent_calls(call_2)
else else
call_1=adjustl(c11)//' ' call_1=adjustl(c11)//' '
call_2=call_3 call_2=call_3
call add_call_to_recent_calls(call_1)
endif endif
if(icq.eq.0) then if(icq.eq.0) then
if(nrpt.eq.0) msg=trim(call_1)//' '//trim(call_2) if(nrpt.eq.0) msg=trim(call_1)//' '//trim(call_2)
@ -662,7 +655,7 @@ subroutine unpack28(n28_0,c13,success)
c13=adjustl(c13) c13=adjustl(c13)
900 i0=index(c13,' ') 900 i0=index(c13,' ')
if(i0.lt.len(trim(c13))) then if(i0.ne.0 .and. i0.lt.len(trim(c13))) then
c13='QU1RK' c13='QU1RK'
success=.false. success=.false.
endif endif
@ -990,7 +983,7 @@ subroutine pack77_3(nwords,w,i3,n3,c77)
"NM ","NY ","NC ","ND ","OH ","OK ","OR ","PA ","RI ","SC ", & "NM ","NY ","NC ","ND ","OH ","OK ","OR ","PA ","RI ","SC ", &
"SD ","TN ","TX ","UT ","VT ","VA ","WA ","WV ","WI ","WY ", & "SD ","TN ","TX ","UT ","VT ","VA ","WA ","WV ","WI ","WY ", &
"NB ","NS ","QC ","ON ","MB ","SK ","AB ","BC ","NWT","NF ", & "NB ","NS ","QC ","ON ","MB ","SK ","AB ","BC ","NWT","NF ", &
"LB ","NU ","VT ","PEI","DC "/ "LB ","NU ","YT ","PEI","DC "/
if(nwords.eq.4 .or. nwords.eq.5 .or. nwords.eq.6) then if(nwords.eq.4 .or. nwords.eq.5 .or. nwords.eq.6) then
i1=1 i1=1
@ -1218,6 +1211,9 @@ subroutine add_call_to_recent_calls(callsign)
recent_calls(1)=callsign recent_calls(1)=callsign
endif endif
! Make sure that callsign is hashed
call save_hash_call(callsign,n10,n12,n22)
return return
end subroutine add_call_to_recent_calls end subroutine add_call_to_recent_calls

View File

@ -1,54 +0,0 @@
program t1
real x(13)
real(KIND=16) :: dlong,dlong0
character wd*13,w*13,error*5
character c*44 !NB: 44^13 = 2^(70.973)
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?@$'/
nargs=iargc()
if(nargs.ne.1) then
print*,'Usage: t1 "FreeText13"'
print*,' t1 <iters>'
go to 999
endif
call getarg(1,w)
iters=1
read(w,*,err=10) iters
10 continue
do iter=1,iters
if(iters.gt.1) then
! Create a random free-text word
call random_number(x)
do i=1,13
j=44*x(i) + 1
w(i:i)=c(j:j)
enddo
endif
! Encode a 13-character free-text message into a 71-bit integer.
dlong=0.d0
do i=1,13
n=index(c,w(i:i))-1
dlong=44.d0*dlong + n
enddo
dlong0=dlong
! Decode a a 71-bit integer into a 13-character free-text message.
do i=13,1,-1
j=mod(dlong,44.d0)+1.d0
wd(i:i)=c(j:j)
dlong=dlong/44.d0
enddo
error=' '
if(wd.ne.w) then
error='ERROR'
write(*,1010) w,dlong0,wd,error
1010 format('"',a13,'"',f25.1,2x,'"',a13'"',2x,a5)
endif
if(mod(iter,1000).eq.0) print*,iter
enddo
999 end program t1

View File

@ -1,25 +0,0 @@
program t3
character*3 csec
character*70 line
logical eof
eof=.false.
j=1
do i=1,83
read(*,1001,end=1) csec
1001 format(a3)
go to 2
1 eof=.true.
2 line(j:j+5)='"'//csec//'",'
j=j+6
if(j.gt.60 .or. i.eq.83 .or.eof) then
line(j:j+2)=' &'
line(j+3:)=' '
write(*,1010) line
1010 format(a70)
j=1
endif
if(eof) go to 999
enddo
999 end program t3

View File

@ -26,7 +26,7 @@ module crc
integer (c_int), value :: length integer (c_int), value :: length
end function crc13 end function crc13
function crc13_check (data, length) bind (C, name="crc14_check") function crc13_check (data, length) bind (C, name="crc13_check")
use, intrinsic :: iso_c_binding, only: c_bool, c_ptr, c_int use, intrinsic :: iso_c_binding, only: c_bool, c_ptr, c_int
implicit none implicit none
logical (c_bool) :: crc13_check logical (c_bool) :: crc13_check

View File

@ -67,20 +67,6 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
else else
open(13,file=trim(temp_dir)//'/decoded.txt',status='unknown',iostat=ios) open(13,file=trim(temp_dir)//'/decoded.txt',status='unknown',iostat=ios)
endif endif
if(params%nmode.eq.8) then
inquire(file=trim(temp_dir)//'/houndcallers.txt',exist=ex)
if(.not.ex) then
c2fox=' '
g2fox=' '
nsnrfox=-99
nfreqfox=-99
n30z=0
nwrap=0
nfox=0
endif
open(19,file=trim(temp_dir)//'/houndcallers.txt',status='unknown')
endif
if(ios.ne.0) then if(ios.ne.0) then
nfail=nfail+1 nfail=nfail+1
if(nfail.le.3) then if(nfail.le.3) then
@ -91,6 +77,22 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
if(params%nmode.eq.8) then if(params%nmode.eq.8) then
! We're in FT8 mode ! We're in FT8 mode
if(ncontest.eq.5) then
! Fox mode: initialize and open houndcallers.txt
inquire(file=trim(temp_dir)//'/houndcallers.txt',exist=ex)
if(.not.ex) then
c2fox=' '
g2fox=' '
nsnrfox=-99
nfreqfox=-99
n30z=0
nwrap=0
nfox=0
endif
open(19,file=trim(temp_dir)//'/houndcallers.txt',status='unknown')
endif
call timer('decft8 ',0) call timer('decft8 ',0)
newdat=params%newdat newdat=params%newdat
ncontest=iand(params%nexp_decode,7) ncontest=iand(params%nexp_decode,7)
@ -106,33 +108,37 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
n30max=maxval(n30fox(1:nfox)) n30max=maxval(n30fox(1:nfox))
endif endif
j=0 j=0
rewind 19
if(nfox.eq.0) then if(ncontest.eq.5) then
endfile 19 ! Fox mode: save decoded Hound calls for possible selection by FoxOp
rewind 19 rewind 19
else if(nfox.eq.0) then
do i=1,nfox endfile 19
n=n30fox(i) rewind 19
if(n30max-n30fox(i).le.4) then else
j=j+1 do i=1,nfox
c2fox(j)=c2fox(i) n=n30fox(i)
g2fox(j)=g2fox(i) if(n30max-n30fox(i).le.4) then
nsnrfox(j)=nsnrfox(i) j=j+1
nfreqfox(j)=nfreqfox(i) c2fox(j)=c2fox(i)
n30fox(j)=n g2fox(j)=g2fox(i)
m=n30max-n nsnrfox(j)=nsnrfox(i)
if(len(trim(g2fox(j))).eq.4) then nfreqfox(j)=nfreqfox(i)
call azdist(mygrid,g2fox(j),0.d0,nAz,nEl,nDmiles,nDkm, & n30fox(j)=n
nHotAz,nHotABetter) m=n30max-n
else if(len(trim(g2fox(j))).eq.4) then
nDkm=9999 call azdist(mygrid,g2fox(j),0.d0,nAz,nEl,nDmiles,nDkm, &
nHotAz,nHotABetter)
else
nDkm=9999
endif
write(19,1004) c2fox(j),g2fox(j),nsnrfox(j),nfreqfox(j),nDkm,m
1004 format(a12,1x,a4,i5,i6,i7,i3)
endif endif
write(19,1004) c2fox(j),g2fox(j),nsnrfox(j),nfreqfox(j),nDkm,m enddo
1004 format(a12,1x,a4,i5,i6,i7,i3) nfox=j
endif flush(19)
enddo endif
nfox=j
flush(19)
endif endif
go to 800 go to 800
endif endif

8
lib/emedop.dat Normal file
View File

@ -0,0 +1,8 @@
Lat_A 40.35417
WLong_A 75.62500
Lat_B 45.1875
WLong_B -1.541667
TxFreqMHz 143.05
StartTime 20180907 08:00:00
StopTime 20180907 09:00:00
StepSec 60.0

67
lib/emedop.f90 Normal file
View File

@ -0,0 +1,67 @@
program emedop
real*8 txfreq8
real*8 rxfreq8
real*4 LST
real*4 lat_a
real*4 lat_b
character*80 infile
character*256 jpleph_file_name
common/jplcom/jpleph_file_name
data jpleph_file_name/'JPLEPH'/
nargs=iargc()
if(nargs.ne.1) then
print*,'Usage: emedop <infile>'
go to 999
endif
call getarg(1,infile)
open(10,file=infile,status='old',err=900)
read(10,1001) lat_a
1001 format(10x,f12.0)
read(10,1001) wlon_a
read(10,1001) lat_b
read(10,1001) wlon_b
read(10,1001) txfreq8
read(10,1002) nyear,month,nday,ih,im,is
1002 format(10x,i4,2i2,1x,i2,1x,i2,1x,i2)
sec_start=3600.0*ih + 60.0*im + is
read(10,1002) nyear,month,nday,ih,im,is
sec_stop=3600.0*ih + 60.0*im + is
read(10,1001) sec_step
write(*,1005)
1005 format(' Date UTC Tx Freq Rx Freq Doppler'/ &
'------------------------------------------------------')
sec=sec_start
ncalc=(sec_stop - sec_start)/sec_step
do icalc=1,ncalc
uth=sec/3600.0
call MoonDopJPL(nyear,month,nday,uth,-wlon_a,lat_a,RAMoon,DecMoon, &
LST,HA,AzMoon,ElMoon,vr_a,techo)
call MoonDopJPL(nyear,month,nday,uth,-wlon_b,lat_b,RAMoon,DecMoon, &
LST,HA,AzMoon,ElMoon,vr_b,techo)
dop_a=-txfreq8*vr_a/2.99792458e5 !One-way Doppler from a
dop_b=-txfreq8*vr_b/2.99792458e5 !One-way Doppler to b
doppler=1.e6*(dop_a + dop_b)
rxfreq8=txfreq8 + dop_a + dop_b
ih=sec/3600.0
im=(sec-ih*3600.0)/60.0
is=nint(mod(sec,60.0))
write(*,1010) nyear,month,nday,ih,im,is,txFreq8,rxFreq8,doppler
1010 format(i4,2i2.2,2x,i2.2,':',i2.2,':',i2.2,2f13.7,f8.1)
sec=sec + sec_step
enddo
go to 999
900 print*,'Cannot open file ',trim(infile)
999 end program emedop

View File

@ -14,25 +14,20 @@ subroutine foxgen()
! common/foxcom/. The generated wave(NWAVE) is passed back in the same ! common/foxcom/. The generated wave(NWAVE) is passed back in the same
! common block. ! common block.
use crc parameter (NN=79,ND=58,NSPS=4*1920)
parameter (NN=79,ND=58,KK=87,NSPS=4*1920)
parameter (NWAVE=NN*NSPS,NFFT=614400,NH=NFFT/2) parameter (NWAVE=NN*NSPS,NFFT=614400,NH=NFFT/2)
character*40 cmsg character*40 cmsg
character*37 msg,msgsent character*37 msg,msgsent
character*87 cbits integer itone(79)
character*88 cb88 integer*1 msgbits(77),msgbits2
integer itone(NN)
integer icos7(0:6)
integer*1 msgbits(KK),codeword(3*ND),msgbits2
integer*1, target:: i1Msg8BitBytes(11) integer*1, target:: i1Msg8BitBytes(11)
integer*1, target:: mycall integer*1, target:: mycall
real x(NFFT) real x(NFFT)
real*8 dt,twopi,f0,fstep,dfreq,phi,dphi real*8 dt,twopi,f0,fstep,dfreq,phi,dphi
complex cx(0:NH) complex cx(0:NH)
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall(12) common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall(12)
common/foxcom2/itone2(NN),msgbits2(KK) common/foxcom2/itone2(NN),msgbits2(77)
equivalence (x,cx),(y,cy) equivalence (x,cx),(y,cy)
data icos7/2,5,6,0,4,1,3/ !Costas 7x7 tone pattern
fstep=60.d0 fstep=60.d0
dfreq=6.25d0 dfreq=6.25d0
@ -43,50 +38,10 @@ subroutine foxgen()
wave=0. wave=0.
do n=1,nslots do n=1,nslots
i3b=i3bit(n) msg=cmsg(n)(1:37)
if(i3b.eq.0) then call genft8_174_91(msg,i3,n3,msgsent,msgbits,itone)
msg=cmsg(n)(1:22) !Standard FT8 message ! print*,'Foxgen:',n,msg,msgsent,i3,n3
else ! write(*,'(77i1)') msgbits
i1=index(cmsg(n),' ') !Special Fox message
i2=index(cmsg(n),';')
i3=index(cmsg(n),'<')
i4=index(cmsg(n),'>')
msg=cmsg(n)(1:i1)//cmsg(n)(i2+1:i3-2)//' '
read(cmsg(n)(i4+2:i4+4),*) irpt
endif
call genft8(msg,0,1,1,msgsent,msgbits,itone)
! print*,'Foxgen:',n,cmsg(n),msgsent
if(i3b.eq.1) then
icrc10=crc10(c_loc(mycall),12)
nrpt=irpt+30
write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,0
1001 format(56b1.1,b10.10,b6.6,b3.3,b12.12)
read(cbits,1002) msgbits
1002 format(87i1)
cb88=cbits//'0'
read(cb88,1003) i1Msg8BitBytes(1:11)
1003 format(11b8)
icrc12=crc12(c_loc(i1Msg8BitBytes),11)
write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,icrc12
read(cbits,1002) msgbits
call encode174(msgbits,codeword) !Encode the test message
! Message structure: S7 D29 S7 D29 S7
itone(1:7)=icos7
itone(36+1:36+7)=icos7
itone(NN-6:NN)=icos7
k=7
do j=1,ND
i=3*j -2
k=k+1
if(j.eq.30) k=k+7
itone(k)=codeword(i)*4 + codeword(i+1)*2 + codeword(i+2)
enddo
endif
! Make copies of itone() and msgbits() for ft8sim ! Make copies of itone() and msgbits() for ft8sim
itone2=itone itone2=itone

View File

@ -1,6 +1,6 @@
subroutine foxgen_wrap(msg40,msgbits,itone) subroutine foxgen_wrap(msg40,msgbits,itone)
parameter (NN=79,ND=58,KK=87,NSPS=4*1920) parameter (NN=79,ND=58,KK=77,NSPS=4*1920)
parameter (NWAVE=NN*NSPS) parameter (NWAVE=NN*NSPS)
character*40 msg40,cmsg character*40 msg40,cmsg

View File

@ -1,20 +1,43 @@
subroutine ft8apset_174_91(mycall12,hiscall12,hisgrid6,ncontest,apsym) subroutine ft8apset_174_91(mycall12,hiscall12,apsym)
parameter(NAPM=4,KK=91) use packjt77
character*37 msg,msgsent character*77 c77
character*12 mycall12,hiscall12 character*37 msg
character*6 hisgrid6 character*12 mycall12,hiscall12,hiscall
character*4 hisgrid integer apsym(58)
integer apsym(77)
integer*1 msgbits(77) integer*1 msgbits(77)
integer itone(KK) logical nohiscall
if(index(hiscall12," ").eq.0) hiscall12="K9ABC" if(len(trim(mycall12)).eq.0) then
msg=trim(mycall12)//' '//trim(hiscall12)//' RRR' apsym=0
i3=1 apsym(1)=99
n3=0 apsym(30)=99
!write(*,*) 'apset msg ',msg return
call genft8_174_91(msg,i3,n3,msgsent,msgbits,itone) endif
apsym=2*msgbits-1
!write(*,'(29i1,1x,29i1,1x,19i1)') (apsym(1:77)+1)/2 nohiscall=.false.
hiscall=hiscall12
if(len(trim(hiscall)).eq.0) then
hiscall="K9ABC"
nohiscall=.true.
endif
! Encode a dummy standard message: i3=1, 28 1 28 1 1 15
!
msg=trim(mycall12)//' '//trim(hiscall)//' RRR'
call pack77(msg,i3,n3,c77)
if(i3.ne.1) then
apsym=0
apsym(1)=99
apsym(30)=99
return
endif
read(c77,'(58i1)',err=1) apsym(1:58)
if(nohiscall) apsym(30)=99
return
1 apsym=0
apsym(1)=99
apsym(30)=99
return return
end subroutine ft8apset_174_91 end subroutine ft8apset_174_91

View File

@ -1,5 +1,5 @@
subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
napwid,lsubtract,nagain,iaptype,mycall12,hiscall12, & napwid,lsubtract,nagain,ncontest,iaptype,mycall12,hiscall12, &
sync0,f1,xdt,xbase,apsym,nharderrors,dmin,nbadcrc,ipass,iera,msg37,xsnr) sync0,f1,xdt,xbase,apsym,nharderrors,dmin,nbadcrc,ipass,iera,msg37,xsnr)
use crc use crc
@ -16,19 +16,20 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
real a(5) real a(5)
real s8(0:7,NN) real s8(0:7,NN)
real s2(0:511),s2l(0:511) real s2(0:511),s2l(0:511)
real bmeta(3*ND),bmetb(3*ND),bmetc(3*ND) real bmeta(174),bmetb(174),bmetc(174)
real bmetal(3*ND),bmetbl(3*ND),bmetcl(3*ND) real bmetal(174),bmetbl(174),bmetcl(174)
real llra(3*ND),llrb(3*ND),llrc(3*ND),llrd(3*ND) !Soft symbols real llra(174),llrb(174),llrc(174),llrd(174) !Soft symbols
real llral(3*ND),llrbl(3*ND),llrcl(3*ND) !Soft symbols real llral(174),llrbl(174),llrcl(174) !Soft symbols
real dd0(15*12000) real dd0(15*12000)
integer*1 message77(77),apmask(3*ND),cw(3*ND) integer*1 message77(77),apmask(174),cw(174)
integer*1 msgbits(77) integer apsym(58)
integer apsym(77) integer mcq(29),mcqru(29),mcqfd(29),mcqtest(29),mcqhund(29)
integer mcq(29),mrrr(19),m73(19),mrr73(19) integer mrrr(19),m73(19),mrr73(19)
integer itone(NN) integer itone(NN)
integer icos7(0:6),ip(1) integer icos7(0:6),ip(1)
integer nappasses(0:5) !Number of decoding passes to use for each QSO state integer nappasses(0:5) !Number of decoding passes to use for each QSO state
integer naptypes(0:5,4) ! (nQSOProgress, decoding pass) maximum of 4 passes for now integer naptypes(0:5,4) ! (nQSOProgress, decoding pass) maximum of 4 passes for now
integer ncontest,ncontest0
integer*1, target:: i1hiscall(12) integer*1, target:: i1hiscall(12)
logical one(0:511,0:8) logical one(0:511,0:8)
integer graymap(0:7) integer graymap(0:7)
@ -38,16 +39,25 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
complex cs(0:7,NN) complex cs(0:7,NN)
logical first,newdat,lsubtract,lapon,lapcqonly,nagain,unpk77_success logical first,newdat,lsubtract,lapon,lapcqonly,nagain,unpk77_success
data icos7/3,1,4,0,6,5,2/ ! Flipped w.r.t. original FT8 sync array data icos7/3,1,4,0,6,5,2/ ! Flipped w.r.t. original FT8 sync array
data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/
data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ data mcqru/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,0,0/
data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ data mcqfd/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0/
data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/ data mcqtest/0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,1,0,1,1,1,1,1,1,0,0,1,0/
data mcqhund/0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,0,0,1,1,1,0,0/
data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/
data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/
data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/
data first/.true./ data first/.true./
data graymap/0,1,3,2,5,6,4,7/ data graymap/0,1,3,2,5,6,4,7/
save nappasses,naptypes,one,hiscall12_0 save nappasses,naptypes,ncontest0,one,hiscall12_0
if(first) then
if(first.or.(ncontest.ne.ncontest0)) then
mcq=2*mcq-1 mcq=2*mcq-1
mcqfd=2*mcqfd-1
mcqru=2*mcqru-1
mcqtest=2*mcqtest-1
mcqhund=2*mcqhund-1
mrrr=2*mrrr-1 mrrr=2*mrrr-1
m73=2*m73-1 m73=2*m73-1
mrr73=2*mrr73-1 mrr73=2*mrr73-1
@ -67,12 +77,12 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
! 5 MyCall DxCall 73 (77 ap bits) ! 5 MyCall DxCall 73 (77 ap bits)
! 6 MyCall DxCall RR73 (77 ap bits) ! 6 MyCall DxCall RR73 (77 ap bits)
naptypes(0,1:4)=(/1,2,0,0/) naptypes(0,1:4)=(/1,2,0,0/) ! Tx6 selected (CQ)
naptypes(1,1:4)=(/2,3,0,0/) naptypes(1,1:4)=(/2,3,0,0/) ! Tx1
naptypes(2,1:4)=(/2,3,0,0/) naptypes(2,1:4)=(/2,3,0,0/) ! Tx2
naptypes(3,1:4)=(/3,4,5,6/) naptypes(3,1:4)=(/3,4,5,6/) ! Tx3
naptypes(4,1:4)=(/3,4,5,6/) naptypes(4,1:4)=(/3,4,5,6/) ! Tx4
naptypes(5,1:4)=(/3,1,2,0/) naptypes(5,1:4)=(/3,1,2,0/) ! Tx5
one=.false. one=.false.
do i=0,511 do i=0,511
@ -81,6 +91,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
enddo enddo
enddo enddo
first=.false. first=.false.
ncontest0=ncontest
endif endif
if(hiscall12.ne.hiscall12_0) then if(hiscall12.ne.hiscall12_0) then
@ -124,7 +135,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
ctwk(i)=cmplx(cos(phi),sin(phi)) ctwk(i)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dphi,twopi) phi=mod(phi+dphi,twopi)
enddo enddo
call sync8d(cd0,i0,ctwk,1,2,sync) call sync8d(cd0,i0,ctwk,1,2,sync)
if( sync .gt. smax ) then if( sync .gt. smax ) then
smax=sync smax=sync
delfbest=delf delfbest=delf
@ -211,12 +222,12 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
enddo enddo
enddo enddo
enddo enddo
call normalizebmet(bmeta,3*ND) call normalizebmet(bmeta,174)
! call normalizebmet(bmetal,3*ND) ! call normalizebmet(bmetal,174)
call normalizebmet(bmetb,3*ND) call normalizebmet(bmetb,174)
! call normalizebmet(bmetbl,3*ND) ! call normalizebmet(bmetbl,174)
call normalizebmet(bmetc,3*ND) call normalizebmet(bmetc,174)
! call normalizebmet(bmetcl,3*ND) ! call normalizebmet(bmetcl,174)
scalefac=2.83 scalefac=2.83
llra=scalefac*bmeta llra=scalefac*bmeta
@ -226,7 +237,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
llrc=scalefac*bmetc llrc=scalefac*bmetc
! llrcl=scalefac*bmetcl ! llrcl=scalefac*bmetcl
apmag=maxval(abs(llrb))*1.01 apmag=maxval(abs(llra))*1.01
! pass # ! pass #
!------------------------------ !------------------------------
@ -238,7 +249,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
! 6 ap pass 3 ! 6 ap pass 3
! 7 ap pass 4 ! 7 ap pass 4
if(lapon) then if(lapon.or.ncontest.eq.6) then !Hounds always use AP
if(.not.lapcqonly) then if(.not.lapcqonly) then
npasses=3+nappasses(nQSOProgress) npasses=3+nappasses(nQSOProgress)
else else
@ -264,29 +275,117 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
else else
iaptype=1 iaptype=1
endif endif
if(iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle
if(iaptype.eq.1 .or. iaptype.eq.2 ) then ! AP,???,??? ! ncontest=0 : NONE
! 1 : NA_VHF
! 2 : EU_VHF
! 3 : FIELD DAY
! 4 : RTTY
! 5 : FOX
! 6 : HOUND
!
! Conditions that cause us to bail out of AP decoding
if(ncontest.le.4 .and. iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle
if(ncontest.eq.5) cycle ! No AP for Foxes
if(ncontest.eq.6.and.f1.gt.950.0) cycle ! Hounds use AP only for signals below 950 Hz
if(iaptype.ge.2 .and. apsym(1).gt.1) cycle ! No, or nonstandard, mycall
if(iaptype.ge.3 .and. apsym(30).gt.1) cycle ! No, or nonstandard, dxcall
apsym=2*apsym-1 ! Change from [0,1] to antipodal
if(iaptype.eq.1) then ! CQ or CQ RU or CQ TEST or CQ FD
apmask=0 apmask=0
apmask(1:29)=1 apmask(1:29)=1
if(ncontest.eq.0) llrd(1:29)=apmag*mcq(1:29)
if(ncontest.eq.1) llrd(1:29)=apmag*mcqtest(1:29)
if(ncontest.eq.2) llrd(1:29)=apmag*mcqtest(1:29)
if(ncontest.eq.3) llrd(1:29)=apmag*mcqfd(1:29)
if(ncontest.eq.4) llrd(1:29)=apmag*mcqru(1:29)
if(ncontest.eq.6) llrd(1:29)=apmag*mcqhund(1:29)
apmask(75:77)=1 apmask(75:77)=1
llrd(75:77)=apmag*apsym(75:77) llrd(75:76)=apmag*(-1)
if(iaptype.eq.1) llrd(1:29)=apmag*mcq(1:29) llrd(77)=apmag*(+1)
if(iaptype.eq.2) llrd(1:29)=apmag*apsym(1:29)
endif endif
if(iaptype.eq.3) then ! mycall, dxcall, ???
if(iaptype.eq.2) then ! MyCall,???,???
apmask=0 apmask=0
apmask(1:56)=1 if(ncontest.eq.0.or.ncontest.eq.1) then
apmask(75:77)=1 apmask(1:29)=1
llrd(1:56)=apmag*apsym(1:56) llrd(1:29)=apmag*apsym(1:29)
llrd(75:77)=apmag*apsym(75:77) apmask(75:77)=1
llrd(75:76)=apmag*(-1)
llrd(77)=apmag*(+1)
else if(ncontest.eq.2) then
apmask(1:28)=1
llrd(1:28)=apmag*apsym(1:28)
apmask(72:74)=1
llrd(72)=apmag*(-1)
llrd(73)=apmag*(+1)
llrd(74)=apmag*(-1)
apmask(75:77)=1
llrd(75:77)=apmag*(-1)
else if(ncontest.eq.3) then
apmask(1:28)=1
llrd(1:28)=apmag*apsym(1:28)
apmask(75:77)=1
llrd(75:77)=apmag*(-1)
else if(ncontest.eq.4) then
apmask(2:29)=1
llrd(2:29)=apmag*apsym(1:28)
apmask(75:77)=1
llrd(75)=apmag*(-1)
llrd(76:77)=apmag*(+1)
else if(ncontest.eq.6) then ! ??? RR73; MyCall <???> ???
apmask(29:56)=1
llrd(29:56)=apmag*apsym(1:28)
apmask(72:77)=1
llrd(72:73)=apmag*(-1)
llrd(74)=apmag*(+1)
llrd(75:77)=apmag*(-1)
endif
endif endif
if(iaptype.eq.3) then ! MyCall,DxCall,???
apmask=0
if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2.or.ncontest.eq.6) then
apmask(1:58)=1
llrd(1:58)=apmag*apsym
apmask(75:77)=1
llrd(75:76)=apmag*(-1)
llrd(77)=apmag*(+1)
else if(ncontest.eq.3) then ! Field Day
apmask(1:56)=1
llrd(1:28)=apmag*apsym(1:28)
llrd(29:56)=apmag*apsym(30:57)
apmask(72:74)=1
apmask(75:77)=1
llrd(75:77)=apmag*(-1)
else if(ncontest.eq.4) then ! RTTY RU
apmask(2:57)=1
llrd(2:29)=apmag*apsym(1:28)
llrd(30:57)=apmag*apsym(30:57)
apmask(75:77)=1
llrd(75)=apmag*(-1)
llrd(76:77)=apmag*(+1)
endif
endif
if(iaptype.eq.5.and.ncontest.eq.6) cycle !Hound
if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then
apmask=0 apmask=0
apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73 if(ncontest.le.4 .or. (ncontest.eq.6.and.iaptype.eq.6)) then
llrd(1:58)=apmag*apsym(1:58) apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73
if(iaptype.eq.4) llrd(59:77)=apmag*mrrr llrd(1:58)=apmag*apsym
if(iaptype.eq.5) llrd(59:77)=apmag*m73 if(iaptype.eq.4) llrd(59:77)=apmag*mrrr
if(iaptype.eq.6) llrd(59:77)=apmag*mrr73 if(iaptype.eq.5) llrd(59:77)=apmag*m73
if(iaptype.eq.6) llrd(59:77)=apmag*mrr73
else if(ncontest.eq.6.and.iaptype.eq.4) then ! Hound listens for MyCall RR73;...
apmask(1:28)=1
llrd(1:28)=apmag*apsym(1:28)
apmask(72:77)=1
llrd(72:73)=apmag*(-1)
llrd(74)=apmag*(1)
llrd(75:77)=apmag*(-1)
endif
endif endif
endif endif
@ -299,11 +398,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
if(ndepth.eq.3 .and. nharderrors.lt.0) then if(ndepth.eq.3 .and. nharderrors.lt.0) then
ndeep=3 ndeep=3
if(abs(nfqso-f1).le.napwid .or. abs(nftx-f1).le.napwid) then if(abs(nfqso-f1).le.napwid .or. abs(nftx-f1).le.napwid) then
if((ipass.eq.3 .or. ipass.eq.4) .and. .not.nagain) then ndeep=4
ndeep=3
else
ndeep=4
endif
endif endif
if(nagain) ndeep=5 if(nagain) ndeep=5
call timer('osd174_91 ',0) call timer('osd174_91 ',0)
@ -312,7 +407,6 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
endif endif
msg37=' ' msg37=' '
xsnr=-99.0
if(nharderrors.lt.0 .or. nharderrors.gt.36) cycle if(nharderrors.lt.0 .or. nharderrors.gt.36) cycle
if(count(cw.eq.0).eq.174) cycle !Reject the all-zero codeword if(count(cw.eq.0).eq.174) cycle !Reject the all-zero codeword
write(c77,'(77i1)') message77 write(c77,'(77i1)') message77
@ -326,7 +420,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
cycle cycle
endif endif
nbadcrc=0 ! If we get this far: valid codeword, valid (i3,n3), nonquirky message. nbadcrc=0 ! If we get this far: valid codeword, valid (i3,n3), nonquirky message.
call genft8_174_91(msg37,i3,n3,msgsent37,msgbits,itone) call get_tones_from_77bits(message77,itone)
if(lsubtract) call subtractft8(dd0,itone,f1,xdt) if(lsubtract) call subtractft8(dd0,itone,f1,xdt)
xsig=0.0 xsig=0.0
xnoi=0.0 xnoi=0.0
@ -336,13 +430,16 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
xnoi=xnoi+s8(ios,i)**2 xnoi=xnoi+s8(ios,i)**2
enddo enddo
xsnr=0.001 xsnr=0.001
if(xnoi.gt.0 .and. xnoi.lt.xsig) xsnr=xsig/xnoi-1.0 xsnr2=0.001
arg=xsig/xnoi-1.0
if(arg.gt.0.1) xsnr=arg
arg=xsig/xbase/2.6e6-1.0
if(arg.gt.0.1) xsnr2=arg
xsnr=10.0*log10(xsnr)-27.0 xsnr=10.0*log10(xsnr)-27.0
xbase=10**(xbase/10.0) xsnr2=10.0*log10(xsnr2)-27.0
! factor=xnoi/xbase if(.not.nagain) then
factor=3.6e6 xsnr=xsnr2
xsnr2=10*log10(xsig/xbase/factor-1.0)-27.0 endif
! if(.not.nagain) xsnr=xsnr2
if(xsnr .lt. -24.0) xsnr=-24.0 if(xsnr .lt. -24.0) xsnr=-24.0
return return

View File

@ -18,10 +18,12 @@ subroutine genft8_174_91(msg,i3,n3,msgsent,msgbits,itone)
n3=-1 n3=-1
call pack77(msg,i3,n3,c77) call pack77(msg,i3,n3,c77)
call unpack77(c77,msgsent,unpk77_success) call unpack77(c77,msgsent,unpk77_success)
read(c77,'(77i1)',err=1) msgbits read(c77,'(77i1)',err=1) msgbits
go to 2 go to 2
1 write(81,*) msg,c77 ; flush(81) 1 write(81,*) msg,c77 ; flush(81)
entry get_tones_from_77bits(msgbits,itone)
2 call encode174_91(msgbits,codeword) !Encode the test message 2 call encode174_91(msgbits,codeword) !Encode the test message
! Message structure: S7 D29 S7 D29 S7 ! Message structure: S7 D29 S7 D29 S7

View File

@ -52,7 +52,7 @@ contains
character*12 mycall12,hiscall12,mycall12_0 character*12 mycall12,hiscall12,mycall12_0
character*6 hisgrid6 character*6 hisgrid6
integer*2 iwave(15*12000) integer*2 iwave(15*12000)
integer apsym1(KK),apsym2(77) integer apsym1(KK),apsym2(58)
character datetime*13,msg37*37 character datetime*13,msg37*37
! character message*22 ! character message*22
character*37 allmessages(100) character*37 allmessages(100)
@ -70,7 +70,7 @@ contains
1001 format("000000_",i6.6) 1001 format("000000_",i6.6)
call ft8apset(mycall12,hiscall12,apsym1) call ft8apset(mycall12,hiscall12,apsym1)
call ft8apset_174_91(mycall12,hiscall12,hisgrid6,ncontest,apsym2) call ft8apset_174_91(mycall12,hiscall12,apsym2)
dd=iwave dd=iwave
ndecodes=0 ndecodes=0
allmessages=' ' allmessages=' '
@ -121,7 +121,7 @@ contains
nbadcrc,iappass,iera,msg37,xsnr) nbadcrc,iappass,iera,msg37,xsnr)
else else
call ft8b_2(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lft8apon, & call ft8b_2(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lft8apon, &
lapcqonly,napwid,lsubtract,nagain,iaptype,mycall12, & lapcqonly,napwid,lsubtract,nagain,ncontest,iaptype,mycall12, &
hiscall12,sync,f1,xdt,xbase,apsym2,nharderrors,dmin, & hiscall12,sync,f1,xdt,xbase,apsym2,nharderrors,dmin, &
nbadcrc,iappass,iera,msg37,xsnr) nbadcrc,iappass,iera,msg37,xsnr)
endif endif
@ -131,9 +131,6 @@ contains
hd=nharderrors+dmin hd=nharderrors+dmin
call timer('ft8b ',1) call timer('ft8b ',1)
if(nbadcrc.eq.0) then if(nbadcrc.eq.0) then
! call jtmsg(message,iflag)
! This probably needs to be re-visited for the new message type
! if(iand(iflag,31).ne.0) message(22:22)='?'
ldupe=.false. ldupe=.false.
do id=1,ndecodes do id=1,ndecodes
if(msg37.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true. if(msg37.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true.
@ -143,11 +140,11 @@ contains
allmessages(ndecodes)=msg37 allmessages(ndecodes)=msg37
allsnrs(ndecodes)=nsnr allsnrs(ndecodes)=nsnr
endif endif
! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, & write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
! nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), & nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
! xdt,nint(f1),msg37,isync xdt,nint(f1),msg37,isync
!1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a37,i4) 1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a37,i4)
! flush(81) flush(81)
if(.not.ldupe .and. associated(this%callback)) then if(.not.ldupe .and. associated(this%callback)) then
qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0] qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0]
call this%callback(sync,nsnr,xdt,f1,msg37,iaptype,qual) call this%callback(sync,nsnr,xdt,f1,msg37,iaptype,qual)

View File

@ -29,7 +29,7 @@ subroutine genmsk40(msg,msgsent,ichk,itone,itype)
10 irpt=i !Report index, 0-15 10 irpt=i !Report index, 0-15
if(ichk.lt.10000) then if(ichk.lt.10000) then
hashmsg=msg(2:i1-1) hashmsg=msg(2:i1-1)
call hash(hashmsg,22,ihash) call hash(hashmsg,37,ihash)
ihash=iand(ihash,4095) !12-bit hash ihash=iand(ihash,4095) !12-bit hash
ig=16*ihash + irpt !4-bit report ig=16*ihash + irpt !4-bit report
else else

View File

@ -46,6 +46,7 @@ subroutine genmsk_128_90(msg0,ichk,msgsent,i4tone,itype)
enddo enddo
endif endif
message(1:37)=' '
itype=1 itype=1
if(msg0(1:1).eq.'@') then !Generate a fixed tone if(msg0(1:1).eq.'@') then !Generate a fixed tone
read(msg0(2:5),*,end=1,err=1) nfreq !at specified frequency read(msg0(2:5),*,end=1,err=1) nfreq !at specified frequency
@ -54,23 +55,28 @@ subroutine genmsk_128_90(msg0,ichk,msgsent,i4tone,itype)
2 i4tone(1)=nfreq 2 i4tone(1)=nfreq
else else
message=msg0 message=msg0
do i=1, 37 do i=1, 37
if(ichar(message(i:i)).eq.0) then if(ichar(message(i:i)).eq.0) then
message(i:)=' ' message(i:37)=' '
exit exit
endif endif
enddo enddo
do i=1,37 !Strip leading blanks do i=1,37 !Strip leading blanks
if(message(1:1).ne.' ') exit if(message(1:1).ne.' ') exit
message=message(i+1:) message=message(i+1:)
enddo enddo
if(message(1:1).eq.'<') then if(message(1:1).eq.'<') then
call genmsk40(message,msgsent,ichk,i4tone,itype) i2=index(message,'>')
if(itype.lt.0) go to 999 i1=0
i4tone(41)=-40 if(i2.gt.0) i1=index(message(1:i2),' ')
go to 999 if(i1.gt.0) then
call genmsk40(message,msgsent,ichk,i4tone,itype)
if(itype.lt.0) go to 999
i4tone(41)=-40
go to 999
endif
endif endif
i3=-1 i3=-1

View File

@ -5,8 +5,8 @@ subroutine msk40decodeframe(c,mycall,hiscall,xsnr,bswl,nhasharray, &
parameter (NSPM=240) parameter (NSPM=240)
character*4 rpt(0:15) character*4 rpt(0:15)
character*6 mycall,hiscall,mycall0,hiscall0 character*12 mycall,hiscall,mycall0,hiscall0
character*22 hashmsg,msgreceived character*37 hashmsg,msgreceived
complex cb(42) complex cb(42)
complex cfac,cca complex cfac,cca
complex c(NSPM) complex c(NSPM)
@ -59,7 +59,7 @@ subroutine msk40decodeframe(c,mycall,hiscall,xsnr,bswl,nhasharray, &
hashmsg=trim(mycall)//' '//trim(hiscall) hashmsg=trim(mycall)//' '//trim(hiscall)
if( hashmsg .ne. ' ' .and. hiscall .ne. '' ) then ! protect against blank mycall/hiscall if( hashmsg .ne. ' ' .and. hiscall .ne. '' ) then ! protect against blank mycall/hiscall
call fmtmsg(hashmsg,iz) call fmtmsg(hashmsg,iz)
call hash(hashmsg,22,ihash) call hash(hashmsg,37,ihash)
ihash=iand(ihash,4095) ihash=iand(ihash,4095)
else else
ihash=9999 ! so that it can never match a received hash ihash=9999 ! so that it can never match a received hash

View File

@ -6,8 +6,8 @@ subroutine msk40spd(cbig,n,ntol,mycall,hiscall,bswl,nhasharray, &
use timer_module, only: timer use timer_module, only: timer
parameter (NSPM=240, MAXSTEPS=150, NFFT=NSPM, MAXCAND=5, NPATTERNS=6) parameter (NSPM=240, MAXSTEPS=150, NFFT=NSPM, MAXCAND=5, NPATTERNS=6)
character*6 mycall,hiscall character*12 mycall,hiscall
character*22 msgreceived character*37 msgreceived
complex cbig(n) complex cbig(n)
complex cdat(3*NSPM) !Analytic signal complex cdat(3*NSPM) !Analytic signal
complex c(NSPM) complex c(NSPM)

View File

@ -15,10 +15,10 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
character*4 decsym !"&" for mskspd or "^" for long averages character*4 decsym !"&" for mskspd or "^" for long averages
character*37 msgreceived !Decoded message character*37 msgreceived !Decoded message
character*22 msgrx22 !Sh messages are returned as 22chars character*37 msglast,msglastswl !Used for dupechecking
character*37 msglast,msglastswl !Used for dupechecking
character*80 line !Formatted line with UTC dB T Freq Msg character*80 line !Formatted line with UTC dB T Freq Msg
character*12 mycall,hiscall character*12 mycall,hiscall
character*13 mycall13
character*6 mygrid character*6 mygrid
character*37 recent_shmsgs(NSHMEM) character*37 recent_shmsgs(NSHMEM)
character*512 datadir character*512 datadir
@ -55,7 +55,7 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
1,1,1,1,1,1,1,0/ 1,1,1,1,1,1,1,0/
data xmc/2.0,4.5,2.5,3.5/ !Used to set time at center of averaging mask data xmc/2.0,4.5,2.5,3.5/ !Used to set time at center of averaging mask
save first,tsec0,nutc00,pnoise,cdat,msglast,msglastswl, & save first,tsec0,nutc00,pnoise,cdat,msglast,msglastswl, &
nsnrlast,nsnrlastswl,nhasharray,recent_shmsgs nsnrlast,nsnrlastswl,nhasharray,recent_shmsgs,mycall13
if(first) then if(first) then
tsec0=tsec tsec0=tsec
@ -71,11 +71,16 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
msglastswl=' ' msglastswl=' '
nsnrlast=-99 nsnrlast=-99
nsnrlastswl=-99 nsnrlastswl=-99
mycall13=mycall//" "
call save_hash_call(mycall13,n10,n12,n22) ! Make sure that my callsign is in hashtable
first=.false. first=.false.
endif endif
fc=nrxfreq fc=nrxfreq
! Reset if mycall changes
if(mycall13(1:12).ne.mycall) first=.true.
! Dupe checking setup ! Dupe checking setup
if(nutc00.ne.nutc0 .or. tsec.lt.tsec0) then ! reset dupe checker if(nutc00.ne.nutc0 .or. tsec.lt.tsec0) then ! reset dupe checker
msglast=' ' msglast=' '
@ -119,9 +124,8 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
call msk144spd(cdat,np,ntol,ndecodesuccess,msgreceived,fc,fest,tdec,navg,ct, & call msk144spd(cdat,np,ntol,ndecodesuccess,msgreceived,fc,fest,tdec,navg,ct, &
softbits) softbits)
if(ndecodesuccess.eq.0 .and. (bshmsg.or.bswl)) then if(ndecodesuccess.eq.0 .and. (bshmsg.or.bswl)) then
call msk40spd(cdat,np,ntol,mycall(1:6),hiscall(1:6),bswl,nhasharray, & call msk40spd(cdat,np,ntol,mycall,hiscall,bswl,nhasharray, &
ndecodesuccess,msgrx22,fc,fest,tdec,navg) ndecodesuccess,msgreceived,fc,fest,tdec,navg)
if( ndecodesuccess .ge. 1 ) msgreceived(1:22)=msgrx22
endif endif
if( ndecodesuccess .ge. 1 ) then if( ndecodesuccess .ge. 1 ) then
tdec=tsec+tdec tdec=tsec+tdec
@ -184,7 +188,12 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
nsnr=nint(snr0) nsnr=nint(snr0)
bshdecode=.false. bshdecode=.false.
if( msgreceived(1:1) .eq. '<' ) bshdecode=.true. if( msgreceived(1:1) .eq. '<' ) then
i2=index(msgreceived,'>')
i1=0
if(i2.gt.0) i1=index(msgreceived(1:i2),' ')
if(i1.gt.0) bshdecode=.true.
endif
if(.not. bshdecode) then if(.not. bshdecode) then
call msk144signalquality(ct,snr0,fest,tdec,softbits,msgreceived,hiscall, & call msk144signalquality(ct,snr0,fest,tdec,softbits,msgreceived,hiscall, &
@ -210,15 +219,17 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
if(.not. bshdecode) then if(.not. bshdecode) then
call update_hasharray(nhasharray) call update_hasharray(nhasharray)
endif endif
if( .not.bshdecode ) then write(line,1021) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived,char(0)
write(line,1020) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived(1:22), & 1021 format(i6.6,i4,f5.1,i5,a4,a37,a1)
navg,ncorrected,eyeopening,char(0) ! if( .not.bshdecode ) then
1020 format(i6.6,i4,f5.1,i5,a4,a22,i2,i3,f5.1,a1) ! write(line,1020) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived(1:22), &
else ! navg,ncorrected,eyeopening,char(0)
write(line,1022) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived(1:22), & !1020 format(i6.6,i4,f5.1,i5,a4,a22,i2,i3,f5.1,a1)
navg,char(0) ! else
1022 format(i6.6,i4,f5.1,i5,a4,a22,i2,a1) ! write(line,1022) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived(1:22), &
endif ! navg,char(0)
!1022 format(i6.6,i4,f5.1,i5,a4,a22,i2,a1)
! endif
elseif(bswl .and. ndecodesuccess.ge.2) then elseif(bswl .and. ndecodesuccess.ge.2) then
seenb4=.false. seenb4=.false.
do i=1,nshmem do i=1,nshmem
@ -233,8 +244,9 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
if(bflag) then if(bflag) then
msglastswl=msgreceived msglastswl=msgreceived
nsnrlastswl=nsnr nsnrlastswl=nsnr
write(line,1022) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived, & write(line,1021) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived,char(0)
navg,char(0) ! write(line,1022) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived, &
! navg,char(0)
endif endif
endif endif
999 tsec0=tsec 999 tsec0=tsec

View File

@ -29,7 +29,7 @@ subroutine sync4(dat,jz,ntol,nfqso,mode,mode4,minwidth,dtx,dfx,snrx, &
df=0.5*11025.0/nfft df=0.5*11025.0/nfft
ftop=nfqso + 7*mode4*df ftop=nfqso + 7*mode4*df
if(ftop.gt.11025.0/4.0) then if(ftop.gt.11025.0/4.0) then
print*,'*** Rx Freq is set too high for this sybmode ***' print*,'*** Rx Freq is set too high for this submode ***'
go to 900 go to 900
endif endif

View File

@ -1,7 +1,7 @@
subroutine update_hasharray(nhasharray) subroutine update_hasharray(nhasharray)
use packjt77 use packjt77
character*22 hashmsg character*37 hashmsg
integer nhasharray(MAXRECENT,MAXRECENT) integer nhasharray(MAXRECENT,MAXRECENT)
nhasharray=-1 nhasharray=-1
@ -10,12 +10,12 @@ subroutine update_hasharray(nhasharray)
if( recent_calls(i)(1:1) .ne. ' ' .and. recent_calls(j)(1:1) .ne. ' ' ) then if( recent_calls(i)(1:1) .ne. ' ' .and. recent_calls(j)(1:1) .ne. ' ' ) then
hashmsg=trim(recent_calls(i))//' '//trim(recent_calls(j)) hashmsg=trim(recent_calls(i))//' '//trim(recent_calls(j))
call fmtmsg(hashmsg,iz) call fmtmsg(hashmsg,iz)
call hash(hashmsg,22,ihash) call hash(hashmsg,37,ihash)
ihash=iand(ihash,4095) ihash=iand(ihash,4095)
nhasharray(i,j)=ihash nhasharray(i,j)=ihash
hashmsg=trim(recent_calls(j))//' '//trim(recent_calls(i)) hashmsg=trim(recent_calls(j))//' '//trim(recent_calls(i))
call fmtmsg(hashmsg,iz) call fmtmsg(hashmsg,iz)
call hash(hashmsg,22,ihash) call hash(hashmsg,37,ihash)
ihash=iand(ihash,4095) ihash=iand(ihash,4095)
nhasharray(j,i)=ihash nhasharray(j,i)=ihash
endif endif

View File

@ -115,7 +115,7 @@ void ADIF::add(QString const& call, QString const& grid, QString const& band,
{ {
QSO q; QSO q;
q.call = call; q.call = call;
q.grid = grid; q.grid = grid.left(4); //We only want to test matches to 4-character grids.
q.band = band; q.band = band;
q.mode = mode; q.mode = mode;
q.date = date; q.date = date;
@ -180,11 +180,12 @@ int ADIF::getCount() const
return _data.size(); return _data.size();
} }
QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode,
, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
, QDateTime const& dateTimeOff, QString const& band, QString const& comments QDateTime const& dateTimeOff, QString const& band, QString const& comments,
, QString const& name, QString const& strDialFreq, QString const& m_myCall QString const& name, QString const& strDialFreq, QString const& m_myCall,
, QString const& m_myGrid, QString const& m_txPower, QString const& operator_call) QString const& m_myGrid, QString const& m_txPower, QString const& operator_call,
QString const& xSent, QString const& xRcvd)
{ {
QString t; QString t;
t = "<call:" + QString::number(hisCall.length()) + ">" + hisCall; t = "<call:" + QString::number(hisCall.length()) + ">" + hisCall;
@ -198,26 +199,24 @@ QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QStri
t += " <time_off:6>" + dateTimeOff.time().toString("hhmmss"); t += " <time_off:6>" + dateTimeOff.time().toString("hhmmss");
t += " <band:" + QString::number(band.length()) + ">" + band; t += " <band:" + QString::number(band.length()) + ">" + band;
t += " <freq:" + QString::number(strDialFreq.length()) + ">" + strDialFreq; t += " <freq:" + QString::number(strDialFreq.length()) + ">" + strDialFreq;
t += " <station_callsign:" + QString::number(m_myCall.length()) + ">" + t += " <station_callsign:" + QString::number(m_myCall.length()) + ">" + m_myCall;
m_myCall; t += " <my_gridsquare:" + QString::number(m_myGrid.length()) + ">" + m_myGrid;
t += " <my_gridsquare:" + QString::number(m_myGrid.length()) + ">" + if(m_txPower!="") t += " <tx_pwr:" + QString::number(m_txPower.length()) + ">" + m_txPower;
m_myGrid; if(comments!="") t += " <comment:" + QString::number(comments.length()) + ">" + comments;
if (m_txPower != "") if(name!="") t += " <name:" + QString::number(name.length()) + ">" + name;
t += " <tx_pwr:" + QString::number(m_txPower.length()) + if(operator_call!="") t+=" <operator:" + QString::number(operator_call.length()) + ">" + operator_call;
">" + m_txPower; if(xRcvd!="") {
if (comments != "") QString t1="";
t += " <comment:" + QString::number(comments.length()) + if(xRcvd.split(" ").size()==2) t1=xRcvd.split(" ").at(1);
">" + comments; if(t1.toInt()>0) {
if (name != "") t += " <SRX:" + QString::number(t1.length()) + ">" + t1;
t += " <name:" + QString::number(name.length()) + } else {
">" + name; t += " <STATE:" + QString::number(t1.length()) + ">" + t1;
if (operator_call!="") }
t+=" <operator:" + QString::number(operator_call.length()) + }
">" + operator_call; return t.toLatin1();
return t.toLatin1 ();
} }
// open ADIF file and append the QSO details. Return true on success // open ADIF file and append the QSO details. Return true on success
bool ADIF::addQSOToFile(QByteArray const& ADIF_record) bool ADIF::addQSOToFile(QByteArray const& ADIF_record)
{ {

View File

@ -33,11 +33,12 @@ class ADIF
// open ADIF file and append the QSO details. Return true on success // open ADIF file and append the QSO details. Return true on success
bool addQSOToFile(QByteArray const& ADIF_record); bool addQSOToFile(QByteArray const& ADIF_record);
QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode,
, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
, QString const& band, QString const& comments, QString const& name QDateTime const& dateTimeOff, QString const& band, QString const& comments,
, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid QString const& name, QString const& strDialFreq, QString const& m_myCall,
, QString const& m_txPower, QString const& operator_call); QString const& m_myGrid, QString const& m_txPower, QString const& operator_call,
QString const& xSent, QString const& xRcvd);
private: private:
struct QSO struct QSO

View File

@ -59,9 +59,14 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
QString const& rptSent, QString const& rptRcvd, QString const& rptSent, QString const& rptRcvd,
QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff,
Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid, Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid,
bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, QString const& opCall) bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox,
bool bAutoLog, QString const& opCall, qint32 nContest,
QString xSent, QString xRcvd)
{ {
if(!isHidden()) return; if(!isHidden()) return;
m_nContest=nContest;
m_xSent=xSent;
m_xRcvd=xRcvd;
ui->call->setText(hisCall); ui->call->setText(hisCall);
ui->grid->setText(hisGrid); ui->grid->setText(hisGrid);
ui->name->setText(""); ui->name->setText("");
@ -87,7 +92,9 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
m_myGrid=myGrid; m_myGrid=myGrid;
ui->band->setText (m_config->bands ()->find (dialFreq)); ui->band->setText (m_config->bands ()->find (dialFreq));
ui->loggedOperator->setText(opCall); ui->loggedOperator->setText(opCall);
if(bFox) { ui->exchSent->setText(m_xSent);
ui->exchRcvd->setText(m_xRcvd);
if(bFox or bAutoLog) {
accept(); accept();
} else { } else {
show (); show ();
@ -114,13 +121,14 @@ void LogQSO::accept()
QString strDialFreq(QString::number(m_dialFreq / 1.e6,'f',6)); QString strDialFreq(QString::number(m_dialFreq / 1.e6,'f',6));
operator_call = ui->loggedOperator->text(); operator_call = ui->loggedOperator->text();
//Log this QSO to ADIF file "wsjtx_log.adi" //Log this QSO to ADIF file "wsjtx_log.adi"
QString filename = "wsjtx_log.adi"; // TODO allow user to set QString filename = "wsjtx_log.adi"; // TODO allow user to set
ADIF adifile; ADIF adifile;
auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx_log.adi"); auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx_log.adi");
adifile.init(adifilePath); adifile.init(adifilePath);
QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, rptSent, rptRcvd, m_dateTimeOn, m_dateTimeOff, band QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, rptSent, rptRcvd,
, comments, name, strDialFreq, m_myCall, m_myGrid, m_txPower, operator_call)}; m_dateTimeOn, m_dateTimeOff, band, comments, name, strDialFreq, m_myCall,
m_myGrid, m_txPower, operator_call, m_xSent, m_xRcvd)};
if (!adifile.addQSOToFile (ADIF)) if (!adifile.addQSOToFile (ADIF))
{ {
MessageBox::warning_message (this, tr ("Log file error"), MessageBox::warning_message (this, tr ("Log file error"),

View File

@ -33,7 +33,9 @@ public:
QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
QDateTime const& dateTimeOff, QDateTime const& dateTimeOff,
Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid, Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid,
bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, QString const& opCall); bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox,
bool bAutoLog, QString const& opCall, qint32 nContest, QString xSent,
QString xRcvd);
public slots: public slots:
void accept(); void accept();
@ -61,6 +63,9 @@ private:
Radio::Frequency m_dialFreq; Radio::Frequency m_dialFreq;
QString m_myCall; QString m_myCall;
QString m_myGrid; QString m_myGrid;
QString m_xSent;
QString m_xRcvd;
qint32 m_nContest;
QDateTime m_dateTimeOn; QDateTime m_dateTimeOn;
QDateTime m_dateTimeOff; QDateTime m_dateTimeOff;
}; };

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>377</width> <width>377</width>
<height>257</height> <height>287</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -16,7 +16,7 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_11"> <layout class="QVBoxLayout" name="verticalLayout_5">
<item> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="font"> <property name="font">
@ -390,6 +390,57 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Exch sent</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="exchSent">
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Rcvd</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="exchRcvd">
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
@ -397,7 +448,7 @@
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>0</width> <width>20</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>

View File

@ -17,13 +17,10 @@
#include <QStandardPaths> #include <QStandardPaths>
#include <QStringList> #include <QStringList>
#include <QLockFile> #include <QLockFile>
#include <QStack>
#include <QSplashScreen> #include <QSplashScreen>
#if QT_VERSION >= 0x050200
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QCommandLineOption> #include <QCommandLineOption>
#endif
#include "revision_utils.hpp" #include "revision_utils.hpp"
#include "MetaDataRegistry.hpp" #include "MetaDataRegistry.hpp"
@ -54,38 +51,12 @@ namespace
qsrand (seed); // this is good for rand() as well qsrand (seed); // this is good for rand() as well
} }
} seeding; } seeding;
class MessageTimestamper
{
public:
MessageTimestamper ()
{
prior_handlers_.push (qInstallMessageHandler (message_handler));
}
~MessageTimestamper ()
{
if (prior_handlers_.size ()) qInstallMessageHandler (prior_handlers_.pop ());
}
private:
static void message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg)
{
QtMessageHandler handler {prior_handlers_.top ()};
if (handler)
{
handler (type, context,
QDateTime::currentDateTimeUtc ().toString ("yy-MM-ddTHH:mm:ss.zzzZ: ") + msg);
}
}
static QStack<QtMessageHandler> prior_handlers_;
};
QStack<QtMessageHandler> MessageTimestamper::prior_handlers_;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// Add timestamps to all debug messages // Add timestamps to all debug messages
MessageTimestamper message_timestamper; qSetMessagePattern ("[%{time yyyyMMdd HH:mm:ss.zzz t} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{message}");
init_random_seed (); init_random_seed ();
@ -108,7 +79,6 @@ int main(int argc, char *argv[])
a.setApplicationName ("WSJT-X"); a.setApplicationName ("WSJT-X");
a.setApplicationVersion (version ()); a.setApplicationVersion (version ());
#if QT_VERSION >= 0x050200
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription ("\n" PROJECT_SUMMARY_DESCRIPTION); parser.setApplicationDescription ("\n" PROJECT_SUMMARY_DESCRIPTION);
auto help_option = parser.addHelpOption (); auto help_option = parser.addHelpOption ();
@ -210,11 +180,11 @@ int main(int argc, char *argv[])
} }
} }
} }
#endif
#if WSJT_QDEBUG_TO_FILE #if WSJT_QDEBUG_TO_FILE
// Open a trace file // Open a trace file
TraceFile trace_file {temp_dir.absoluteFilePath (a.applicationName () + "_trace.log")}; TraceFile trace_file {temp_dir.absoluteFilePath (a.applicationName () + "_trace.log")};
qSetMessagePattern ("[%{time yyyyMMdd HH:mm:ss.zzz t} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}");
qDebug () << program_title (revision ()) + " - Program startup"; qDebug () << program_title (revision ()) + " - Program startup";
#endif #endif

View File

@ -58,7 +58,9 @@
#include "MultiSettings.hpp" #include "MultiSettings.hpp"
#include "MaidenheadLocatorValidator.hpp" #include "MaidenheadLocatorValidator.hpp"
#include "CallsignValidator.hpp" #include "CallsignValidator.hpp"
#include "ExchangeValidator.hpp"
#include "EqualizationToolsDialog.hpp" #include "EqualizationToolsDialog.hpp"
#include "LotWUsers.hpp"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "moc_mainwindow.cpp" #include "moc_mainwindow.cpp"
@ -162,7 +164,6 @@ int fast_jhpeak {0};
int fast_jh2 {0}; int fast_jh2 {0};
int narg[15]; int narg[15];
QVector<QColor> g_ColorTbl; QVector<QColor> g_ColorTbl;
QHash<QString,int> m_LoTW;
namespace namespace
{ {
@ -203,7 +204,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_configurations_button {0}, m_configurations_button {0},
m_settings {multi_settings->settings ()}, m_settings {multi_settings->settings ()},
ui(new Ui::MainWindow), ui(new Ui::MainWindow),
m_config {temp_directory, m_settings, this}, m_config {&m_network_manager, temp_directory, m_settings, this},
m_WSPR_band_hopping {m_settings, &m_config, this}, m_WSPR_band_hopping {m_settings, &m_config, this},
m_WSPR_tx_next {false}, m_WSPR_tx_next {false},
m_rigErrorMessageBox {MessageBox::Critical, tr ("Rig Control Error") m_rigErrorMessageBox {MessageBox::Critical, tr ("Rig Control Error")
@ -386,6 +387,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
ui->dxGridEntry->setValidator (new MaidenheadLocatorValidator {this}); ui->dxGridEntry->setValidator (new MaidenheadLocatorValidator {this});
ui->dxCallEntry->setValidator (new CallsignValidator {this}); ui->dxCallEntry->setValidator (new CallsignValidator {this});
ui->sbTR->values ({5, 10, 15, 30}); ui->sbTR->values ({5, 10, 15, 30});
ui->decodedTextBrowser->set_configuration (&m_config);
ui->decodedTextBrowser2->set_configuration (&m_config);
m_baseCall = Radio::base_callsign (m_config.my_callsign ()); m_baseCall = Radio::base_callsign (m_config.my_callsign ());
m_opCall = m_config.opCall(); m_opCall = m_config.opCall();
@ -555,6 +558,10 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_equalizationToolsDialog->show (); m_equalizationToolsDialog->show ();
}); });
connect (&m_config.lotw_users (), &LotWUsers::LotW_users_error, this, [this] (QString const& reason) {
MessageBox::warning_message (this, tr ("Error Loading LotW Users Data"), reason);
}, Qt::QueuedConnection);
QButtonGroup* txMsgButtonGroup = new QButtonGroup {this}; QButtonGroup* txMsgButtonGroup = new QButtonGroup {this};
txMsgButtonGroup->addButton(ui->txrb1,1); txMsgButtonGroup->addButton(ui->txrb1,1);
txMsgButtonGroup->addButton(ui->txrb2,2); txMsgButtonGroup->addButton(ui->txrb2,2);
@ -721,6 +728,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_msg[0][0]=0; m_msg[0][0]=0;
ui->labDXped->setVisible(false); ui->labDXped->setVisible(false);
ui->labDXped->setStyleSheet("QLabel {background-color: red; color: white;}"); ui->labDXped->setStyleSheet("QLabel {background-color: red; color: white;}");
ui->labNextCall->setText("");
ui->labNextCall->setVisible(false);
for(int i=0; i<28; i++) { //Initialize dBm values for(int i=0; i<28; i++) { //Initialize dBm values
float dbm=(10.0*i)/3.0 - 30.0; float dbm=(10.0*i)/3.0 - 30.0;
@ -740,7 +749,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
ui->decodedTextLabel->setText(t); ui->decodedTextLabel->setText(t);
ui->decodedTextLabel2->setText(t); ui->decodedTextLabel2->setText(t);
readSettings(); //Restore user's setup parameters readSettings(); //Restore user's setup parameters
setColorHighlighting(); //Set the color highlighting scheme for decoded text.
m_audioThread.start (m_audioThreadPriority); m_audioThread.start (m_audioThreadPriority);
#ifdef WIN32 #ifdef WIN32
@ -919,31 +927,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
ui->cbMenus->setChecked(false); ui->cbMenus->setChecked(false);
} }
QFile f{m_config.data_dir().absoluteFilePath ("lotw-user-activity.csv")};
if(f.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream s(&f);
QString line,call;
int nLoTW=0;
int i1;
QDateTime now=QDateTime::currentDateTime();
QDateTime callDateTime;
// Read and process the file of LoTW-active stations
while(!s.atEnd()) {
line=s.readLine();
i1=line.indexOf(",");
call=line.left(i1);
line=line.mid(i1+1);
i1=line.indexOf(",");
callDateTime=QDateTime::fromString(line.left(i1),"yyyy-MM-dd");
int ndays=callDateTime.daysTo(now);
if(ndays < 366) {
nLoTW++;
m_LoTW[call]=ndays;
}
}
f.close();
}
// this must be the last statement of constructor // this must be the last statement of constructor
if (!m_valid) throw std::runtime_error {"Fatal initialization exception"}; if (!m_valid) throw std::runtime_error {"Fatal initialization exception"};
} }
@ -951,14 +934,14 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
void MainWindow::not_GA_warning_message () void MainWindow::not_GA_warning_message ()
{ {
QDateTime now=QDateTime::currentDateTime(); QDateTime now=QDateTime::currentDateTime();
QDateTime timeout=QDateTime(QDate(2018,10,31)); QDateTime timeout=QDateTime(QDate(2018,11,30));
MessageBox::critical_message (this, MessageBox::critical_message (this,
"This version of WSJT-X is a beta-level Release Candidate.\n\n" "This version of WSJT-X is a beta-level Release Candidate.\n\n"
"On-the-air use carries an obligation to report problems\n" "On-the-air use carries an obligation to report problems\n"
"to the WSJT Development group and to upgrade to a GA\n" "to the WSJT Development group and to upgrade to a GA\n"
"(General Availability) release when it becomes available.\n\n" "(General Availability) release when it becomes available.\n\n"
"This version cannot be used after October 31, 2018\n\n"); "This version cannot be used after November 30, 2018\n\n");
if(now.daysTo(timeout) < 0) Q_EMIT finished(); if(now.daysTo(timeout) < 0) Q_EMIT finished();
} }
@ -1107,7 +1090,8 @@ void MainWindow::readSettings()
ui->cbFirst->setChecked(m_settings->value("CallFirst",true).toBool()); ui->cbFirst->setChecked(m_settings->value("CallFirst",true).toBool());
ui->comboBoxHoundSort->setCurrentIndex(m_settings->value("HoundSort",3).toInt()); ui->comboBoxHoundSort->setCurrentIndex(m_settings->value("HoundSort",3).toInt());
ui->sbNlist->setValue(m_settings->value("FoxNlist",12).toInt()); ui->sbNlist->setValue(m_settings->value("FoxNlist",12).toInt());
ui->sbNslots->setValue(m_settings->value("FoxNslots",5).toInt()); m_Nslots=m_settings->value("FoxNslots",5).toInt();
ui->sbNslots->setValue(m_Nslots);
ui->sbMax_dB->setValue(m_settings->value("FoxMaxDB",30).toInt()); ui->sbMax_dB->setValue(m_settings->value("FoxMaxDB",30).toInt());
m_settings->endGroup(); m_settings->endGroup();
@ -1187,8 +1171,8 @@ void MainWindow::readSettings()
m_audioThreadPriority = static_cast<QThread::Priority> (m_settings->value ("Audio/ThreadPriority", QThread::HighPriority).toInt () % 8); m_audioThreadPriority = static_cast<QThread::Priority> (m_settings->value ("Audio/ThreadPriority", QThread::HighPriority).toInt () % 8);
m_settings->endGroup (); m_settings->endGroup ();
if (displayMsgAvg) on_actionMessage_averaging_triggered();
setContestType(); setContestType();
if(displayMsgAvg) on_actionMessage_averaging_triggered();
} }
void MainWindow::setContestType() void MainWindow::setContestType()
@ -1198,6 +1182,8 @@ void MainWindow::setContestType()
if(m_config.bEU_VHF_Contest()) m_nContest=EU_VHF; if(m_config.bEU_VHF_Contest()) m_nContest=EU_VHF;
if(m_config.bFieldDay()) m_nContest=FIELD_DAY; if(m_config.bFieldDay()) m_nContest=FIELD_DAY;
if(m_config.bRTTYroundup()) m_nContest=RTTY; if(m_config.bRTTYroundup()) m_nContest=RTTY;
if(m_config.bFox()) m_nContest=FOX;
if(m_config.bHound()) m_nContest=HOUND;
} }
void MainWindow::set_application_font (QFont const& font) void MainWindow::set_application_font (QFont const& font)
@ -1217,7 +1203,7 @@ void MainWindow::setDecodedTextFont (QFont const& font)
ui->decodedTextBrowser->setContentFont (font); ui->decodedTextBrowser->setContentFont (font);
ui->decodedTextBrowser2->setContentFont (font); ui->decodedTextBrowser2->setContentFont (font);
ui->textBrowser4->setContentFont(font); ui->textBrowser4->setContentFont(font);
ui->textBrowser4->displayFoxToBeCalled(" ","#ffffff"); ui->textBrowser4->displayFoxToBeCalled(" ");
ui->textBrowser4->setText(""); ui->textBrowser4->setText("");
auto style_sheet = "QLabel {" + font_as_stylesheet (font) + '}'; auto style_sheet = "QLabel {" + font_as_stylesheet (font) + '}';
ui->decodedTextLabel->setStyleSheet (ui->decodedTextLabel->styleSheet () + style_sheet); ui->decodedTextLabel->setStyleSheet (ui->decodedTextLabel->styleSheet () + style_sheet);
@ -1524,11 +1510,13 @@ void MainWindow::fastSink(qint64 frames)
int RxFreq=ui->RxFreqSpinBox->value (); int RxFreq=ui->RxFreqSpinBox->value ();
int nTRpDepth=m_TRperiod + 1000*(m_ndepth & 3); int nTRpDepth=m_TRperiod + 1000*(m_ndepth & 3);
qint64 ms0 = QDateTime::currentMSecsSinceEpoch(); qint64 ms0 = QDateTime::currentMSecsSinceEpoch();
strncpy(dec_data.params.mycall, (m_baseCall+" ").toLatin1(),12); // strncpy(dec_data.params.mycall, (m_baseCall+" ").toLatin1(),12);
strncpy(dec_data.params.mycall,(m_config.my_callsign () + " ").toLatin1(),12);
QString hisCall {ui->dxCallEntry->text ()}; QString hisCall {ui->dxCallEntry->text ()};
bool bshmsg=ui->cbShMsgs->isChecked(); bool bshmsg=ui->cbShMsgs->isChecked();
bool bswl=ui->cbSWL->isChecked(); bool bswl=ui->cbSWL->isChecked();
strncpy(dec_data.params.hiscall,(Radio::base_callsign (hisCall) + " ").toLatin1 ().constData (), 12); // strncpy(dec_data.params.hiscall,(Radio::base_callsign (hisCall) + " ").toLatin1 ().constData (), 12);
strncpy(dec_data.params.hiscall,(hisCall + " ").toLatin1 ().constData (), 12);
strncpy(dec_data.params.mygrid, (m_config.my_grid()+" ").toLatin1(),6); strncpy(dec_data.params.mygrid, (m_config.my_grid()+" ").toLatin1(),6);
QString dataDir; QString dataDir;
dataDir = m_config.writeable_data_dir ().absolutePath (); dataDir = m_config.writeable_data_dir ().absolutePath ();
@ -1702,23 +1690,8 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog
} }
m_opCall=m_config.opCall(); m_opCall=m_config.opCall();
} }
setColorHighlighting();
} }
void MainWindow::setColorHighlighting()
{
//Inform the decoded text windows about our color-highlighting scheme.
ui->decodedTextBrowser->setDecodedTextColors(m_config.color_CQ(),m_config.color_MyCall(),
m_config.color_DXCC(),m_config.color_DXCCband(),m_config.color_NewCall(),
m_config.color_NewCallBand(),m_config.color_NewGrid(),m_config.color_NewGridBand(),
m_config.color_TxMsg(),m_config.color_LoTW());
ui->decodedTextBrowser2->setDecodedTextColors(m_config.color_CQ(),m_config.color_MyCall(),
m_config.color_DXCC(),m_config.color_DXCCband(),m_config.color_NewCall(),
m_config.color_NewCallBand(),m_config.color_NewGrid(),m_config.color_NewGridBand(),
m_config.color_TxMsg(),m_config.color_LoTW());
}
void MainWindow::on_monitorButton_clicked (bool checked) void MainWindow::on_monitorButton_clicked (bool checked)
{ {
if (!m_transmitting) { if (!m_transmitting) {
@ -1836,6 +1809,9 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
} }
} }
break; break;
case Qt::Key_Escape:
on_stopTxButton_clicked();
return;
case Qt::Key_F1: case Qt::Key_F1:
on_actionOnline_User_Guide_triggered(); on_actionOnline_User_Guide_triggered();
return; return;
@ -1860,21 +1836,33 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
on_actionOpen_next_in_directory_triggered(); on_actionOpen_next_in_directory_triggered();
return; return;
case Qt::Key_F11: case Qt::Key_F11:
n=11; if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) {
if(e->modifiers() & Qt::ControlModifier) n+=100; m_bandEdited = true;
if(e->modifiers() & Qt::ShiftModifier) { band_changed(m_freqNominal-2000);
ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()-60); // qDebug() << "Down" << m_freqNominal;
} else{ } else {
bumpFqso(n); n=11;
if(e->modifiers() & Qt::ControlModifier) n+=100;
if(e->modifiers() & Qt::ShiftModifier) {
ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()-60);
} else{
bumpFqso(n);
}
} }
return; return;
case Qt::Key_F12: case Qt::Key_F12:
n=12; if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) {
if(e->modifiers() & Qt::ControlModifier) n+=100; m_bandEdited = true;
if(e->modifiers() & Qt::ShiftModifier) { band_changed(m_freqNominal+2000);
ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()+60); // qDebug() << "Up " << m_freqNominal;
} else { } else {
bumpFqso(n); n=12;
if(e->modifiers() & Qt::ControlModifier) n+=100;
if(e->modifiers() & Qt::ShiftModifier) {
ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()+60);
} else {
bumpFqso(n);
}
} }
return; return;
case Qt::Key_X: case Qt::Key_X:
@ -1936,7 +1924,13 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
return; return;
} }
break; break;
} case Qt::Key_PageUp:
break;
case Qt::Key_PageDown:
band_changed(m_freqNominal-2000);
qDebug() << "Down" << m_freqNominal;
break; }
QMainWindow::keyPressEvent (e); QMainWindow::keyPressEvent (e);
} }
@ -2184,7 +2178,7 @@ void MainWindow::closeEvent(QCloseEvent * e)
m_prefixes.reset (); m_prefixes.reset ();
m_shortcuts.reset (); m_shortcuts.reset ();
m_mouseCmnds.reset (); m_mouseCmnds.reset ();
m_colorHighlighting.reset(); m_colorHighlighting.reset ();
if(m_mode!="MSK144" and m_mode!="FT8") killFile(); if(m_mode!="MSK144" and m_mode!="FT8") killFile();
float sw=0.0; float sw=0.0;
int nw=400; int nw=400;
@ -2221,6 +2215,12 @@ void MainWindow::on_actionFT8_DXpedition_Mode_User_Guide_triggered()
{ {
QDesktopServices::openUrl (QUrl {"http://physics.princeton.edu/pulsar/k1jt/FT8_DXpedition_Mode.pdf"}); QDesktopServices::openUrl (QUrl {"http://physics.princeton.edu/pulsar/k1jt/FT8_DXpedition_Mode.pdf"});
} }
void MainWindow::on_actionQuick_Start_Guide_v2_triggered()
{
QDesktopServices::openUrl (QUrl {"https://physics.princeton.edu/pulsar/k1jt/Quick_Start_WSJT-X_2.0.pdf"});
}
void MainWindow::on_actionOnline_User_Guide_triggered() //Display manual void MainWindow::on_actionOnline_User_Guide_triggered() //Display manual
{ {
#if defined (CMAKE_BUILD) #if defined (CMAKE_BUILD)
@ -2387,32 +2387,29 @@ void MainWindow::on_actionAstronomical_data_toggled (bool checked)
void MainWindow::on_actionFox_Log_triggered() void MainWindow::on_actionFox_Log_triggered()
{ {
on_actionMessage_averaging_triggered(); on_actionMessage_averaging_triggered();
m_msgAvgWidget->foxLogSetup(); m_msgAvgWidget->foxLogSetup(m_nContest);
} }
void MainWindow::on_actionColors_triggered() void MainWindow::on_actionColors_triggered()
{ {
if (!m_colorHighlighting) { if (!m_colorHighlighting)
m_colorHighlighting.reset (new ColorHighlighting {m_settings}); {
} m_colorHighlighting.reset (new ColorHighlighting {m_settings, m_config.decode_highlighting ()});
m_colorHighlighting->showNormal(); connect (&m_config, &Configuration::decode_highlighting_changed, m_colorHighlighting.data (), &ColorHighlighting::set_items);
}
m_colorHighlighting->showNormal ();
m_colorHighlighting->raise (); m_colorHighlighting->raise ();
m_colorHighlighting->activateWindow (); m_colorHighlighting->activateWindow ();
m_colorHighlighting->colorHighlightlingSetup(m_config.color_CQ(),m_config.color_MyCall(),
m_config.color_DXCC(),m_config.color_DXCCband(),m_config.color_NewCall(),
m_config.color_NewCallBand(),m_config.color_NewGrid(),m_config.color_NewGridBand(),
m_config.color_TxMsg(),m_config.color_LoTW());
} }
void MainWindow::on_actionMessage_averaging_triggered() void MainWindow::on_actionMessage_averaging_triggered()
{ {
if (!m_msgAvgWidget) if(!m_msgAvgWidget) {
{ m_msgAvgWidget.reset (new MessageAveraging {m_settings, m_config.decoded_text_font ()});
m_msgAvgWidget.reset (new MessageAveraging {m_settings, m_config.decoded_text_font ()});
// Connect signals from Message Averaging window // Connect signals from Message Averaging window
connect (this, &MainWindow::finished, m_msgAvgWidget.data (), &MessageAveraging::close); connect (this, &MainWindow::finished, m_msgAvgWidget.data (), &MessageAveraging::close);
} }
m_msgAvgWidget->showNormal(); m_msgAvgWidget->showNormal();
m_msgAvgWidget->raise (); m_msgAvgWidget->raise ();
m_msgAvgWidget->activateWindow (); m_msgAvgWidget->activateWindow ();
@ -2943,12 +2940,17 @@ void MainWindow::readFromStdout() //readFromStdout
m_blankLine = false; m_blankLine = false;
} }
DecodedText decodedtext {QString::fromUtf8(t.constData()).remove(QRegularExpression {"\r|\n"})}; DecodedText decodedtext0 {QString::fromUtf8(t.constData())
.remove(QRegularExpression {"\r|\n"})};
DecodedText decodedtext {QString::fromUtf8(t.constData())
.remove(QRegularExpression {"\r|\n"}).remove("TU; ")};
if(m_mode=="FT8" and m_config.bFox() and if(m_mode=="FT8" and m_config.bFox() and
(decodedtext.string().contains("R+") or decodedtext.string().contains("R-"))) { (decodedtext.string().contains("R+") or decodedtext.string().contains("R-"))) {
auto for_us = decodedtext.string().contains(" " + m_config.my_callsign() + " ") or auto for_us = decodedtext.string().contains(" " + m_config.my_callsign() + " ") or
decodedtext.string().contains(" "+m_baseCall) or decodedtext.string().contains(" "+m_baseCall) or
decodedtext.string().contains(m_baseCall+" "); decodedtext.string().contains(m_baseCall+" ") or
decodedtext.string().contains(" <" + m_config.my_callsign() + "> ");
if(decodedtext.string().contains(" DE ")) for_us=true; //Hound with compound callsign if(decodedtext.string().contains(" DE ")) for_us=true; //Hound with compound callsign
if(for_us) { if(for_us) {
QString houndCall,houndGrid; QString houndCall,houndGrid;
@ -2956,7 +2958,8 @@ void MainWindow::readFromStdout() //readFromStdout
foxRxSequencer(decodedtext.string(),houndCall,houndGrid); foxRxSequencer(decodedtext.string(),houndCall,houndGrid);
} }
} }
//Left (Band activity) window
//Left (Band activity) window
if(!bAvgMsg) { if(!bAvgMsg) {
if(m_mode=="FT8" and m_config.bFox()) { if(m_mode=="FT8" and m_config.bFox()) {
if(!m_bDisplayedOnce) { if(!m_bDisplayedOnce) {
@ -2967,13 +2970,13 @@ void MainWindow::readFromStdout() //readFromStdout
m_bDisplayedOnce=true; m_bDisplayedOnce=true;
} }
} else { } else {
ui->decodedTextBrowser->displayDecodedText(decodedtext,m_baseCall,m_config.DXCC(), ui->decodedTextBrowser->displayDecodedText(decodedtext0,m_baseCall,m_config.DXCC(),
m_logBook,m_currentBand,m_config.ppfx(), m_logBook,m_currentBand,m_config.ppfx(),
(ui->cbCQonly->isVisible() and ui->cbCQonly->isChecked())); (ui->cbCQonly->isVisible() and ui->cbCQonly->isChecked()));
} }
} }
//Right (Rx Frequency) window //Right (Rx Frequency) window
bool bDisplayRight=bAvgMsg; bool bDisplayRight=bAvgMsg;
int audioFreq=decodedtext.frequencyOffset(); int audioFreq=decodedtext.frequencyOffset();
@ -3002,7 +3005,7 @@ void MainWindow::readFromStdout() //readFromStdout
if (bDisplayRight) { if (bDisplayRight) {
// This msg is within 10 hertz of our tuned frequency, or a JT4 or JT65 avg, // This msg is within 10 hertz of our tuned frequency, or a JT4 or JT65 avg,
// or contains MyCall // or contains MyCall
ui->decodedTextBrowser2->displayDecodedText(decodedtext,m_baseCall,m_config.DXCC(), ui->decodedTextBrowser2->displayDecodedText(decodedtext0,m_baseCall,m_config.DXCC(),
m_logBook,m_currentBand,m_config.ppfx()); m_logBook,m_currentBand,m_config.ppfx());
if(m_mode!="JT4") { if(m_mode!="JT4") {
@ -3056,8 +3059,9 @@ void MainWindow::readFromStdout() //readFromStdout
//### I think this is where we are preventing Hounds from spotting Fox ### //### I think this is where we are preventing Hounds from spotting Fox ###
if(m_mode!="FT8" or !m_config.bHound()) { if(m_mode!="FT8" or !m_config.bHound()) {
if(m_mode=="FT8" or m_mode=="QRA64" or m_mode=="JT4" or m_mode=="JT65" or if(m_mode=="FT8" or m_mode=="QRA64" or m_mode=="JT4" or m_mode=="JT65" or m_mode=="JT9") {
m_mode=="JT9") auto_sequence (decodedtext, 25, 50); auto_sequence (decodedtext, 25, 50);
}
postDecode (true, decodedtext.string ()); postDecode (true, decodedtext.string ());
// find and extract any report for myCall, but save in m_rptRcvd only if it's from DXcall // find and extract any report for myCall, but save in m_rptRcvd only if it's from DXcall
@ -3130,7 +3134,7 @@ void MainWindow::auto_sequence (DecodedText const& message, unsigned start_toler
} }
} }
bool bEU_VHF_w2=(nrpt>=520001 and nrpt<=594000); bool bEU_VHF_w2=(nrpt>=520001 and nrpt<=594000);
if(bEU_VHF_w2) m_xRcvd=message.string().left(45).trimmed().right(13); if(bEU_VHF_w2) m_xRcvd=message.string().trimmed().right(13);
if (m_auto if (m_auto
&& (m_QSOProgress==REPLYING or (!ui->tx1->isEnabled () and m_QSOProgress==REPORT)) && (m_QSOProgress==REPLYING or (!ui->tx1->isEnabled () and m_QSOProgress==REPORT))
&& qAbs (ui->TxFreqSpinBox->value () - df) <= int (stop_tolerance) && qAbs (ui->TxFreqSpinBox->value () - df) <= int (stop_tolerance)
@ -3333,13 +3337,9 @@ void MainWindow::guiUpdate()
auto const& message = tr ("Please choose another Tx frequency." auto const& message = tr ("Please choose another Tx frequency."
" WSJT-X will not knowingly transmit another" " WSJT-X will not knowingly transmit another"
" mode in the WSPR sub-band on 30m."); " mode in the WSPR sub-band on 30m.");
#if QT_VERSION >= 0x050400
QTimer::singleShot (0, [=] { // don't block guiUpdate QTimer::singleShot (0, [=] { // don't block guiUpdate
MessageBox::warning_message (this, tr ("WSPR Guard Band"), message); MessageBox::warning_message (this, tr ("WSPR Guard Band"), message);
}); });
#else
MessageBox::warning_message (this, tr ("WSPR Guard Band"), message);
#endif
} }
} }
@ -3354,13 +3354,9 @@ void MainWindow::guiUpdate()
auto const& message = tr ("Please choose another dial frequency." auto const& message = tr ("Please choose another dial frequency."
" WSJT-X will not operate in Fox mode" " WSJT-X will not operate in Fox mode"
" in the standard FT8 sub-bands."); " in the standard FT8 sub-bands.");
#if QT_VERSION >= 0x050400
QTimer::singleShot (0, [=] { // don't block guiUpdate QTimer::singleShot (0, [=] { // don't block guiUpdate
MessageBox::warning_message (this, tr ("Fox Mode warning"), message); MessageBox::warning_message (this, tr ("Fox Mode warning"), message);
}); });
#else
MessageBox::warning_message (this, tr ("Fox Mode warning"), message);
#endif
break; break;
} }
} }
@ -3580,7 +3576,6 @@ void MainWindow::guiUpdate()
m_xSent=t.at(n-2) + " " + t.at(n-1); m_xSent=t.at(n-2) + " " + t.at(n-1);
} }
} }
} }
if(m_isync==1) msgsent[22]=0; if(m_isync==1) msgsent[22]=0;
if(m_isync==2) msgsent[37]=0; if(m_isync==2) msgsent[37]=0;
@ -3629,18 +3624,20 @@ void MainWindow::guiUpdate()
if(m_config.id_after_73 ()) { if(m_config.id_after_73 ()) {
icw[0] = m_ncw; icw[0] = m_ncw;
} }
if (m_config.prompt_to_log () && !m_tune) { if((m_config.prompt_to_log() or m_config.autoLog()) && !m_tune) logQSOTimer.start(0);
logQSOTimer.start (0);
}
} }
bool b=(m_mode=="FT8") and ui->cbAutoSeq->isChecked(); bool b=(m_mode=="FT8") and ui->cbAutoSeq->isChecked();
if(is_73 and (m_config.disable_TX_on_73() or b)) { if(is_73 and (m_config.disable_TX_on_73() or b)) {
auto_tx_mode (false); if(m_nextCall!="") {
if(b) { useNextCall();
m_ntx=6; } else {
ui->txrb6->setChecked(true); auto_tx_mode (false);
m_QSOProgress = CALLING; if(b) {
m_ntx=6;
ui->txrb6->setChecked(true);
m_QSOProgress = CALLING;
}
} }
} }
@ -3741,7 +3738,7 @@ void MainWindow::guiUpdate()
} }
if(m_mode=="FT8" or m_mode=="MSK144") { if(m_mode=="FT8" or m_mode=="MSK144") {
if(ui->txrb1->isEnabled() and m_nContest!=NONE and m_nContest!=EU_VHF) { if(ui->txrb1->isEnabled() and (m_nContest==NA_VHF or m_nContest==FIELD_DAY or m_nContest==RTTY)) {
//We're in a contest-like mode other than EU_VHF: start QSO with Tx2. //We're in a contest-like mode other than EU_VHF: start QSO with Tx2.
ui->tx1->setEnabled(false); ui->tx1->setEnabled(false);
} }
@ -3753,8 +3750,8 @@ void MainWindow::guiUpdate()
//Once per second: //Once per second:
if(nsec != m_sec0) { if(nsec != m_sec0) {
// qDebug() << "OneSec:"; // qDebug() << "OneSec:" << m_nContest << m_Nslots;
if(!m_msgAvgWidget and m_nContest>0 and m_nContest<6) on_actionFox_Log_triggered();
if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) { if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) {
if(!m_bVHFwarned) vhfWarning(); if(!m_bVHFwarned) vhfWarning();
} else { } else {
@ -3762,21 +3759,7 @@ void MainWindow::guiUpdate()
} }
m_currentBand=m_config.bands()->find(m_freqNominal); m_currentBand=m_config.bands()->find(m_freqNominal);
// if(m_config.bFox()) {
// if(m_config.my_callsign()=="K1JT" or m_config.my_callsign()=="K9AN" or
// m_config.my_callsign()=="G4WJS" or m_config.my_callsign().contains("KH7Z")) {
// ui->sbNslots->setMaximum(5);
// m_Nslots=ui->sbNslots->value();
// ui->sbNslots->setEnabled(true);
// } else {
// ui->sbNslots->setMaximum(1);
// m_Nslots=1;
// ui->sbNslots->setEnabled(false);
// }
// }
if(m_config.bHound()) { if(m_config.bHound()) {
// m_bWarnedHound=false;
qint32 tHound=QDateTime::currentMSecsSinceEpoch()/1000 - m_tAutoOn; qint32 tHound=QDateTime::currentMSecsSinceEpoch()/1000 - m_tAutoOn;
//To keep calling Fox, Hound must reactivate Enable Tx at least once every 2 minutes //To keep calling Fox, Hound must reactivate Enable Tx at least once every 2 minutes
if(tHound >= 120 and m_ntx==1) auto_tx_mode(false); if(tHound >= 120 and m_ntx==1) auto_tx_mode(false);
@ -3860,6 +3843,22 @@ void MainWindow::guiUpdate()
m_btxok0=m_btxok; m_btxok0=m_btxok;
} //End of guiUpdate } //End of guiUpdate
void MainWindow::useNextCall()
{
ui->dxCallEntry->setText(m_nextCall);
m_nextCall="";
ui->labNextCall->setStyleSheet("");
ui->labNextCall->setText("");
if(m_nextGrid.contains(grid_regexp)) {
ui->dxGridEntry->setText(m_nextGrid);
m_ntx=2;
ui->txrb2->setChecked(true);
} else {
m_ntx=3;
ui->txrb3->setChecked(true);
}
genStdMsgs(m_nextRpt);
}
void MainWindow::startTx2() void MainWindow::startTx2()
{ {
@ -4218,6 +4217,14 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
QString hiscall; QString hiscall;
QString hisgrid; QString hisgrid;
message.deCallAndGrid(/*out*/hiscall,hisgrid); message.deCallAndGrid(/*out*/hiscall,hisgrid);
if(message.string().contains(hiscall+"/R")) {
hiscall+="/R";
ui->dxCallEntry->setText(hiscall);
}
if(message.string().contains(hiscall+"/P")) {
hiscall+="/P";
ui->dxCallEntry->setText(hiscall);
}
bool is_73 = message_words.filter (QRegularExpression {"^(73|RR73)$"}).size (); bool is_73 = message_words.filter (QRegularExpression {"^(73|RR73)$"}).size ();
if (!is_73 and !message.isStandardMessage() and !message.string().contains("<")) { if (!is_73 and !message.isStandardMessage() and !message.string().contains("<")) {
@ -4264,7 +4271,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
} }
// prior DX call (possible QSO partner) // prior DX call (possible QSO partner)
auto qso_partner_base_call = Radio::base_callsign (ui->dxCallEntry-> text ()); auto qso_partner_base_call = Radio::base_callsign (ui->dxCallEntry->text ());
auto base_call = Radio::base_callsign (hiscall); auto base_call = Radio::base_callsign (hiscall);
// Determine appropriate response to received message // Determine appropriate response to received message
@ -4277,7 +4284,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
|| dtext.contains ("/" + m_baseCall + " ") || dtext.contains ("/" + m_baseCall + " ")
|| dtext.contains (" " + m_baseCall + "/") || dtext.contains (" " + m_baseCall + "/")
|| (firstcall == "DE")) { || (firstcall == "DE")) {
QString w2=message_words.at(2); QString w2="";
if(message_words.size()>=3) w2=message_words.at(2);
QString w34=""; QString w34="";
if(message_words.size()>=4) w34=message_words.at(3); if(message_words.size()>=4) w34=message_words.at(3);
int nrpt=w2.toInt(); int nrpt=w2.toInt();
@ -4366,8 +4374,19 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
if (ui->rbGenMsg->isChecked ()) m_ntx=7; if (ui->rbGenMsg->isChecked ()) m_ntx=7;
m_gen_message_is_cq = false; m_gen_message_is_cq = false;
} else { } else {
m_ntx=5; m_bTUmsg=false;
ui->txrb5->setChecked(true); if(m_nContest==RTTY and m_nextCall!="") {
// We're in RTTY contest and have "nextCall" queued up: send a "TU; ..." message
on_logQSOButton_clicked();
ui->tx3->setText(ui->tx3->text().remove("TU; "));
useNextCall();
QString t="TU; " + ui->tx3->text();
ui->tx3->setText(t);
m_bTUmsg=true;
} else {
m_ntx=5;
ui->txrb5->setChecked(true);
}
} }
m_QSOProgress = SIGNOFF; m_QSOProgress = SIGNOFF;
} else if((m_QSOProgress >= REPORT } else if((m_QSOProgress >= REPORT
@ -4400,7 +4419,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
} }
} }
else if (m_QSOProgress >= ROGERS else if (m_QSOProgress >= ROGERS
&& message_words.size () > 2 && message_words.at (1).contains (m_baseCall) && message_words.at (2) == "73") { && message_words.size () > 2 && message_words.at (1).contains (m_baseCall)
&& message_words.at (2) == "73") {
// 73 back to compound call holder // 73 back to compound call holder
if(ui->tabWidget->currentIndex()==1) { if(ui->tabWidget->currentIndex()==1) {
gen_msg = 5; gen_msg = 5;
@ -4414,7 +4434,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
m_QSOProgress = SIGNOFF; m_QSOProgress = SIGNOFF;
} }
else if (!(m_bAutoReply && m_QSOProgress > CALLING)) { else if (!(m_bAutoReply && m_QSOProgress > CALLING)) {
if ((message_words.size () > 4 && message_words.at (1).contains (m_baseCall) && message_words.at (4) == "OOO")) { if ((message_words.size () > 4 && message_words.at (1).contains (m_baseCall)
&& message_words.at (4) == "OOO")) {
// EME short code report or MSK144/FT8 contest mode reply, send back Tx3 // EME short code report or MSK144/FT8 contest mode reply, send back Tx3
m_ntx=3; m_ntx=3;
m_QSOProgress = ROGER_REPORT; m_QSOProgress = ROGER_REPORT;
@ -4445,6 +4466,17 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
} }
} }
else { // nothing for us else { // nothing for us
if(message_words.size () > 3 // enough fields for a normal message
&& m_nContest==RTTY
&& (message_words.at(1).contains(m_baseCall) || "DE" == message_words.at(1))
&& (!message_words.at(2).contains(qso_partner_base_call) and !bEU_VHF_w2)) {
// Queue up the next QSO partner
m_nextCall=message_words.at(2);
m_nextGrid=message_words.at(3);
m_nextRpt=message.report();
ui->labNextCall->setText("Next: " + m_nextCall);
ui->labNextCall->setStyleSheet("QLabel {background-color: #66ff66}");
}
return; return;
} }
} }
@ -4488,7 +4520,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
ui->txrb5->setChecked(true); ui->txrb5->setChecked(true);
} }
m_QSOProgress = SIGNOFF; m_QSOProgress = SIGNOFF;
} else {// just work them } else {
// just work them
if (ui->tx1->isEnabled ()) { if (ui->tx1->isEnabled ()) {
m_ntx = 1; m_ntx = 1;
m_QSOProgress = REPLYING; m_QSOProgress = REPLYING;
@ -4554,7 +4587,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
} }
ui->rptSpinBox->setValue(n); ui->rptSpinBox->setValue(n);
if (!m_nTx73) { // Don't genStdMsgs if we're already sending 73. // Don't genStdMsgs if we're already sending 73, or a "TU; " msg is queued.
if (!m_nTx73 and !m_bTUmsg) {
genStdMsgs(rpt); genStdMsgs(rpt);
if (gen_msg) { if (gen_msg) {
switch (gen_msg) { switch (gen_msg) {
@ -4610,7 +4644,8 @@ void MainWindow::genCQMsg ()
} }
} else { } else {
if(stdCall(m_config.my_callsign())) { if(stdCall(m_config.my_callsign())) {
msgtype (QString {"%1 %2 %3"}.arg(m_CQtype).arg(m_config.my_callsign()).arg(grid.left(4)),ui->tx6); msgtype (QString {"%1 %2 %3"}.arg(m_CQtype).arg(m_config.my_callsign())
.arg(grid.left(4)),ui->tx6);
} else { } else {
msgtype (QString {"%1 %2"}.arg(m_CQtype).arg(m_config.my_callsign()),ui->tx6); msgtype (QString {"%1 %2"}.arg(m_CQtype).arg(m_config.my_callsign()),ui->tx6);
} }
@ -4623,11 +4658,14 @@ void MainWindow::genCQMsg ()
} }
} }
if((m_mode=="FT8" or m_mode=="MSK144") and m_nContest!=NONE) { QString t=ui->tx6->text();
QString t=ui->tx6->text(); if((m_mode=="FT8" or m_mode=="MSK144") and m_nContest!=NONE and
// if(m_nContest==NA_VHF) t="CQ QP" + t.mid(2,-1); t.split(" ").at(1)==m_config.my_callsign() and stdCall(m_config.my_callsign())) {
if(m_nContest==NA_VHF) t="CQ TEST" + t.mid(2,-1);
if(m_nContest==EU_VHF) t="CQ TEST" + t.mid(2,-1);
if(m_nContest==FIELD_DAY) t="CQ FD" + t.mid(2,-1); if(m_nContest==FIELD_DAY) t="CQ FD" + t.mid(2,-1);
if(m_nContest==RTTY) t="CQ RU" + t.mid(2,-1); if(m_nContest==RTTY) t="CQ RU" + t.mid(2,-1);
if(m_nContest==FOX) t="CQ HUND" + t.mid(2,-1);
ui->tx6->setText(t); ui->tx6->setText(t);
} }
} else { } else {
@ -4662,6 +4700,10 @@ bool MainWindow::stdCall(QString w)
void MainWindow::genStdMsgs(QString rpt, bool unconditional) void MainWindow::genStdMsgs(QString rpt, bool unconditional)
{ {
if(ui->tx3->text().left(4)=="TU; ") {
return;
}
genCQMsg (); genCQMsg ();
auto const& hisCall=ui->dxCallEntry->text(); auto const& hisCall=ui->dxCallEntry->text();
if(!hisCall.size ()) { if(!hisCall.size ()) {
@ -4686,19 +4728,22 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
bool bMyCall=stdCall(my_callsign); bool bMyCall=stdCall(my_callsign);
bool bHisCall=stdCall(hisCall); bool bHisCall=stdCall(hisCall);
bool b77=(m_mode=="MSK144" or m_mode=="FT8") and (!bMyCall or !bHisCall); bool b77=(m_mode=="MSK144" or m_mode=="FT8") and
(!bMyCall or !bHisCall or m_config.bGenerate77());
QString t0=hisBase + " " + m_baseCall + " "; QString t0=hisBase + " " + m_baseCall + " ";
QString t0s=hisCall + " " + my_callsign + " ";
QString t0a,t0b; QString t0a,t0b;
if(b77) { if(b77) {
// if(bHisCall and bMyCall) t0=hisCall + " " + my_callsign + " "; if(bHisCall and bMyCall) t0=hisCall + " " + my_callsign + " ";
t0a="<"+hisCall + "> " + my_callsign + " "; t0a="<"+hisCall + "> " + my_callsign + " ";
t0b=hisCall + " <" + my_callsign + "> "; t0b=hisCall + " <" + my_callsign + "> ";
} }
QString t00=t0; QString t00=t0;
QString t {t0 + my_grid}; QString t {t0 + my_grid};
if(b77 and (!bMyCall or !bHisCall)) t=t0a; // if(b77 and (!bMyCall or !bHisCall)) t=t0a;
if(b77 and (!bMyCall)) t=t0a;
msgtype(t, ui->tx1); msgtype(t, ui->tx1);
if (eme_short_codes) { if (eme_short_codes) {
t=t+" OOO"; t=t+" OOO";
@ -4744,8 +4789,8 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
} }
if(m_mode=="MSK144" and m_bShMsgs) { if(m_mode=="MSK144" and m_bShMsgs) {
int i=t0.length()-1; int i=t0s.length()-1;
t0="<" + t0.mid(0,i) + "> "; t0="<" + t0s.mid(0,i) + "> ";
if(!m_config.bNA_VHF_Contest()) { if(!m_config.bNA_VHF_Contest()) {
if(n<=-2) n=-3; if(n<=-2) n=-3;
if(n>=-1 and n<=1) n=0; if(n>=-1 and n<=1) n=0;
@ -4764,14 +4809,14 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
t=t0 + "R" + rpt; t=t0 + "R" + rpt;
msgtype(t, ui->tx3); msgtype(t, ui->tx3);
} }
if(m_mode=="MSK144" and m_bShMsgs) { if(m_mode=="MSK144" and m_bShMsgs and m_nContest==NONE) {
t=t0 + "R" + rpt; t=t0 + "R" + rpt;
msgtype(t, ui->tx3); msgtype(t, ui->tx3);
m_send_RR73=false; m_send_RR73=false;
} }
t=t0 + (m_send_RR73 ? "RR73" : "RRR"); t=t0 + (m_send_RR73 ? "RR73" : "RRR");
if(m_mode=="MSK144" or m_mode=="FT8") { if((m_mode=="MSK144" and !m_bShMsgs) or m_mode=="FT8") {
if(!bHisCall and bMyCall) t=hisCall + " <" + my_callsign + "> " + (m_send_RR73 ? "RR73" : "RRR"); if(!bHisCall and bMyCall) t=hisCall + " <" + my_callsign + "> " + (m_send_RR73 ? "RR73" : "RRR");
if(bHisCall and !bMyCall) t="<" + hisCall + "> " + my_callsign + " " + (m_send_RR73 ? "RR73" : "RRR"); if(bHisCall and !bMyCall) t="<" + hisCall + "> " + my_callsign + " " + (m_send_RR73 ? "RR73" : "RRR");
} }
@ -4779,7 +4824,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
msgtype(t, ui->tx4); msgtype(t, ui->tx4);
t=t0 + "73"; t=t0 + "73";
if(m_mode=="MSK144" or m_mode=="FT8") { if((m_mode=="MSK144" and !m_bShMsgs) or m_mode=="FT8") {
if(!bHisCall and bMyCall) t=hisCall + " <" + my_callsign + "> 73"; if(!bHisCall and bMyCall) t=hisCall + " <" + my_callsign + "> 73";
if(bHisCall and !bMyCall) t="<" + hisCall + "> " + my_callsign + " 73"; if(bHisCall and !bMyCall) t="<" + hisCall + "> " + my_callsign + " 73";
} }
@ -4795,7 +4840,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
} }
} }
if(m_config.bGenerate77()) return; if(m_config.bGenerate77() or "MSK144" == m_mode) return;
if (is_compound) { if (is_compound) {
if (is_type_one) { if (is_type_one) {
@ -5180,22 +5225,38 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button
if (dateTimeQSOOff < m_dateTimeQSOOn) dateTimeQSOOff = m_dateTimeQSOOn; if (dateTimeQSOOff < m_dateTimeQSOOn) dateTimeQSOOff = m_dateTimeQSOOn;
QString grid=m_hisGrid; QString grid=m_hisGrid;
if(grid=="....") grid=""; if(grid=="....") grid="";
m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd, if(m_nContest>NONE and m_nContest<FOX) {
m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + ui->TxFreqSpinBox->value(),
m_config.my_callsign(), m_config.my_grid(), m_noSuffix,
m_config.log_as_RTTY(), m_config.report_in_comments(),
m_config.bFox(), m_opCall);
if(m_nContest!=NONE) {
if(m_nContest==NA_VHF) { if(m_nContest==NA_VHF) {
m_xSent=m_config.my_grid().left(4); m_xSent=m_config.my_grid().left(4);
m_xRcvd=m_hisGrid; m_xRcvd=m_hisGrid;
} }
if(m_nContest!=NONE) { if(m_nContest==EU_VHF) {
int n=ui->sbSerialNumber->value(); m_rptSent=m_xSent.split(" ").at(0).left(2);
ui->sbSerialNumber->setValue(n+1); m_rptRcvd=m_xRcvd.split(" ").at(0).left(2);
cabLog(); //Call the Cabrillo contest logger m_hisGrid=m_xRcvd.split(" ").at(1);
grid=m_hisGrid;
ui->dxGridEntry->setText(grid);
} }
if(m_nContest==FIELD_DAY) {
m_rptSent=m_xSent.split(" ").at(0);
m_rptRcvd=m_xRcvd.split(" ").at(0);
}
if(m_nContest==RTTY) {
m_rptSent=m_xSent.split(" ").at(0);
m_rptRcvd=m_xRcvd.split(" ").at(0);
}
int n=ui->sbSerialNumber->value();
ui->sbSerialNumber->setValue(n+1);
cabLog(); //Call the Cabrillo contest logger
} }
bool bAutoLog=m_config.autoLog() and m_nContest>0;
m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd,
m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal +
ui->TxFreqSpinBox->value(), m_config.my_callsign(),
m_config.my_grid(), m_noSuffix, m_config.log_as_RTTY(),
m_config.report_in_comments(), m_config.bFox(),
bAutoLog, m_opCall, m_nContest, m_xSent, m_xRcvd);
} }
void MainWindow::cabLog() void MainWindow::cabLog()
@ -5205,13 +5266,22 @@ void MainWindow::cabLog()
int nfreq=m_freqNominal/1000; int nfreq=m_freqNominal/1000;
if(m_freqNominal>50000000) nfreq=m_freqNominal/1000000; if(m_freqNominal>50000000) nfreq=m_freqNominal/1000000;
QString t; QString t;
t.sprintf("QSO: %5d RY ",nfreq); t.sprintf("QSO: %5d DG ",nfreq);
t=t + QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hhmm ") + t=t + QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hhmm ") +
m_config.my_callsign().leftJustified(13,' ') + m_xSent.leftJustified(14,' ') + m_config.my_callsign().leftJustified(13,' ') + m_xSent.leftJustified(14,' ') +
m_hisCall.leftJustified(13,' ') + m_xRcvd; m_hisCall.leftJustified(13,' ') + m_xRcvd;
QTextStream out(&f); QTextStream out(&f);
out << t << endl; out << t << endl;
f.close(); f.close();
if(m_msgAvgWidget != NULL and m_msgAvgWidget->isVisible()) {
QString band;
band.sprintf(" %5d ",nfreq);
t=QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hhmm ") + band +
m_hisCall.leftJustified(13,' ') + m_xSent.leftJustified(14,' ') + m_xRcvd;
m_msgAvgWidget->contestAddLog(m_nContest,t);
}
m_xSent="";
m_xRcvd="";
} else { } else {
MessageBox::warning_message (this, tr("File Open Error"), MessageBox::warning_message (this, tr("File Open Error"),
tr("Cannot open \"%1\" for append: %2").arg(f.fileName()).arg(f.errorString())); tr("Cannot open \"%1\" for append: %2").arg(f.fileName()).arg(f.errorString()));
@ -5289,7 +5359,7 @@ void MainWindow::displayWidgets(qint64 n)
if(i==25) ui->actionEnable_AP_JT65->setVisible (b); if(i==25) ui->actionEnable_AP_JT65->setVisible (b);
if(i==26) ui->actionEnable_AP_DXcall->setVisible (b); if(i==26) ui->actionEnable_AP_DXcall->setVisible (b);
if(i==27) ui->cbFirst->setVisible(b); if(i==27) ui->cbFirst->setVisible(b);
// if(i==28) ui->cbVHFcontest->setVisible(b); if(i==28) ui->labNextCall->setVisible(b);
if(i==29) ui->measure_check_box->setVisible(b); if(i==29) ui->measure_check_box->setVisible(b);
if(i==30) ui->labDXped->setVisible(b); if(i==30) ui->labDXped->setVisible(b);
if(i==31) ui->cbRxAll->setVisible(b); if(i==31) ui->cbRxAll->setVisible(b);
@ -5338,7 +5408,7 @@ void MainWindow::on_actionFT8_triggered()
ui->label_6->setText("Band Activity"); ui->label_6->setText("Band Activity");
ui->decodedTextLabel->setText( " UTC dB DT Freq Message"); ui->decodedTextLabel->setText( " UTC dB DT Freq Message");
} }
displayWidgets(nWidgets("111010000100111000010000100100001")); displayWidgets(nWidgets("111010000100111000010000100110001"));
ui->txrb2->setEnabled(true); ui->txrb2->setEnabled(true);
ui->txrb4->setEnabled(true); ui->txrb4->setEnabled(true);
ui->txrb5->setEnabled(true); ui->txrb5->setEnabled(true);
@ -5357,7 +5427,7 @@ void MainWindow::on_actionFT8_triggered()
ui->tabWidget->setCurrentIndex(2); ui->tabWidget->setCurrentIndex(2);
ui->TxFreqSpinBox->setValue(300); ui->TxFreqSpinBox->setValue(300);
displayWidgets(nWidgets("111010000100111000010000000000100")); displayWidgets(nWidgets("111010000100111000010000000000100"));
ui->labDXped->setText("DXpedition: Fox"); ui->labDXped->setText("Fox");
on_actionFox_Log_triggered(); on_actionFox_Log_triggered();
} }
if(m_config.bHound()) { if(m_config.bHound()) {
@ -5367,7 +5437,7 @@ void MainWindow::on_actionFT8_triggered()
ui->tabWidget->setCurrentIndex(0); ui->tabWidget->setCurrentIndex(0);
ui->cbHoldTxFreq->setChecked(true); ui->cbHoldTxFreq->setChecked(true);
displayWidgets(nWidgets("111010000100110000010000000000110")); displayWidgets(nWidgets("111010000100110000010000000000110"));
ui->labDXped->setText("DXpedition: Hound"); ui->labDXped->setText("Hound");
ui->txrb1->setChecked(true); ui->txrb1->setChecked(true);
ui->txrb2->setEnabled(false); ui->txrb2->setEnabled(false);
ui->txrb4->setEnabled(false); ui->txrb4->setEnabled(false);
@ -5964,6 +6034,17 @@ void MainWindow::on_actionErase_cabrillo_log_triggered()
} }
} }
void MainWindow::on_actionExport_Cabrillo_log_triggered()
{
if(!m_exportCabrillo) {
m_exportCabrillo.reset(new ExportCabrillo{m_settings});
}
QString CabLog=m_config.writeable_data_dir ().absoluteFilePath ("cabrillo.log");
m_exportCabrillo->setFile(CabLog);
m_exportCabrillo->exec();
}
void MainWindow::on_actionErase_wsjtx_log_adi_triggered() void MainWindow::on_actionErase_wsjtx_log_adi_triggered()
{ {
int ret = MessageBox::query_message (this, tr ("Confirm Erase"), int ret = MessageBox::query_message (this, tr ("Confirm Erase"),
@ -6223,6 +6304,7 @@ void MainWindow::on_tuneButton_clicked (bool checked)
} }
else { // we're turning off so remember our Tune pwr setting and reset to Tx pwr else { // we're turning off so remember our Tune pwr setting and reset to Tx pwr
if (m_config.pwrBandTuneMemory() || m_config.pwrBandTxMemory()) { if (m_config.pwrBandTuneMemory() || m_config.pwrBandTxMemory()) {
stopTx();
m_pwrBandTuneMemory[curBand] = ui->outAttenuation->value(); // remember our Tune pwr m_pwrBandTuneMemory[curBand] = ui->outAttenuation->value(); // remember our Tune pwr
m_PwrBandSetOK = false; m_PwrBandSetOK = false;
ui->outAttenuation->setValue(m_pwrBandTxMemory[curBand].toInt()); // set to Tx pwr ui->outAttenuation->setValue(m_pwrBandTxMemory[curBand].toInt()); // set to Tx pwr
@ -6767,7 +6849,7 @@ void::MainWindow::VHF_features_enabled(bool b)
ui->actionMessage_averaging->setEnabled(b); ui->actionMessage_averaging->setEnabled(b);
ui->actionEnable_AP_DXcall->setVisible (m_mode=="QRA64"); ui->actionEnable_AP_DXcall->setVisible (m_mode=="QRA64");
ui->actionEnable_AP_JT65->setVisible (b && m_mode=="JT65"); ui->actionEnable_AP_JT65->setVisible (b && m_mode=="JT65");
if(!b && m_msgAvgWidget and !m_config.bFox()) { if(!b && m_msgAvgWidget and !m_config.bFox() and !m_config.autoLog()) {
if(m_msgAvgWidget->isVisible()) m_msgAvgWidget->close(); if(m_msgAvgWidget->isVisible()) m_msgAvgWidget->close();
} }
} }
@ -6898,27 +6980,28 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de
QString format_string {"%1 %2 %3 %4 %5 %6"}; QString format_string {"%1 %2 %3 %4 %5 %6"};
auto const& time_string = time.toString ("~" == mode || "&" == mode ? "hhmmss" : "hhmm"); auto const& time_string = time.toString ("~" == mode || "&" == mode ? "hhmmss" : "hhmm");
auto cqtext = format_string auto message_line = format_string
.arg (time_string) .arg (time_string)
.arg (snr, 3) .arg (snr, 3)
.arg (delta_time, 4, 'f', 1) .arg (delta_time, 4, 'f', 1)
.arg (delta_frequency, 4) .arg (delta_frequency, 4)
.arg (mode, -2) .arg (mode, -2)
.arg (message_text); .arg (message_text);
auto messages = ui->decodedTextBrowser->toPlainText (); QTextCursor start {ui->decodedTextBrowser->document ()};
auto position = messages.lastIndexOf (cqtext); start.movePosition (QTextCursor::End);
if (position < 0) auto cursor = ui->decodedTextBrowser->document ()->find (message_line, start, QTextDocument::FindBackward);
if (cursor.isNull ())
{ {
// try again with with -0.0 delta time // try again with with -0.0 delta time
position = messages.lastIndexOf (format_string cursor = ui->decodedTextBrowser->document ()->find (format_string
.arg (time_string) .arg (time_string)
.arg (snr, 3) .arg (snr, 3)
.arg ('-' + QString::number (delta_time, 'f', 1), 4) .arg ('-' + QString::number (delta_time, 'f', 1), 4)
.arg (delta_frequency, 4) .arg (delta_frequency, 4)
.arg (mode, -2) .arg (mode, -2)
.arg (message_text)); .arg (message_text), start, QTextDocument::FindBackward);
} }
if (position >= 0) if (!cursor.isNull ())
{ {
if (m_config.udpWindowToFront ()) if (m_config.udpWindowToFront ())
{ {
@ -6931,14 +7014,11 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de
showNormal (); showNormal ();
raise (); raise ();
} }
// find the linefeed at the end of the line
position = ui->decodedTextBrowser->toPlainText().indexOf(QChar::LineFeed,position);
if (message_text.contains (QRegularExpression {R"(^(CQ |CQDX |QRZ ))"})) { if (message_text.contains (QRegularExpression {R"(^(CQ |CQDX |QRZ ))"})) {
// a message we are willing to accept and auto reply to // a message we are willing to accept and auto reply to
m_bDoubleClicked = true; m_bDoubleClicked = true;
} }
auto start = messages.left (position).lastIndexOf (QChar::LineFeed) + 1; DecodedText message {message_line};
DecodedText message {messages.mid (start, position - start)};
Qt::KeyboardModifiers kbmod {modifiers << 24}; Qt::KeyboardModifiers kbmod {modifiers << 24};
processMessage (message, kbmod); processMessage (message, kbmod);
tx_watchdog (false); tx_watchdog (false);
@ -6946,7 +7026,7 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de
} }
else else
{ {
qDebug () << "process reply message ignored, decode not found:" << cqtext; qDebug () << "process reply message ignored, decode not found:" << message_line;
} }
} }
@ -6983,10 +7063,12 @@ void MainWindow::replayDecodes ()
// is not checked // is not checked
// attempt to parse the decoded text // attempt to parse the decoded text
Q_FOREACH (auto const& message for (QTextBlock block = ui->decodedTextBrowser->document ()->firstBlock (); block.isValid (); block = block.next ())
, ui->decodedTextBrowser->toPlainText ().split (QChar::LineFeed,
QString::SkipEmptyParts))
{ {
auto message = block.text ();
message = message.left (message.indexOf (QChar::Nbsp)); // discard
// any
// appended info
if (message.size() >= 4 && message.left (4) != "----") if (message.size() >= 4 && message.left (4) != "----")
{ {
auto const& parts = message.split (' ', QString::SkipEmptyParts); auto const& parts = message.split (' ', QString::SkipEmptyParts);
@ -6996,14 +7078,8 @@ void MainWindow::replayDecodes ()
} }
else else
{ {
auto eom_pos = message.indexOf (' ', 35);
// we always want at least the characters to position 35
if (eom_pos < 35)
{
eom_pos = message.size () - 1;
}
// TODO - how to skip ISCAT decodes // TODO - how to skip ISCAT decodes
postDecode (false, message.left (eom_pos + 1)); postDecode (false, message);
} }
} }
} }
@ -7607,13 +7683,9 @@ void MainWindow::write_transmit_entry (QString const& file_name)
{ {
auto const& message = tr ("Cannot open \"%1\" for append: %2") auto const& message = tr ("Cannot open \"%1\" for append: %2")
.arg (f.fileName ()).arg (f.errorString ()); .arg (f.fileName ()).arg (f.errorString ());
#if QT_VERSION >= 0x050400
QTimer::singleShot (0, [=] { // don't block guiUpdate QTimer::singleShot (0, [=] { // don't block guiUpdate
MessageBox::warning_message (this, tr ("Log File Error"), message); MessageBox::warning_message (this, tr ("Log File Error"), message);
}); });
#else
MessageBox::warning_message (this, tr ("Log File Error"), message);
#endif
} }
} }
@ -7802,9 +7874,9 @@ void MainWindow::selectHound(QString line)
if(rpt.mid(0,1) != "-" and rpt.mid(0,1) != "+") t2="+" + rpt; if(rpt.mid(0,1) != "-" and rpt.mid(0,1) != "+") t2="+" + rpt;
if(t2.length()==2) t2=t2.mid(0,1) + "0" + t2.mid(1,1); if(t2.length()==2) t2=t2.mid(0,1) + "0" + t2.mid(1,1);
t1=t1.mid(0,12) + t2; t1=t1.mid(0,12) + t2;
ui->textBrowser4->displayFoxToBeCalled(t1,"#ffffff"); // Add hound call and rpt to tb4 ui->textBrowser4->displayFoxToBeCalled(t1); // Add hound call and rpt to tb4
t1=t1 + " " + houndGrid; // Append the grid t1=t1 + " " + houndGrid; // Append the grid
m_houndQueue.enqueue(t1); // Put this hound into the queue m_houndQueue.enqueue(t1); // Put this hound into the queue
writeFoxQSO(" Sel: " + t1); writeFoxQSO(" Sel: " + t1);
QTextCursor cursor = ui->textBrowser4->textCursor(); QTextCursor cursor = ui->textBrowser4->textCursor();
cursor.setPosition(0); // Scroll to top of list cursor.setPosition(0); // Scroll to top of list

View File

@ -36,6 +36,7 @@
#include "astro.h" #include "astro.h"
#include "MessageBox.hpp" #include "MessageBox.hpp"
#include "NetworkAccessManager.hpp" #include "NetworkAccessManager.hpp"
#include "ExportCabrillo.h"
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync #define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync #define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
@ -139,6 +140,7 @@ private slots:
void on_stopButton_clicked(); void on_stopButton_clicked();
void on_actionRelease_Notes_triggered (); void on_actionRelease_Notes_triggered ();
void on_actionFT8_DXpedition_Mode_User_Guide_triggered(); void on_actionFT8_DXpedition_Mode_User_Guide_triggered();
void on_actionQuick_Start_Guide_v2_triggered();
void on_actionOnline_User_Guide_triggered(); void on_actionOnline_User_Guide_triggered();
void on_actionLocal_User_Guide_triggered(); void on_actionLocal_User_Guide_triggered();
void on_actionWide_Waterfall_triggered(); void on_actionWide_Waterfall_triggered();
@ -202,6 +204,7 @@ private slots:
void on_actionErase_FoxQSO_txt_triggered(); void on_actionErase_FoxQSO_txt_triggered();
void on_actionErase_cabrillo_log_triggered(); void on_actionErase_cabrillo_log_triggered();
void on_actionErase_wsjtx_log_adi_triggered(); void on_actionErase_wsjtx_log_adi_triggered();
void on_actionExport_Cabrillo_log_triggered();
void startTx2(); void startTx2();
void startP1(); void startP1();
void stopTx(); void stopTx();
@ -341,7 +344,6 @@ private:
QSettings * m_settings; QSettings * m_settings;
QScopedPointer<Ui::MainWindow> ui; QScopedPointer<Ui::MainWindow> ui;
// other windows
Configuration m_config; Configuration m_config;
WSPRBandHopping m_WSPR_band_hopping; WSPRBandHopping m_WSPR_band_hopping;
bool m_WSPR_tx_next; bool m_WSPR_tx_next;
@ -359,6 +361,7 @@ private:
QScopedPointer<HelpTextWindow> m_mouseCmnds; QScopedPointer<HelpTextWindow> m_mouseCmnds;
QScopedPointer<MessageAveraging> m_msgAvgWidget; QScopedPointer<MessageAveraging> m_msgAvgWidget;
QScopedPointer<ColorHighlighting> m_colorHighlighting; QScopedPointer<ColorHighlighting> m_colorHighlighting;
QScopedPointer<ExportCabrillo> m_exportCabrillo;
Transceiver::TransceiverState m_rigState; Transceiver::TransceiverState m_rigState;
Frequency m_lastDialFreq; Frequency m_lastDialFreq;
QString m_lastBand; QString m_lastBand;
@ -501,6 +504,7 @@ private:
bool m_bAutoReply; bool m_bAutoReply;
bool m_bCheckedContest; bool m_bCheckedContest;
bool m_bWarnedSplit=false; bool m_bWarnedSplit=false;
bool m_bTUmsg;
enum enum
{ {
@ -518,7 +522,9 @@ private:
NA_VHF, NA_VHF,
EU_VHF, EU_VHF,
FIELD_DAY, FIELD_DAY,
RTTY RTTY,
FOX,
HOUND
} m_nContest; //Contest type } m_nContest; //Contest type
enum {CALL, GRID, DXCC, MULT}; enum {CALL, GRID, DXCC, MULT};
@ -582,6 +588,7 @@ private:
QString m_modeTx; QString m_modeTx;
QString m_fnameWE; // save path without extension QString m_fnameWE; // save path without extension
QString m_rpt; QString m_rpt;
QString m_nextRpt;
QString m_rptSent; QString m_rptSent;
QString m_rptRcvd; QString m_rptRcvd;
QString m_qsoStart; QString m_qsoStart;
@ -599,6 +606,8 @@ private:
QString m_xSent; //Contest exchange sent QString m_xSent; //Contest exchange sent
QString m_xRcvd; //Contest exchange received QString m_xRcvd; //Contest exchange received
QString m_currentBand; QString m_currentBand;
QString m_nextCall;
QString m_nextGrid;
QSet<QString> m_pfx; QSet<QString> m_pfx;
QSet<QString> m_sfx; QSet<QString> m_sfx;
@ -694,6 +703,7 @@ private:
void fast_config(bool b); void fast_config(bool b);
void CQTxFreq(); void CQTxFreq();
void cabLog(); void cabLog();
void useNextCall();
bool isWorked(int itype, QString key, float fMHz=0, QString=""); bool isWorked(int itype, QString key, float fMHz=0, QString="");
QString save_wave_file (QString const& name QString save_wave_file (QString const& name

View File

@ -654,9 +654,15 @@ QLabel[oob=&quot;true&quot;] {
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="maximumSize"> <property name="minimumSize">
<size> <size>
<width>20</width> <width>20</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>20</height> <height>20</height>
</size> </size>
</property> </property>
@ -698,9 +704,15 @@ QLabel[oob=&quot;true&quot;] {
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="maximumSize"> <property name="minimumSize">
<size> <size>
<width>20</width> <width>20</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>20</height> <height>20</height>
</size> </size>
</property> </property>
@ -1034,6 +1046,19 @@ QLabel[oob=&quot;true&quot;] {
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1">
<widget class="QLabel" name="labNextCall">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Double-click on another caller to queue that call for your next QSO.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Next Call</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@ -2621,10 +2646,12 @@ QPushButton[state=&quot;ok&quot;] {
<addaction name="actionErase_FoxQSO_txt"/> <addaction name="actionErase_FoxQSO_txt"/>
<addaction name="actionErase_wsjtx_log_adi"/> <addaction name="actionErase_wsjtx_log_adi"/>
<addaction name="actionErase_cabrillo_log"/> <addaction name="actionErase_cabrillo_log"/>
<addaction name="actionExport_Cabrillo_log"/>
<addaction name="actionOpen_log_directory"/> <addaction name="actionOpen_log_directory"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSettings"/> <addaction name="actionSettings"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="separator"/>
<addaction name="actionExit"/> <addaction name="actionExit"/>
</widget> </widget>
<widget class="QMenu" name="menuView"> <widget class="QMenu" name="menuView">
@ -2670,6 +2697,7 @@ QPushButton[state=&quot;ok&quot;] {
<addaction name="actionOnline_User_Guide"/> <addaction name="actionOnline_User_Guide"/>
<addaction name="actionLocal_User_Guide"/> <addaction name="actionLocal_User_Guide"/>
<addaction name="actionFT8_DXpedition_Mode_User_Guide"/> <addaction name="actionFT8_DXpedition_Mode_User_Guide"/>
<addaction name="actionQuick_Start_Guide_v2"/>
<addaction name="download_samples_action"/> <addaction name="download_samples_action"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionKeyboard_shortcuts"/> <addaction name="actionKeyboard_shortcuts"/>
@ -3275,13 +3303,13 @@ QPushButton[state=&quot;ok&quot;] {
</action> </action>
<action name="actionFox_Log"> <action name="actionFox_Log">
<property name="text"> <property name="text">
<string>Fox Log</string> <string>Fox or Contest Log</string>
</property> </property>
<property name="iconText"> <property name="iconText">
<string>Fox Log</string> <string>Fox or Contest Log</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Fox Log</string> <string>Fox or Contest Log</string>
</property> </property>
</action> </action>
<action name="actionErase_FoxQSO_txt"> <action name="actionErase_FoxQSO_txt">
@ -3304,6 +3332,21 @@ QPushButton[state=&quot;ok&quot;] {
<string>Color highlighting scheme</string> <string>Color highlighting scheme</string>
</property> </property>
</action> </action>
<action name="actionContest_Log">
<property name="text">
<string>Contest Log</string>
</property>
</action>
<action name="actionExport_Cabrillo_log">
<property name="text">
<string>Export Cabrillo log</string>
</property>
</action>
<action name="actionQuick_Start_Guide_v2">
<property name="text">
<string>Quick-Start Guide to WSJT-X 2.0</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

View File

@ -20,6 +20,12 @@ MessageAveraging::MessageAveraging(QSettings * settings, QFont const& font, QWid
read_settings (); read_settings ();
if(m_title_.contains("Fox")) { if(m_title_.contains("Fox")) {
ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band");
} else if(m_title_.contains("Contest")) {
ui->header_label->setText(" Date UTC Band Call Sent Rcvd");
ui->lab1->setText("QSOs: 0");
ui->lab2->setText("Mults: 0");
ui->lab3->setText("Score: 0");
ui->lab4->setText("Rate: 0");
} else { } else {
ui->header_label->setText(" UTC Sync DT Freq "); ui->header_label->setText(" UTC Sync DT Freq ");
ui->lab1->setVisible(false); ui->lab1->setVisible(false);
@ -27,6 +33,7 @@ MessageAveraging::MessageAveraging(QSettings * settings, QFont const& font, QWid
ui->lab3->setVisible(false); ui->lab3->setVisible(false);
ui->lab4->setVisible(false); ui->lab4->setVisible(false);
} }
setWindowTitle(m_title_); setWindowTitle(m_title_);
m_nLogged_=0; m_nLogged_=0;
} }
@ -74,6 +81,7 @@ void MessageAveraging::read_settings ()
SettingsGroup group {settings_, "MessageAveraging"}; SettingsGroup group {settings_, "MessageAveraging"};
restoreGeometry (settings_->value ("window/geometry").toByteArray ()); restoreGeometry (settings_->value ("window/geometry").toByteArray ());
m_title_=settings_->value("window/title","Message Averaging").toString(); m_title_=settings_->value("window/title","Message Averaging").toString();
m_nContest_=settings_->value("nContest",0).toInt();
} }
void MessageAveraging::write_settings () void MessageAveraging::write_settings ()
@ -81,6 +89,7 @@ void MessageAveraging::write_settings ()
SettingsGroup group {settings_, "MessageAveraging"}; SettingsGroup group {settings_, "MessageAveraging"};
settings_->setValue ("window/geometry", saveGeometry ()); settings_->setValue ("window/geometry", saveGeometry ());
settings_->setValue("window/title",m_title_); settings_->setValue("window/title",m_title_);
settings_->setValue("nContest",m_nContest_);
} }
void MessageAveraging::displayAvg(QString const& t) void MessageAveraging::displayAvg(QString const& t)
@ -88,11 +97,19 @@ void MessageAveraging::displayAvg(QString const& t)
ui->msgAvgPlainTextEdit->setPlainText(t); ui->msgAvgPlainTextEdit->setPlainText(t);
} }
void MessageAveraging::foxLogSetup() void MessageAveraging::foxLogSetup(int nContest)
{ {
m_title_=QApplication::applicationName () + " - Fox Log"; if(nContest==5) {
setWindowTitle(m_title_); m_title_=QApplication::applicationName () + " - Fox Log";
ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band"); setWindowTitle(m_title_);
ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band");
}
if(nContest>0 and nContest<5) {
m_title_=QApplication::applicationName () + " - Contest Log";
setWindowTitle(m_title_);
ui->header_label->setText(" Date UTC Band Call Sent Rcvd");
}
m_nContest_=nContest;
} }
void MessageAveraging::foxLabCallers(int n) void MessageAveraging::foxLabCallers(int n)
@ -124,3 +141,19 @@ void MessageAveraging::foxAddLog(QString logLine)
t.sprintf("Logged: %d",m_nLogged_); t.sprintf("Logged: %d",m_nLogged_);
ui->lab3->setText(t); ui->lab3->setText(t);
} }
void MessageAveraging::contestAddLog(qint32 nContest, QString logLine)
{
m_nContest_=nContest;
ui->msgAvgPlainTextEdit->appendPlainText(logLine);
m_nLogged_++;
QString t;
t.sprintf("QSOs: %d",m_nLogged_);
ui->lab1->setText(t);
if(m_mult_<1) m_mult_=1;
t.sprintf("Mults: %d",m_mult_);
ui->lab2->setText(t);
int score=m_mult_*m_nLogged_;
t.sprintf("Score: %d",score);
ui->lab3->setText(t);
}

View File

@ -17,11 +17,12 @@ public:
~MessageAveraging(); ~MessageAveraging();
void displayAvg(QString const&); void displayAvg(QString const&);
void changeFont (QFont const&); void changeFont (QFont const&);
void foxLogSetup(); void foxLogSetup(int nContest);
void foxLabCallers(int n); void foxLabCallers(int n);
void foxLabQueued(int n); void foxLabQueued(int n);
void foxLabRate(int n); void foxLabRate(int n);
void foxAddLog(QString logLine); void foxAddLog(QString logLine);
void contestAddLog(qint32 nContest, QString logLine);
protected: protected:
void closeEvent (QCloseEvent *) override; void closeEvent (QCloseEvent *) override;
@ -32,7 +33,9 @@ private:
void setContentFont (QFont const&); void setContentFont (QFont const&);
QSettings * settings_; QSettings * settings_;
QString m_title_; QString m_title_;
qint32 m_nLogged_; qint32 m_nLogged_=0;
qint32 m_mult_=0;
qint32 m_nContest_;
QScopedPointer<Ui::MessageAveraging> ui; QScopedPointer<Ui::MessageAveraging> ui;
}; };

View File

@ -18,7 +18,7 @@
QDataStream& operator << (QDataStream& os, CLASS::ENUM const& v) \ QDataStream& operator << (QDataStream& os, CLASS::ENUM const& v) \
{ \ { \
auto const& mo = CLASS::staticMetaObject; \ auto const& mo = CLASS::staticMetaObject; \
return os << mo.enumerator (mo.indexOfEnumerator (#ENUM)).valueToKey (v); \ return os << mo.enumerator (mo.indexOfEnumerator (#ENUM)).valueToKey (static_cast<int> (v)); \
} \ } \
\ \
QDataStream& operator >> (QDataStream& is, CLASS::ENUM& v) \ QDataStream& operator >> (QDataStream& is, CLASS::ENUM& v) \
@ -47,35 +47,9 @@
QString enum_to_qstring (CLASS::ENUM const& m) \ QString enum_to_qstring (CLASS::ENUM const& m) \
{ \ { \
auto const& mo = CLASS::staticMetaObject; \ auto const& mo = CLASS::staticMetaObject; \
return QString {mo.enumerator (mo.indexOfEnumerator (#ENUM)).valueToKey (m)}; \ return QString {mo.enumerator (mo.indexOfEnumerator (#ENUM)).valueToKey (static_cast<int> (m))}; \
} }
#if QT_VERSION >= 0x050500
// Qt 5.5 now has Q_ENUM which registers enumns better
#define ENUM_QDEBUG_OPS_DECL(CLASS, ENUM)
#define ENUM_QDEBUG_OPS_IMPL(CLASS, ENUM)
#else
#define Q_ENUM(E)
#include <QDebug>
class QVariant;
#define ENUM_QDEBUG_OPS_DECL(CLASS, ENUM) \
QDebug operator << (QDebug, CLASS::ENUM const&);
#define ENUM_QDEBUG_OPS_IMPL(CLASS, ENUM) \
QDebug operator << (QDebug d, CLASS::ENUM const& m) \
{ \
auto const& mo = CLASS::staticMetaObject; \
return d << mo.enumerator (mo.indexOfEnumerator (#ENUM)).valueToKey (m); \
}
#endif
inline inline
void throw_qstring (QString const& qs) void throw_qstring (QString const& qs)
{ {

View File

@ -1,4 +1,5 @@
<table cellspacing=1> <table cellspacing=1>
<tr><td><b>Esc </b></td><td>Stop transmitting</td></tr>
<tr><td><b>F1 </b></td><td>Online User's Guide</td></tr> <tr><td><b>F1 </b></td><td>Online User's Guide</td></tr>
<tr><td><b>Shift+F1 </b></td><td>Copyright Notice</td></tr> <tr><td><b>Shift+F1 </b></td><td>Copyright Notice</td></tr>
<tr><td><b>Ctrl+F1 </b></td><td>About WSJT-X</td></tr> <tr><td><b>Ctrl+F1 </b></td><td>About WSJT-X</td></tr>
@ -13,9 +14,11 @@
<tr><td><b>F11 </b></td><td>Move Rx frequency down 1 Hz</td></tr> <tr><td><b>F11 </b></td><td>Move Rx frequency down 1 Hz</td></tr>
<tr><td><b>Ctrl+F11 </b></td><td>Move identical Rx and Tx frequencies down 1 Hz</td></tr> <tr><td><b>Ctrl+F11 </b></td><td>Move identical Rx and Tx frequencies down 1 Hz</td></tr>
<tr><td><b>Shift+F11 </b></td><td>Move Tx frequency down 60 Hz</td></tr> <tr><td><b>Shift+F11 </b></td><td>Move Tx frequency down 60 Hz</td></tr>
<tr><td><b>Ctrl+Shift+F11 </b></td><td>Move dial frequency down 2000 Hz</td></tr>
<tr><td><b>F12 </b></td><td>Move Rx frequency up 1 Hz</td></tr> <tr><td><b>F12 </b></td><td>Move Rx frequency up 1 Hz</td></tr>
<tr><td><b>Ctrl+F12 </b></td><td>Move identical Rx and Tx frequencies up 1 Hz</td></tr> <tr><td><b>Ctrl+F12 </b></td><td>Move identical Rx and Tx frequencies up 1 Hz</td></tr>
<tr><td><b>Shift+F12 </b></td><td>Move Tx frequency up 60 Hz</td></tr> <tr><td><b>Shift+F12 </b></td><td>Move Tx frequency up 60 Hz</td></tr>
<tr><td><b>Ctrl+Shift+F12 </b></td><td>Move dial frequency up 2000 Hz</td></tr>
<tr><td><b>Alt+1-6 </b></td><td>Set now transmission to this number on Tab 1</td></tr> <tr><td><b>Alt+1-6 </b></td><td>Set now transmission to this number on Tab 1</td></tr>
<tr><td><b>Ctl+1-6 </b></td><td>Set next transmission to this number on Tab 1</td></tr> <tr><td><b>Ctl+1-6 </b></td><td>Set next transmission to this number on Tab 1</td></tr>
<tr><td><b>Alt+D </b></td><td>Decode again at QSO frequency</td></tr> <tr><td><b>Alt+D </b></td><td>Decode again at QSO frequency</td></tr>

View File

@ -67,8 +67,8 @@ SOURCES += \
echoplot.cpp echograph.cpp fastgraph.cpp fastplot.cpp Modes.cpp \ echoplot.cpp echograph.cpp fastgraph.cpp fastplot.cpp Modes.cpp \
WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\ WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\
MultiSettings.cpp PhaseEqualizationDialog.cpp IARURegions.cpp MessageBox.cpp \ MultiSettings.cpp PhaseEqualizationDialog.cpp IARURegions.cpp MessageBox.cpp \
EqualizationToolsDialog.cpp \ EqualizationToolsDialog.cpp CallsignValidator.cpp ExchangeValidator.cpp \
colorhighlighting.cpp colorhighlighting.cpp ExportCabrillo.cpp LotWUsers.cpp
HEADERS += qt_helpers.hpp \ HEADERS += qt_helpers.hpp \
pimpl_h.hpp pimpl_impl.hpp \ pimpl_h.hpp pimpl_impl.hpp \
@ -84,8 +84,8 @@ HEADERS += qt_helpers.hpp \
logbook/logbook.h logbook/countrydat.h logbook/countriesworked.h logbook/adif.h \ logbook/logbook.h logbook/countrydat.h logbook/countriesworked.h logbook/adif.h \
messageaveraging.h echoplot.h echograph.h fastgraph.h fastplot.h Modes.hpp WSPRBandHopping.hpp \ messageaveraging.h echoplot.h echograph.h fastgraph.h fastplot.h Modes.hpp WSPRBandHopping.hpp \
WsprTxScheduler.h SampleDownloader.hpp MultiSettings.hpp PhaseEqualizationDialog.hpp \ WsprTxScheduler.h SampleDownloader.hpp MultiSettings.hpp PhaseEqualizationDialog.hpp \
IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp \ IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp CallsignValidator.hpp \
colorhighlighting.h ExchangeValidator.hpp colorhighlighting.h ExportCabrillo.h LotWUsers.h
INCLUDEPATH += qmake_only INCLUDEPATH += qmake_only
@ -97,8 +97,7 @@ HEADERS += OmniRigTransceiver.hpp
FORMS += mainwindow.ui about.ui Configuration.ui widegraph.ui astro.ui \ FORMS += mainwindow.ui about.ui Configuration.ui widegraph.ui astro.ui \
logqso.ui wf_palette_design_dialog.ui messageaveraging.ui echograph.ui \ logqso.ui wf_palette_design_dialog.ui messageaveraging.ui echograph.ui \
fastgraph.ui \ fastgraph.ui colorhighlighting.ui ExportCabrillo.ui
colorhighlighting.ui
RC_FILE = wsjtx.rc RC_FILE = wsjtx.rc
RESOURCES = wsjtx.qrc RESOURCES = wsjtx.qrc