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

View File

@ -157,7 +157,6 @@
#include <QStandardPaths>
#include <QFont>
#include <QFontDialog>
#include <QColorDialog>
#include <QSerialPortInfo>
#include <QScopedPointer>
#include <QDebug>
@ -180,6 +179,9 @@
#include "MessageBox.hpp"
#include "MaidenheadLocatorValidator.hpp"
#include "CallsignValidator.hpp"
#include "LotWUsers.hpp"
#include "ExchangeValidator.hpp"
#include "DecodeHighlightingModel.hpp"
#include "ui_Configuration.h"
#include "moc_Configuration.cpp"
@ -354,8 +356,11 @@ public:
using FrequencyDelta = Radio::FrequencyDelta;
using port_type = Configuration::port_type;
explicit impl (Configuration * self, QDir const& temp_directory,
QSettings * settings, QWidget * parent);
explicit impl (Configuration * self
, QNetworkAccessManager * network_manager
, QDir const& temp_directory
, QSettings * settings
, QWidget * parent);
~impl ();
bool have_rig ();
@ -440,22 +445,19 @@ private:
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_failure (QString const& reason);
Q_SLOT void on_pbCQmsg_clicked();
Q_SLOT void on_pbMyCall_clicked();
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_reset_highlighting_to_defaults_push_button_clicked (bool);
Q_SLOT void on_LotW_CSV_fetch_push_button_clicked (bool);
Q_SLOT void on_cbFox_clicked (bool);
Q_SLOT void on_cbHound_clicked (bool);
Q_SLOT void on_cbx2ToneSpacing_clicked(bool);
Q_SLOT void on_cbx4ToneSpacing_clicked(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 :(
Q_SIGNAL void start_transceiver (unsigned seqeunce_number) const;
@ -471,6 +473,7 @@ private:
QScopedPointer<Ui::configuration_dialog> ui_;
QNetworkAccessManager * network_manager_;
QSettings * settings_;
QDir doc_dir_;
@ -488,6 +491,8 @@ private:
QFont decoded_text_font_;
QFont next_decoded_text_font_;
LotWUsers lotw_users_;
bool restart_sound_input_device_;
bool restart_sound_output_device_;
@ -516,10 +521,14 @@ private:
QAction * reset_frequencies_action_;
FrequencyDialog * frequency_dialog_;
QAction * station_delete_action_;
QAction * station_insert_action_;
QAction station_delete_action_;
QAction station_insert_action_;
StationDialog * station_dialog_;
DecodeHighlightingModel decode_highlighing_model_;
DecodeHighlightingModel next_decode_highlighing_model_;
int LotW_days_since_upload_;
TransceiverFactory::ParameterPack rig_params_;
TransceiverFactory::ParameterPack saved_rig_params_;
TransceiverFactory::Capabilities::PortType last_port_type_;
@ -539,26 +548,6 @@ private:
QString my_grid_;
QString FD_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 ntrials_;
@ -574,6 +563,7 @@ private:
bool log_as_RTTY_;
bool report_in_comments_;
bool prompt_to_log_;
bool autoLog_;
bool insert_blank_;
bool DXCC_;
bool ppfx_;
@ -602,13 +592,9 @@ private:
QString opCall_;
QString udp_server_name_;
port_type udp_server_port_;
// QString n1mm_server_name () const;
QString n1mm_server_name_;
port_type n1mm_server_port_;
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 udpWindowToFront_;
bool udpWindowRestore_;
@ -630,9 +616,9 @@ private:
// delegate to implementation class
Configuration::Configuration (QDir const& temp_directory,
Configuration::Configuration (QNetworkAccessManager * network_manager, QDir const& temp_directory,
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_;}
auto Configuration::type_2_msg_gen () const -> Type2MsgGen {return m_->type_2_msg_gen_;}
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::decoded_text_font () const {return m_->decoded_text_font_;}
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::report_in_comments () const {return m_->report_in_comments_;}
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::DXCC () const {return m_->DXCC_;}
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;}
bool Configuration::pwrBandTxMemory () const {return m_->pwrBandTxMemory_;}
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)
{
@ -906,17 +885,19 @@ namespace
}
}
Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
QSettings * settings, QWidget * parent)
Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network_manager
, QDir const& temp_directory, QSettings * settings, QWidget * parent)
: QDialog {parent}
, self_ {self}
, transceiver_thread_ {nullptr}
, ui_ {new Ui::configuration_dialog}
, network_manager_ {network_manager}
, settings_ {settings}
, doc_dir_ {doc_path ()}
, data_dir_ {data_path ()}
, temp_dir_ {temp_directory}
, writeable_data_dir_ {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}
, lotw_users_ {network_manager_}
, restart_sound_input_device_ {false}
, restart_sound_output_device_ {false}
, frequencies_ {&bands_}
@ -926,7 +907,10 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
, current_offset_ {0}
, current_tx_offset_ {0}
, 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}}
, LotW_days_since_upload_ {0}
, last_port_type_ {TransceiverFactory::Capabilities::none}
, rig_is_dummy_ {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
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
//
ui_->callsign_line_edit->setValidator (new CallsignValidator {this});
ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {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->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_);
connect (reset_frequencies_action_, &QAction::triggered, this, &Configuration::impl::reset_frequencies);
//
// setup stations table model & view
//
stations_.sort (StationList::band_column);
ui_->stations_table_view->setModel (&next_stations_);
ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder);
// delegates
// stations delegates
auto stations_item_delegate = new QStyledItemDelegate {this};
stations_item_delegate->setItemEditorFactory (item_editor_factory ());
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});
// actions
station_delete_action_ = new QAction {tr ("&Delete"), ui_->stations_table_view};
ui_->stations_table_view->insertAction (nullptr, station_delete_action_);
connect (station_delete_action_, &QAction::triggered, this, &Configuration::impl::delete_stations);
// stations actions
ui_->stations_table_view->addAction (&station_delete_action_);
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->insertAction (nullptr, station_insert_action_);
connect (station_insert_action_, &QAction::triggered, this, &Configuration::impl::insert_station);
ui_->stations_table_view->addAction (&station_insert_action_);
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
@ -1181,16 +1175,6 @@ void Configuration::impl::initialize_models ()
ui_->callsign_line_edit->setText (my_callsign_);
ui_->grid_line_edit->setText (my_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_->sbNtrials->setValue (ntrials_);
ui_->sbTxDelay->setValue (txDelay_);
@ -1208,6 +1192,7 @@ void Configuration::impl::initialize_models ()
ui_->log_as_RTTY_check_box->setChecked (log_as_RTTY_);
ui_->report_in_comments_check_box->setChecked (report_in_comments_);
ui_->prompt_to_log_check_box->setChecked (prompt_to_log_);
ui_->cbAutoLog->setChecked(autoLog_);
ui_->insert_blank_check_box->setChecked (insert_blank_);
ui_->DXCC_check_box->setChecked (DXCC_);
ui_->ppfx_check_box->setChecked (ppfx_);
@ -1291,6 +1276,9 @@ void Configuration::impl::initialize_models ()
next_frequencies_.frequency_list (frequencies_.frequency_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 ();
}
@ -1314,16 +1302,6 @@ void Configuration::impl::read_settings ()
RTTY_exchange_ = settings_->value ("RTTYExchange",QString {}).toString ();
ui_->FieldDay_Exchange->setText(FD_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 ())
&& next_font_ != font_)
{
@ -1338,6 +1316,8 @@ void Configuration::impl::read_settings ()
&& next_decoded_text_font_ != 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_);
}
else
@ -1441,6 +1421,10 @@ void Configuration::impl::read_settings ()
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 ();
report_in_comments_ = settings_->value("dBtoComments", false).toBool ();
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 ();
data_mode_ = settings_->value ("DataMode", QVariant::fromValue (data_mode_none)).value<Configuration::DataMode> ();
prompt_to_log_ = settings_->value ("PromptToLog", false).toBool ();
autoLog_ = settings_->value ("AutoLog", false).toBool ();
insert_blank_ = settings_->value ("InsertBlank", false).toBool ();
DXCC_ = settings_->value ("DXCCEntity", false).toBool ();
ppfx_ = settings_->value ("PrincipalPrefix", false).toBool ();
@ -1510,16 +1495,6 @@ void Configuration::impl::write_settings ()
settings_->setValue ("MyGrid", my_grid_);
settings_->setValue ("FieldDayExchange", FD_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 ("DecodedTextFont", decoded_text_font_.toString ());
settings_->setValue ("IDint", id_interval_);
@ -1561,6 +1536,8 @@ void Configuration::impl::write_settings ()
settings_->setValue ("Macros", macros_.stringList ());
settings_->setValue ("FrequenciesForRegionModes", QVariant::fromValue (frequencies_.frequency_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 ("dBtoComments", report_in_comments_);
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 ("DataMode", QVariant::fromValue (data_mode_));
settings_->setValue ("PromptToLog", prompt_to_log_);
settings_->setValue ("AutoLog", autoLog_);
settings_->setValue ("InsertBlank", insert_blank_);
settings_->setValue ("DXCCEntity", DXCC_);
settings_->setValue ("PrincipalPrefix", ppfx_);
@ -1883,20 +1861,11 @@ void Configuration::impl::accept ()
if (next_decoded_text_font_ != 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_);
}
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
// related configuration parameters
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 ();
report_in_comments_ = ui_->report_in_comments_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 ();
DXCC_ = ui_->DXCC_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 ();
auto new_n1mm_server = ui_->n1mm_server_name_line_edit->text ();
n1mm_server_name_ = new_n1mm_server;
auto new_n1mm_port = ui_->n1mm_server_port_spin_box->value ();
n1mm_server_port_ = new_n1mm_port;
n1mm_server_name_ = ui_->n1mm_server_name_line_edit->text ();
n1mm_server_port_ = ui_->n1mm_server_port_spin_box->value ();
broadcast_to_n1mm_ = ui_->enable_n1mm_broadcast_check_box->isChecked ();
udpWindowToFront_ = ui_->udpWindowToFront->isChecked ();
@ -2066,10 +2034,18 @@ void Configuration::impl::accept ()
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);
}
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_ )
{
// 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);
}
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 (new_color.isValid ())
if (MessageBox::Yes == MessageBox::query_message (this
, tr ("Reset Decode Highlighting")
, tr ("Reset all decode highlighting and priorities to default values")))
{
next_color_CQ_ = new_color;
ui_->labCQ->setStyleSheet(QString("background: %1").arg(next_color_CQ_.name()));
next_decode_highlighing_model_.items (DecodeHighlightingModel::default_items ());
}
}
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");
if (new_color.isValid ())
{
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()));
lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text (), true);
ui_->LotW_CSV_fetch_push_button->setEnabled (false);
}
void Configuration::impl::on_decoded_text_font_push_button_clicked ()
{
next_decoded_text_font_ = QFontDialog::getFont (0, decoded_text_font_ , this
, tr ("WSJT-X Decoded Text Font Chooser")
#if QT_VERSION >= 0x050201
, 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 ());
}
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 */)
{
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
}
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)
{
if(checked) {
@ -2598,11 +2489,10 @@ void Configuration::impl::on_cbHound_clicked (bool checked)
void Configuration::impl::chk77()
{
bool b77OK = !ui_->cbFox->isChecked() and !ui_->cbHound->isChecked();
ui_->groupBox_8->setEnabled(b77OK);
ui_->groupBox_9->setEnabled(b77OK);
if(!b77OK) {
ui_->cbGenerate77->setChecked(false);
ui_->cbDecode77->setChecked(false);
ui_->cbGenerate77->setChecked(true);
ui_->cbDecode77->setChecked(true);
}
}
@ -2611,6 +2501,16 @@ void Configuration::impl::on_rbNone_toggled(bool b)
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)
{
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));
}
#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, Type2MsgGen);

View File

@ -16,11 +16,14 @@ class QWidget;
class QAudioDeviceInfo;
class QString;
class QDir;
class QNetworkAccessManager;
class Bands;
class FrequencyList_v2;
class StationList;
class QStringListModel;
class QHostAddress;
class LotWUsers;
class DecodeHighlightingModel;
//
// Class Configuration
@ -56,7 +59,6 @@ class Configuration final
: public QObject
{
Q_OBJECT
Q_ENUMS (DataMode Type2MsgGen)
public:
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};
Q_ENUM (Type2MsgGen)
explicit Configuration (QDir const& temp_directory, QSettings * settings,
explicit Configuration (QNetworkAccessManager *, QDir const& temp_directory, QSettings * settings,
QWidget * parent = nullptr);
~Configuration ();
@ -115,6 +117,7 @@ public:
bool log_as_RTTY () const;
bool report_in_comments () const;
bool prompt_to_log () const;
bool autoLog() const;
bool insert_blank () const;
bool DXCC () const;
bool ppfx() const;
@ -169,18 +172,10 @@ public:
QDir azel_directory () const;
QString rig_name () 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 pwrBandTuneMemory () const;
LotWUsers const& lotw_users () const;
DecodeHighlightingModel const& decode_highlighting () const;
struct CalibrationParams
{
@ -239,8 +234,6 @@ public:
Q_SLOT void transceiver_tx_frequency (Frequency = 0u);
// Set transceiver mode.
//
// Rationalise means ensure TX uses same mode as RX.
Q_SLOT void transceiver_mode (MODE);
// Set/unset PTT.
@ -265,15 +258,17 @@ public:
// These signals indicate a font has been selected and accepted for
// the application text and decoded text respectively.
//
Q_SIGNAL void text_font_changed (QFont);
Q_SIGNAL void decoded_text_font_changed (QFont);
Q_SIGNAL void text_font_changed (QFont) const;
Q_SIGNAL void decoded_text_font_changed (QFont) const;
//
// This signal is emitted when the UDP server changes
//
Q_SIGNAL void udp_server_changed (QString const& udp_server);
Q_SIGNAL void udp_server_port_changed (port_type server_port);
Q_SIGNAL void udp_server_changed (QString const& udp_server) const;
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
@ -295,16 +290,6 @@ private:
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, Type2MsgGen);

View File

@ -74,7 +74,7 @@
<item row="0" column="1">
<widget class="QLineEdit" name="grid_line_edit">
<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>
</widget>
</item>
@ -103,7 +103,11 @@
</widget>
</item>
<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>
</layout>
</item>
@ -1700,26 +1704,12 @@ QListView::item:hover {
<property name="text">
<string>Op Call:</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 name="buddy">
<cstring>opCallEntry</cstring>
</property>
</widget>
</item>
<item row="1" 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">
<item row="3" column="0">
<widget class="QCheckBox" name="report_in_comments_check_box">
<property name="toolTip">
<string>Some logging programs will not accept the type of reports
@ -1732,7 +1722,7 @@ comments field.</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="clear_DX_check_box">
<property name="toolTip">
<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>
</widget>
</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>
</widget>
</item>
@ -1895,6 +1912,9 @@ for assessing propagation and system performance.</string>
<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>
</property>
<property name="buddy">
<cstring>n1mm_server_name_line_edit</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
@ -1909,6 +1929,9 @@ for assessing propagation and system performance.</string>
<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>
</property>
<property name="buddy">
<cstring>n1mm_server_port_spin_box</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
@ -2152,8 +2175,158 @@ Right click for insert and delete options.</string>
<attribute name="title">
<string>Colors</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_5" rowstretch="1,0,0" columnstretch="1,0,0">
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_7">
<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">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -2166,317 +2339,6 @@ Right click for insert and delete options.</string>
</property>
</spacer>
</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>
</widget>
<widget class="QWidget" name="advanced_tab">
@ -2560,6 +2422,9 @@ Right click for insert and delete options.</string>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
<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">
<string>Always generate 77-bit messages</string>
</property>
@ -2567,6 +2432,9 @@ Right click for insert and delete options.</string>
</item>
<item>
<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">
<string>Decode only 77-bit messages</string>
</property>
@ -2759,6 +2627,9 @@ Right click for insert and delete options.</string>
<layout class="QGridLayout" name="gridLayout_15" columnstretch="1,2,1,0">
<item row="0" column="0">
<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">
<string>None</string>
</property>
@ -2775,6 +2646,9 @@ Right click for insert and delete options.</string>
<verstretch>0</verstretch>
</sizepolicy>
</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">
<string>EU VHF Contest</string>
</property>
@ -2784,6 +2658,9 @@ Right click for insert and delete options.</string>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="2,1,1">
<item>
<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">
<string>ARRL RTTY Roundup</string>
</property>
@ -2805,7 +2682,7 @@ Right click for insert and delete options.</string>
<item>
<layout class="QFormLayout" name="formLayout_17">
<item row="0" column="0">
<widget class="QLabel" name="label_15">
<widget class="QLabel" name="labRTTY">
<property name="text">
<string>Exch:</string>
</property>
@ -2822,6 +2699,9 @@ Right click for insert and delete options.</string>
<height>0</height>
</size>
</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">
<string>NJ</string>
</property>
@ -2838,6 +2718,9 @@ Right click for insert and delete options.</string>
<layout class="QHBoxLayout" name="horizontalLayout_17" stretch="2,1,1">
<item>
<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">
<string>ARRL Field Day</string>
</property>
@ -2859,7 +2742,7 @@ Right click for insert and delete options.</string>
<item>
<layout class="QFormLayout" name="formLayout_16">
<item row="0" column="0">
<widget class="QLabel" name="label_14">
<widget class="QLabel" name="labFD">
<property name="text">
<string>Exch:</string>
</property>
@ -2876,6 +2759,9 @@ Right click for insert and delete options.</string>
<height>0</height>
</size>
</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">
<string>6A SNJ</string>
</property>
@ -2896,6 +2782,9 @@ Right click for insert and delete options.</string>
<verstretch>0</verstretch>
</sizepolicy>
</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">
<string>NA VHF Contest</string>
</property>
@ -2937,9 +2826,7 @@ Right click for insert and delete options.</string>
<item>
<widget class="QDialogButtonBox" name="configuration_dialog_button_box">
<property name="toolTip">
<string>Discard or apply configuration changes including
resetting the radio interface and applying any
soundcard changes</string>
<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>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -2951,36 +2838,49 @@ soundcard changes</string>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>DecodeHighlightingListView</class>
<extends>QListView</extends>
<header>DecodehigHlightingListView.hpp</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>configuration_tabs</tabstop>
<tabstop>callsign_line_edit</tabstop>
<tabstop>grid_line_edit</tabstop>
<tabstop>use_dynamic_grid</tabstop>
<tabstop>region_combo_box</tabstop>
<tabstop>type_2_msg_gen_combo_box</tabstop>
<tabstop>insert_blank_check_box</tabstop>
<tabstop>miles_check_box</tabstop>
<tabstop>TX_messages_check_box</tabstop>
<tabstop>DXCC_check_box</tabstop>
<tabstop>ppfx_check_box</tabstop>
<tabstop>font_push_button</tabstop>
<tabstop>decoded_text_font_push_button</tabstop>
<tabstop>monitor_off_check_box</tabstop>
<tabstop>monitor_last_used_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>enable_VHF_features_check_box</tabstop>
<tabstop>tx_QSY_check_box</tabstop>
<tabstop>single_decode_check_box</tabstop>
<tabstop>decode_at_52s_check_box</tabstop>
<tabstop>tx_watchdog_spin_box</tabstop>
<tabstop>CW_id_interval_spin_box</tabstop>
<tabstop>rig_combo_box</tabstop>
<tabstop>CAT_poll_interval_spin_box</tabstop>
<tabstop>CAT_port_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_8_bit_radio_button</tabstop>
<tabstop>CAT_default_stop_bit_radio_button</tabstop>
<tabstop>CAT_one_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_xon_radio_button</tabstop>
<tabstop>CAT_handshake_hardware_radio_button</tabstop>
@ -3014,29 +2914,48 @@ soundcard changes</string>
<tabstop>delete_macro_push_button</tabstop>
<tabstop>macros_list_view</tabstop>
<tabstop>prompt_to_log_check_box</tabstop>
<tabstop>cbAutoLog</tabstop>
<tabstop>log_as_RTTY_check_box</tabstop>
<tabstop>report_in_comments_check_box</tabstop>
<tabstop>clear_DX_check_box</tabstop>
<tabstop>opCallEntry</tabstop>
<tabstop>psk_reporter_check_box</tabstop>
<tabstop>udp_server_line_edit</tabstop>
<tabstop>udp_server_port_spin_box</tabstop>
<tabstop>accept_udp_requests_check_box</tabstop>
<tabstop>udpWindowToFront</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_intercept_spin_box</tabstop>
<tabstop>frequencies_table_view</tabstop>
<tabstop>stations_table_view</tabstop>
<tabstop>pbCQmsg</tabstop>
<tabstop>pbMyCall</tabstop>
<tabstop>pbTxMsg</tabstop>
<tabstop>pbNewDXCC</tabstop>
<tabstop>highlighting_list_view</tabstop>
<tabstop>reset_highlighting_to_defaults_push_button</tabstop>
<tabstop>LotW_CSV_URL_line_edit</tabstop>
<tabstop>LotW_CSV_fetch_push_button</tabstop>
<tabstop>LotW_days_since_upload_spin_box</tabstop>
<tabstop>sbNtrials</tabstop>
<tabstop>sbAggressive</tabstop>
<tabstop>cbTwoPass</tabstop>
<tabstop>sbDegrade</tabstop>
<tabstop>sbBandwidth</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>
<resources/>
<connections>
@ -3106,12 +3025,12 @@ soundcard changes</string>
</connection>
</connections>
<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="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"/>
</buttongroups>
</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
//
auto settings_file_name = QStandardPaths::locate (
#if QT_VERSION >= 0x050500
QStandardPaths::AppConfigLocation
#else
QStandardPaths::ConfigLocation
#endif
auto settings_file_name = QStandardPaths::locate (QStandardPaths::AppConfigLocation
, "hamlib_settings.json");
if (!settings_file_name.isEmpty ())
{

View File

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

View File

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

View File

@ -29,8 +29,6 @@ class IARURegions final
: public QAbstractListModel
{
Q_OBJECT
Q_ENUMS (Region)
public:
//
// This enumeration contains the supported regions, to complement
@ -62,19 +60,6 @@ public:
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_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)
, [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
// stops doing this
// spuriously

View File

@ -13,7 +13,7 @@
#include "TransceiverFactory.hpp"
#include "WFPalette.hpp"
#include "IARURegions.hpp"
#include "DecodeHighlightingModel.hpp"
#include "FrequencyLineEdit.hpp"
QItemEditorFactory * item_editor_factory ()
@ -47,10 +47,6 @@ void register_types ()
qRegisterMetaType<AudioDevice::Channel> ("AudioDevice::Channel");
// Configuration
#if QT_VERSION < 0x050500
qRegisterMetaType<Configuration::DataMode> ("Configuration::DataMode");
qRegisterMetaType<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen");
#endif
qRegisterMetaTypeStreamOperators<Configuration::DataMode> ("Configuration::DataMode");
qRegisterMetaTypeStreamOperators<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen");
@ -62,17 +58,8 @@ void register_types ()
// Transceiver
qRegisterMetaType<Transceiver::TransceiverState> ("Transceiver::TransceiverState");
qRegisterMetaType<Transceiver::MODE> ("Transceiver::MODE");
// 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::StopBits> ("TransceiverFactory::StopBits");
qRegisterMetaTypeStreamOperators<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake");
@ -84,8 +71,9 @@ void register_types ()
qRegisterMetaTypeStreamOperators<WFPalette::Colours> ("Colours");
// IARURegions
#if QT_VERSION < 0x050500
qRegisterMetaType<IARURegions::Region> ("IARURegions::Region");
#endif
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;
}
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (Modes, Mode);
#endif
ENUM_QDATASTREAM_OPS_IMPL (Modes, Mode);
ENUM_CONVERSION_OPS_IMPL (Modes, Mode);

View File

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

View File

@ -6,18 +6,9 @@
#include <QString>
#include <QFile>
#include <QTextStream>
#include <QMessageLogContext>
#include <QDateTime>
#include <QMutex>
#include <QMutexLocker>
#include "pimpl_impl.hpp"
namespace
{
QMutex lock;
}
class TraceFile::impl
{
public:
@ -81,35 +72,8 @@ TraceFile::impl::~impl ()
// write Qt messages to the diagnostic log file
void TraceFile::impl::message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg)
{
char const * severity;
switch (type)
{
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;
}
Q_ASSERT_X (current_stream_, "TraceFile:message_handler", "no stream to write to");
*current_stream_ << qFormatLogMessage (type, context, msg) << endl;
if (QtFatalMsg == type)
{

View File

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

View File

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

View File

@ -197,15 +197,6 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
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, StopBits);
ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, Handshake);

View File

@ -21,7 +21,6 @@ class TransceiverFactory
: public QObject
{
Q_OBJECT
Q_ENUMS (DataBits StopBits Handshake PTTMethod TXAudioSource SplitMode)
public:
//
@ -161,28 +160,6 @@ bool operator != (TransceiverFactory::ParameterPack const& lhs, TransceiverFacto
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, StopBits);
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, Handshake);

View File

@ -2,5 +2,5 @@
set (WSJTX_VERSION_MAJOR 2)
set (WSJTX_VERSION_MINOR 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

View File

@ -1,23 +1,28 @@
#include "colorhighlighting.h"
#include "ui_colorhighlighting.h"
#include "SettingsGroup.hpp"
#include <QApplication>
#include <QDebug>
ColorHighlighting::ColorHighlighting(QSettings *settings, QWidget *parent) :
QDialog(parent),
settings_ {settings},
ui(new Ui::ColorHighlighting)
#include "SettingsGroup.hpp"
#include "DecodeHighlightingModel.hpp"
#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);
setWindowTitle (QApplication::applicationName () + " - Colors");
read_settings ();
set_items (highlight_model);
}
ColorHighlighting::~ColorHighlighting()
{
if (isVisible ()) write_settings ();
delete ui;
}
void ColorHighlighting::read_settings ()
@ -32,21 +37,68 @@ void ColorHighlighting::write_settings ()
settings_->setValue ("window/geometry", saveGeometry ());
}
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)
void ColorHighlighting::set_items (DecodeHighlightingModel const& highlighting_model)
{
setWindowTitle(QApplication::applicationName() + " - Colors");
ui->label->setStyleSheet(QString("background: %1").arg(color_CQ.name()));
ui->label_3->setStyleSheet(QString("background: %1").arg(color_MyCall.name()));
ui->label_5->setStyleSheet(QString("background: %1").arg(color_TxMsg.name()));
ui->label_7->setStyleSheet(QString("background: %1").arg(color_DXCC.name()));
ui->label_9->setStyleSheet(QString("background: %1").arg(color_DXCCband.name()));
ui->label_11->setStyleSheet(QString("background: %1").arg(color_NewCall.name()));
ui->label_13->setStyleSheet(QString("background: %1").arg(color_NewCallBand.name()));
ui->label_15->setStyleSheet(QString("background: %1").arg(color_NewGrid.name()));
ui->label_17->setStyleSheet(QString("background: %1").arg(color_NewGridBand.name()));
ui->label_19->setStyleSheet(QString("color: %1").arg(color_LoTW.name()));
int index {0};
for (auto const& item : highlighting_model.items ())
{
QLabel * example;
QLabel * label;
switch (index++)
{
case 0:
example = ui->example1_label;
label = ui->p1_label;
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
#define COLORHIGHLIGHTING_H
#ifndef COLORHIGHLIGHTING_H_
#define COLORHIGHLIGHTING_H_
#include <QDialog>
#include <QSettings>
#include <QScopedPointer>
class QSettings;
class DecodeHighlightingModel;
namespace Ui {
class ColorHighlighting;
class ColorHighlighting;
}
class ColorHighlighting : public QDialog
class ColorHighlighting final
: public QDialog
{
Q_OBJECT
Q_OBJECT;
public:
explicit ColorHighlighting(QSettings *, QWidget *parent = 0);
~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);
public:
explicit ColorHighlighting(QSettings *, DecodeHighlightingModel const&, QWidget * parent = nullptr);
~ColorHighlighting ();
private:
QSettings * settings_;
Q_SLOT void set_items (DecodeHighlightingModel const&);
private:
void read_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>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="6" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Transmitted message</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_14">
<property name="text">
<string>New Call on Band</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_12">
<property name="text">
<string>New Call</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_16">
<property name="text">
<string>New Grid</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_18">
<property name="text">
<string>New Grid on Band</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_9">
<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="label_2">
<property name="text">
<string>CQ in message</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>My Call in message</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>K1ABC</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
<string>New DXCC on Band</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>New DXCC</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_19">
<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="label_20">
<property name="text">
<string>Not in LoTW</string>
</property>
</widget>
</item>
</layout>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="example1_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="0" column="1">
<widget class="QLabel" name="p1_label">
<property name="text">
<string>CQ in message</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="example2_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="1" column="1">
<widget class="QLabel" name="p2_label">
<property name="text">
<string>My Call in message</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="example3_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="2" column="1">
<widget class="QLabel" name="p3_label">
<property name="text">
<string>Transmitted message</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="example4_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="3" column="1">
<widget class="QLabel" name="p4_label">
<property name="text">
<string>New DXCC</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="example5_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="4" column="1">
<widget class="QLabel" name="p5_label">
<property name="text">
<string>New DXCC on Band</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="example6_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="5" column="1">
<widget class="QLabel" name="p6_label">
<property name="text">
<string>New Grid</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="example7_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="6" column="1">
<widget class="QLabel" name="p7_label">
<property name="text">
<string>New Grid on Band</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="example8_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="7" column="1">
<widget class="QLabel" name="p8_label">
<property name="text">
<string>New Call</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="example9_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="8" column="1">
<widget class="QLabel" name="p9_label">
<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>
</layout>
</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
{
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");
}

View File

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

View File

@ -1,5 +1,4 @@
#include "displaytext.h"
#include "mainwindow.h"
#include <QMouseEvent>
#include <QDateTime>
#include <QTextCharFormat>
@ -8,12 +7,16 @@
#include <QMenu>
#include <QAction>
#include "qt_helpers.hpp"
#include "Configuration.hpp"
#include "LotWUsers.hpp"
#include "DecodeHighlightingModel.hpp"
#include "qt_helpers.hpp"
#include "moc_displaytext.cpp"
DisplayText::DisplayText(QWidget *parent)
: QTextEdit(parent)
, m_config {nullptr}
, erase_action_ {new QAction {tr ("&Erase"), this}}
{
setReadOnly (true);
@ -73,13 +76,53 @@ void DisplayText::insertLineSpacer(QString const& line)
appendText (line, "#d3d3d3");
}
void DisplayText::appendText(QString const& text, QColor bg,
QString const& call1, QString const& call2)
namespace
{
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 ();
cursor.movePosition (QTextCursor::End);
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 ())
{
cursor.setBlockFormat (block_format);
@ -90,10 +133,13 @@ void DisplayText::appendText(QString const& text, QColor bg,
else
{
cursor.insertBlock (block_format);
auto char_format = cursor.charFormat ();
char_format.clearBackground ();
char_format.clearForeground ();
cursor.setCharFormat (char_format);
}
QTextCharFormat format = cursor.charFormat();
format.clearBackground();
int text_index {0};
if (call1.size ())
{
@ -126,7 +172,7 @@ void DisplayText::appendText(QString const& text, QColor bg,
if (pos != highlighted_calls_.end ())
{
format.setBackground (bg);
format.clearForeground ();
format.setForeground (fg);
cursor.insertText(text.mid (text_index, call_index - text_index), format);
if (pos.value ().second.isValid ())
{
@ -141,11 +187,14 @@ void DisplayText::appendText(QString const& text, QColor bg,
}
}
}
format.setBackground (bg);
format.clearForeground ();
if(call2.size()>0 and !m_LoTW.contains(call2)) {
format.setForeground(m_color_LoTW); //Mark LoTW non-users
}
if (call2.size () && m_config && m_config->lotw_users ().user (call2))
{
QColor bg;
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);
// 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,
QColor * bg, LogBook const& logBook, QString currentBand)
QColor * bg, QColor * fg, LogBook const& logBook, QString currentBand)
{
// allow for seconds
int padding {message.indexOf (" ") > 4 ? 2 : 0};
@ -191,29 +240,29 @@ QString DisplayText::appendWorkedB4(QString message, QString const& callsign, QS
if (!countryWorkedBefore) {
// therefore not worked call either
// appendage += "!";
*bg = m_color_DXCC;
// appendage += "!";
set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::CQ);
} else {
if(!countryB4onBand) {
*bg = m_color_DXCCband;
set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::DXCCBand);
} else {
if(!gridB4) {
*bg = m_color_NewGrid;
set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::Grid);
} else {
if(!gridB4onBand) {
*bg = m_color_NewGridBand;
set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::GridBand);
} else {
if (!callWorkedBefore) {
// but have worked the country
// appendage += "~";
*bg = m_color_NewCall;
set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::Call);
} else {
if(!callB4onBand) {
// appendage += "~";
*bg = m_color_NewCallBand;
set_colours (m_config, bg, fg, DecodeHighlightingModel::Highlight::CallBand);
} else {
// 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)
{
m_bPrincipalPrefix=ppfx;
QColor bg {Qt::transparent};
QColor bg;
QColor fg;
bool CQcall = false;
if (decodedText.string ().contains (" CQ ")
|| decodedText.string ().contains (" CQDX ")
|| decodedText.string ().contains (" QRZ "))
{
CQcall = true;
bg = m_color_CQ;
set_colours (m_config, &bg, &fg, DecodeHighlightingModel::Highlight::CQ);
}
if(bCQonly and !CQcall) return;
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)) {
bg = m_color_MyCall;
set_colours (m_config, &bg, &fg, DecodeHighlightingModel::Highlight::MyCall);
}
auto message = decodedText.string();
QString dxCall;
@ -296,8 +346,8 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
if (displayDXCCEntity && CQcall)
// if enabled add the DXCC entity and B4 status to the end of the
// preformated text line t1
message = appendWorkedB4 (message, decodedText.CQersCall(), dxGrid, &bg, logBook, currentBand);
appendText (message.trimmed (), bg, decodedText.call (), dxCall);
message = appendWorkedB4 (message, decodedText.CQersCall(), dxGrid, &bg, &fg, logBook, currentBand);
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") + \
" 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)
@ -330,9 +383,9 @@ void DisplayText::displayQSY(QString text)
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
@ -428,20 +481,3 @@ void DisplayText::highlight_callsign (QString const& callsign, QColor const& bg,
}
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"
class QAction;
class Configuration;
class DisplayText
: public QTextEdit
@ -19,7 +20,7 @@ class DisplayText
Q_OBJECT
public:
explicit DisplayText(QWidget *parent = 0);
void set_configuration (Configuration const * configuration) {m_config = configuration;}
void setContentFont (QFont const&);
void insertLineSpacer(QString const&);
void displayDecodedText(DecodedText const& decodedText, QString const& myCall,
@ -27,16 +28,12 @@ public:
QString currentBand="", bool ppfx=false, bool bCQonly=false);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode);
void displayQSY(QString text);
void displayFoxToBeCalled(QString t, QColor bg);
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);
void displayFoxToBeCalled(QString t, QColor bg = QColor {}, QColor fg = QColor {});
Q_SIGNAL void selectCallsign (Qt::KeyboardModifiers);
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 {});
Q_SLOT void erase ();
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);
private:
Configuration const * m_config;
bool m_bPrincipalPrefix;
QString appendWorkedB4(QString message, QString const& callsign, QString grid, QColor * bg,
LogBook const& logBook, QString currentBand);
QString appendWorkedB4(QString message, QString const& callsign
, QString grid, QColor * bg, QColor * fg
, LogBook const& logBook, QString currentBand);
QFont char_font_;
QAction * erase_action_;
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;

View File

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

View File

@ -1,6 +1,6 @@
gfortran -c ../packjt.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 \
../to_contest_msg.f90 ../fmtmsg.f90 ../azdist.f90 ../geodist.f90 \
packjt.o packjt77.o

View File

@ -17,10 +17,7 @@ subroutine hash10(n10,c13)
do i=1,nzhash
if(ihash10(i).eq.n10) then
c13=callsign(i)
if(c13(1:1).ne.'<') then
n=len(trim(c13))
c13='<'//trim(c13)//'>'//' '
endif
c13='<'//trim(c13)//'>'//' '
go to 900
endif
enddo
@ -36,10 +33,7 @@ subroutine hash12(n12,c13)
do i=1,nzhash
if(ihash12(i).eq.n12) then
c13=callsign(i)
if(c13(1:1).ne.'<') then
n=len(trim(c13))
c13='<'//trim(c13)//'>'//' '
endif
c13='<'//trim(c13)//'>'//' '
go to 900
endif
enddo
@ -56,10 +50,7 @@ subroutine hash22(n22,c13)
do i=1,nzhash
if(ihash22(i).eq.n22) then
c13=callsign(i)
if(c13(1:1).ne.'<') then
n=len(trim(c13))
c13='<'//trim(c13)//'>'//' '
endif
c13='<'//trim(c13)//'>'//' '
go to 900
endif
enddo
@ -71,17 +62,13 @@ end subroutine hash22
integer function ihashcall(c0,m)
integer*8 n8
character*13 c0,c1
character*13 c0
character*38 c
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
c1=c0
if(c1(1:1).eq.'<') c1=c1(2:)
i=index(c1,'>')
if(i.gt.0) c1(i:)=' '
n8=0
do i=1,11
j=index(c,c1(i:i)) - 1
j=index(c,c0(i:i)) - 1
n8=38*n8 + j
enddo
ihashcall=ishft(47055833459_8*n8,m-64)
@ -91,7 +78,7 @@ end function ihashcall
subroutine save_hash_call(c13,n10,n12,n22)
character*13 c13
character*13 c13,cw
logical first
data first/.true./
save first
@ -104,12 +91,16 @@ subroutine save_hash_call(c13,n10,n12,n22)
nzhash=0
first=.false.
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)
n12=ihashcall(c13,12)
n22=ihashcall(c13,22)
n10=ihashcall(cw,10)
n12=ihashcall(cw,12)
n22=ihashcall(cw,22)
do i=1,nzhash
if(ihash22(i).eq.n22) go to 900 !This one is already in the table
enddo
@ -124,7 +115,7 @@ subroutine save_hash_call(c13,n10,n12,n22)
ihash10(1)=n10
ihash12(1)=n12
ihash22(1)=n22
callsign(1)=c13
callsign(1)=cw
if(nzhash.lt.MAXHASH) nzhash=nzhash+1
900 return
@ -236,7 +227,7 @@ subroutine unpack77(c77,msg,unpk77_success)
"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 ","VT ","PEI","DC "/
"LB ","NU ","YT ","PEI","DC "/
unpk77_success=.true.
@ -448,9 +439,11 @@ subroutine unpack77(c77,msg,unpk77_success)
if(iflip.eq.0) then
call_1=call_3
call_2=adjustl(c11)//' '
call add_call_to_recent_calls(call_2)
else
call_1=adjustl(c11)//' '
call_2=call_3
call add_call_to_recent_calls(call_1)
endif
if(icq.eq.0) then
if(nrpt.eq.0) msg=trim(call_1)//' '//trim(call_2)
@ -662,7 +655,7 @@ subroutine unpack28(n28_0,c13,success)
c13=adjustl(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'
success=.false.
endif
@ -990,7 +983,7 @@ subroutine pack77_3(nwords,w,i3,n3,c77)
"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 ","VT ","PEI","DC "/
"LB ","NU ","YT ","PEI","DC "/
if(nwords.eq.4 .or. nwords.eq.5 .or. nwords.eq.6) then
i1=1
@ -1218,6 +1211,9 @@ subroutine add_call_to_recent_calls(callsign)
recent_calls(1)=callsign
endif
! Make sure that callsign is hashed
call save_hash_call(callsign,n10,n12,n22)
return
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
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
implicit none
logical (c_bool) :: crc13_check

View File

@ -67,20 +67,6 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
else
open(13,file=trim(temp_dir)//'/decoded.txt',status='unknown',iostat=ios)
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
nfail=nfail+1
if(nfail.le.3) then
@ -91,6 +77,22 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
if(params%nmode.eq.8) then
! 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)
newdat=params%newdat
ncontest=iand(params%nexp_decode,7)
@ -106,33 +108,37 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
n30max=maxval(n30fox(1:nfox))
endif
j=0
rewind 19
if(nfox.eq.0) then
endfile 19
if(ncontest.eq.5) then
! Fox mode: save decoded Hound calls for possible selection by FoxOp
rewind 19
else
do i=1,nfox
n=n30fox(i)
if(n30max-n30fox(i).le.4) then
j=j+1
c2fox(j)=c2fox(i)
g2fox(j)=g2fox(i)
nsnrfox(j)=nsnrfox(i)
nfreqfox(j)=nfreqfox(i)
n30fox(j)=n
m=n30max-n
if(len(trim(g2fox(j))).eq.4) then
call azdist(mygrid,g2fox(j),0.d0,nAz,nEl,nDmiles,nDkm, &
nHotAz,nHotABetter)
else
nDkm=9999
if(nfox.eq.0) then
endfile 19
rewind 19
else
do i=1,nfox
n=n30fox(i)
if(n30max-n30fox(i).le.4) then
j=j+1
c2fox(j)=c2fox(i)
g2fox(j)=g2fox(i)
nsnrfox(j)=nsnrfox(i)
nfreqfox(j)=nfreqfox(i)
n30fox(j)=n
m=n30max-n
if(len(trim(g2fox(j))).eq.4) then
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
write(19,1004) c2fox(j),g2fox(j),nsnrfox(j),nfreqfox(j),nDkm,m
1004 format(a12,1x,a4,i5,i6,i7,i3)
endif
enddo
nfox=j
flush(19)
enddo
nfox=j
flush(19)
endif
endif
go to 800
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 block.
use crc
parameter (NN=79,ND=58,KK=87,NSPS=4*1920)
parameter (NN=79,ND=58,NSPS=4*1920)
parameter (NWAVE=NN*NSPS,NFFT=614400,NH=NFFT/2)
character*40 cmsg
character*37 msg,msgsent
character*87 cbits
character*88 cb88
integer itone(NN)
integer icos7(0:6)
integer*1 msgbits(KK),codeword(3*ND),msgbits2
integer itone(79)
integer*1 msgbits(77),msgbits2
integer*1, target:: i1Msg8BitBytes(11)
integer*1, target:: mycall
real x(NFFT)
real*8 dt,twopi,f0,fstep,dfreq,phi,dphi
complex cx(0:NH)
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)
data icos7/2,5,6,0,4,1,3/ !Costas 7x7 tone pattern
fstep=60.d0
dfreq=6.25d0
@ -43,51 +38,11 @@ subroutine foxgen()
wave=0.
do n=1,nslots
i3b=i3bit(n)
if(i3b.eq.0) then
msg=cmsg(n)(1:22) !Standard FT8 message
else
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
msg=cmsg(n)(1:37)
call genft8_174_91(msg,i3,n3,msgsent,msgbits,itone)
! print*,'Foxgen:',n,msg,msgsent,i3,n3
! write(*,'(77i1)') msgbits
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
itone2=itone
msgbits2=msgbits

View File

@ -1,6 +1,6 @@
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)
character*40 msg40,cmsg

View File

@ -1,20 +1,43 @@
subroutine ft8apset_174_91(mycall12,hiscall12,hisgrid6,ncontest,apsym)
parameter(NAPM=4,KK=91)
character*37 msg,msgsent
character*12 mycall12,hiscall12
character*6 hisgrid6
character*4 hisgrid
integer apsym(77)
subroutine ft8apset_174_91(mycall12,hiscall12,apsym)
use packjt77
character*77 c77
character*37 msg
character*12 mycall12,hiscall12,hiscall
integer apsym(58)
integer*1 msgbits(77)
integer itone(KK)
if(index(hiscall12," ").eq.0) hiscall12="K9ABC"
msg=trim(mycall12)//' '//trim(hiscall12)//' RRR'
i3=1
n3=0
!write(*,*) 'apset msg ',msg
call genft8_174_91(msg,i3,n3,msgsent,msgbits,itone)
apsym=2*msgbits-1
!write(*,'(29i1,1x,29i1,1x,19i1)') (apsym(1:77)+1)/2
logical nohiscall
if(len(trim(mycall12)).eq.0) then
apsym=0
apsym(1)=99
apsym(30)=99
return
endif
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
end subroutine ft8apset_174_91

View File

@ -1,5 +1,5 @@
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)
use crc
@ -16,19 +16,20 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
real a(5)
real s8(0:7,NN)
real s2(0:511),s2l(0:511)
real bmeta(3*ND),bmetb(3*ND),bmetc(3*ND)
real bmetal(3*ND),bmetbl(3*ND),bmetcl(3*ND)
real llra(3*ND),llrb(3*ND),llrc(3*ND),llrd(3*ND) !Soft symbols
real llral(3*ND),llrbl(3*ND),llrcl(3*ND) !Soft symbols
real bmeta(174),bmetb(174),bmetc(174)
real bmetal(174),bmetbl(174),bmetcl(174)
real llra(174),llrb(174),llrc(174),llrd(174) !Soft symbols
real llral(174),llrbl(174),llrcl(174) !Soft symbols
real dd0(15*12000)
integer*1 message77(77),apmask(3*ND),cw(3*ND)
integer*1 msgbits(77)
integer apsym(77)
integer mcq(29),mrrr(19),m73(19),mrr73(19)
integer*1 message77(77),apmask(174),cw(174)
integer apsym(58)
integer mcq(29),mcqru(29),mcqfd(29),mcqtest(29),mcqhund(29)
integer mrrr(19),m73(19),mrr73(19)
integer itone(NN)
integer icos7(0:6),ip(1)
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 ncontest,ncontest0
integer*1, target:: i1hiscall(12)
logical one(0:511,0:8)
integer graymap(0:7)
@ -38,16 +39,25 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
complex cs(0:7,NN)
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 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 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 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 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 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 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 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
mcqfd=2*mcqfd-1
mcqru=2*mcqru-1
mcqtest=2*mcqtest-1
mcqhund=2*mcqhund-1
mrrr=2*mrrr-1
m73=2*m73-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)
! 6 MyCall DxCall RR73 (77 ap bits)
naptypes(0,1:4)=(/1,2,0,0/)
naptypes(1,1:4)=(/2,3,0,0/)
naptypes(2,1:4)=(/2,3,0,0/)
naptypes(3,1:4)=(/3,4,5,6/)
naptypes(4,1:4)=(/3,4,5,6/)
naptypes(5,1:4)=(/3,1,2,0/)
naptypes(0,1:4)=(/1,2,0,0/) ! Tx6 selected (CQ)
naptypes(1,1:4)=(/2,3,0,0/) ! Tx1
naptypes(2,1:4)=(/2,3,0,0/) ! Tx2
naptypes(3,1:4)=(/3,4,5,6/) ! Tx3
naptypes(4,1:4)=(/3,4,5,6/) ! Tx4
naptypes(5,1:4)=(/3,1,2,0/) ! Tx5
one=.false.
do i=0,511
@ -81,6 +91,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
enddo
enddo
first=.false.
ncontest0=ncontest
endif
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))
phi=mod(phi+dphi,twopi)
enddo
call sync8d(cd0,i0,ctwk,1,2,sync)
call sync8d(cd0,i0,ctwk,1,2,sync)
if( sync .gt. smax ) then
smax=sync
delfbest=delf
@ -211,12 +222,12 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
enddo
enddo
enddo
call normalizebmet(bmeta,3*ND)
! call normalizebmet(bmetal,3*ND)
call normalizebmet(bmetb,3*ND)
! call normalizebmet(bmetbl,3*ND)
call normalizebmet(bmetc,3*ND)
! call normalizebmet(bmetcl,3*ND)
call normalizebmet(bmeta,174)
! call normalizebmet(bmetal,174)
call normalizebmet(bmetb,174)
! call normalizebmet(bmetbl,174)
call normalizebmet(bmetc,174)
! call normalizebmet(bmetcl,174)
scalefac=2.83
llra=scalefac*bmeta
@ -226,7 +237,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
llrc=scalefac*bmetc
! llrcl=scalefac*bmetcl
apmag=maxval(abs(llrb))*1.01
apmag=maxval(abs(llra))*1.01
! pass #
!------------------------------
@ -238,7 +249,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
! 6 ap pass 3
! 7 ap pass 4
if(lapon) then
if(lapon.or.ncontest.eq.6) then !Hounds always use AP
if(.not.lapcqonly) then
npasses=3+nappasses(nQSOProgress)
else
@ -264,29 +275,117 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
else
iaptype=1
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(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
llrd(75:77)=apmag*apsym(75:77)
if(iaptype.eq.1) llrd(1:29)=apmag*mcq(1:29)
if(iaptype.eq.2) llrd(1:29)=apmag*apsym(1:29)
llrd(75:76)=apmag*(-1)
llrd(77)=apmag*(+1)
endif
if(iaptype.eq.3) then ! mycall, dxcall, ???
if(iaptype.eq.2) then ! MyCall,???,???
apmask=0
apmask(1:56)=1
apmask(75:77)=1
llrd(1:56)=apmag*apsym(1:56)
llrd(75:77)=apmag*apsym(75:77)
if(ncontest.eq.0.or.ncontest.eq.1) then
apmask(1:29)=1
llrd(1:29)=apmag*apsym(1:29)
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
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
apmask=0
apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73
llrd(1:58)=apmag*apsym(1:58)
if(iaptype.eq.4) llrd(59:77)=apmag*mrrr
if(iaptype.eq.5) llrd(59:77)=apmag*m73
if(iaptype.eq.6) llrd(59:77)=apmag*mrr73
if(ncontest.le.4 .or. (ncontest.eq.6.and.iaptype.eq.6)) then
apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73
llrd(1:58)=apmag*apsym
if(iaptype.eq.4) llrd(59:77)=apmag*mrrr
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
@ -299,11 +398,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
if(ndepth.eq.3 .and. nharderrors.lt.0) then
ndeep=3
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=3
else
ndeep=4
endif
ndeep=4
endif
if(nagain) ndeep=5
call timer('osd174_91 ',0)
@ -312,7 +407,6 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
endif
msg37=' '
xsnr=-99.0
if(nharderrors.lt.0 .or. nharderrors.gt.36) cycle
if(count(cw.eq.0).eq.174) cycle !Reject the all-zero codeword
write(c77,'(77i1)') message77
@ -326,7 +420,7 @@ subroutine ft8b_2(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
cycle
endif
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)
xsig=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
enddo
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
xbase=10**(xbase/10.0)
! factor=xnoi/xbase
factor=3.6e6
xsnr2=10*log10(xsig/xbase/factor-1.0)-27.0
! if(.not.nagain) xsnr=xsnr2
xsnr2=10.0*log10(xsnr2)-27.0
if(.not.nagain) then
xsnr=xsnr2
endif
if(xsnr .lt. -24.0) xsnr=-24.0
return

View File

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

View File

@ -52,7 +52,7 @@ contains
character*12 mycall12,hiscall12,mycall12_0
character*6 hisgrid6
integer*2 iwave(15*12000)
integer apsym1(KK),apsym2(77)
integer apsym1(KK),apsym2(58)
character datetime*13,msg37*37
! character message*22
character*37 allmessages(100)
@ -70,7 +70,7 @@ contains
1001 format("000000_",i6.6)
call ft8apset(mycall12,hiscall12,apsym1)
call ft8apset_174_91(mycall12,hiscall12,hisgrid6,ncontest,apsym2)
call ft8apset_174_91(mycall12,hiscall12,apsym2)
dd=iwave
ndecodes=0
allmessages=' '
@ -121,7 +121,7 @@ contains
nbadcrc,iappass,iera,msg37,xsnr)
else
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, &
nbadcrc,iappass,iera,msg37,xsnr)
endif
@ -131,9 +131,6 @@ contains
hd=nharderrors+dmin
call timer('ft8b ',1)
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.
do id=1,ndecodes
if(msg37.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true.
@ -143,11 +140,11 @@ contains
allmessages(ndecodes)=msg37
allsnrs(ndecodes)=nsnr
endif
! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
! nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
! xdt,nint(f1),msg37,isync
!1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a37,i4)
! flush(81)
write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
xdt,nint(f1),msg37,isync
1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a37,i4)
flush(81)
if(.not.ldupe .and. associated(this%callback)) then
qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0]
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
if(ichk.lt.10000) then
hashmsg=msg(2:i1-1)
call hash(hashmsg,22,ihash)
call hash(hashmsg,37,ihash)
ihash=iand(ihash,4095) !12-bit hash
ig=16*ihash + irpt !4-bit report
else

View File

@ -46,6 +46,7 @@ subroutine genmsk_128_90(msg0,ichk,msgsent,i4tone,itype)
enddo
endif
message(1:37)=' '
itype=1
if(msg0(1:1).eq.'@') then !Generate a fixed tone
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
else
message=msg0
do i=1, 37
if(ichar(message(i:i)).eq.0) then
message(i:)=' '
message(i:37)=' '
exit
endif
enddo
do i=1,37 !Strip leading blanks
if(message(1:1).ne.' ') exit
message=message(i+1:)
enddo
if(message(1:1).eq.'<') then
call genmsk40(message,msgsent,ichk,i4tone,itype)
if(itype.lt.0) go to 999
i4tone(41)=-40
go to 999
i2=index(message,'>')
i1=0
if(i2.gt.0) i1=index(message(1:i2),' ')
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
i3=-1

View File

@ -5,8 +5,8 @@ subroutine msk40decodeframe(c,mycall,hiscall,xsnr,bswl,nhasharray, &
parameter (NSPM=240)
character*4 rpt(0:15)
character*6 mycall,hiscall,mycall0,hiscall0
character*22 hashmsg,msgreceived
character*12 mycall,hiscall,mycall0,hiscall0
character*37 hashmsg,msgreceived
complex cb(42)
complex cfac,cca
complex c(NSPM)
@ -59,7 +59,7 @@ subroutine msk40decodeframe(c,mycall,hiscall,xsnr,bswl,nhasharray, &
hashmsg=trim(mycall)//' '//trim(hiscall)
if( hashmsg .ne. ' ' .and. hiscall .ne. '' ) then ! protect against blank mycall/hiscall
call fmtmsg(hashmsg,iz)
call hash(hashmsg,22,ihash)
call hash(hashmsg,37,ihash)
ihash=iand(ihash,4095)
else
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
parameter (NSPM=240, MAXSTEPS=150, NFFT=NSPM, MAXCAND=5, NPATTERNS=6)
character*6 mycall,hiscall
character*22 msgreceived
character*12 mycall,hiscall
character*37 msgreceived
complex cbig(n)
complex cdat(3*NSPM) !Analytic signal
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*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*12 mycall,hiscall
character*13 mycall13
character*6 mygrid
character*37 recent_shmsgs(NSHMEM)
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/
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, &
nsnrlast,nsnrlastswl,nhasharray,recent_shmsgs
nsnrlast,nsnrlastswl,nhasharray,recent_shmsgs,mycall13
if(first) then
tsec0=tsec
@ -71,11 +71,16 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
msglastswl=' '
nsnrlast=-99
nsnrlastswl=-99
mycall13=mycall//" "
call save_hash_call(mycall13,n10,n12,n22) ! Make sure that my callsign is in hashtable
first=.false.
endif
fc=nrxfreq
! Reset if mycall changes
if(mycall13(1:12).ne.mycall) first=.true.
! Dupe checking setup
if(nutc00.ne.nutc0 .or. tsec.lt.tsec0) then ! reset dupe checker
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, &
softbits)
if(ndecodesuccess.eq.0 .and. (bshmsg.or.bswl)) then
call msk40spd(cdat,np,ntol,mycall(1:6),hiscall(1:6),bswl,nhasharray, &
ndecodesuccess,msgrx22,fc,fest,tdec,navg)
if( ndecodesuccess .ge. 1 ) msgreceived(1:22)=msgrx22
call msk40spd(cdat,np,ntol,mycall,hiscall,bswl,nhasharray, &
ndecodesuccess,msgreceived,fc,fest,tdec,navg)
endif
if( ndecodesuccess .ge. 1 ) then
tdec=tsec+tdec
@ -184,7 +188,12 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
nsnr=nint(snr0)
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
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
call update_hasharray(nhasharray)
endif
if( .not.bshdecode ) then
write(line,1020) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived(1:22), &
navg,ncorrected,eyeopening,char(0)
1020 format(i6.6,i4,f5.1,i5,a4,a22,i2,i3,f5.1,a1)
else
write(line,1022) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived(1:22), &
navg,char(0)
1022 format(i6.6,i4,f5.1,i5,a4,a22,i2,a1)
endif
write(line,1021) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived,char(0)
1021 format(i6.6,i4,f5.1,i5,a4,a37,a1)
! if( .not.bshdecode ) then
! write(line,1020) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived(1:22), &
! navg,ncorrected,eyeopening,char(0)
!1020 format(i6.6,i4,f5.1,i5,a4,a22,i2,i3,f5.1,a1)
! else
! write(line,1022) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived(1:22), &
! navg,char(0)
!1022 format(i6.6,i4,f5.1,i5,a4,a22,i2,a1)
! endif
elseif(bswl .and. ndecodesuccess.ge.2) then
seenb4=.false.
do i=1,nshmem
@ -233,8 +244,9 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
if(bflag) then
msglastswl=msgreceived
nsnrlastswl=nsnr
write(line,1022) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived, &
navg,char(0)
write(line,1021) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived,char(0)
! write(line,1022) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived, &
! navg,char(0)
endif
endif
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
ftop=nfqso + 7*mode4*df
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
endif

View File

@ -1,7 +1,7 @@
subroutine update_hasharray(nhasharray)
use packjt77
character*22 hashmsg
character*37 hashmsg
integer nhasharray(MAXRECENT,MAXRECENT)
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
hashmsg=trim(recent_calls(i))//' '//trim(recent_calls(j))
call fmtmsg(hashmsg,iz)
call hash(hashmsg,22,ihash)
call hash(hashmsg,37,ihash)
ihash=iand(ihash,4095)
nhasharray(i,j)=ihash
hashmsg=trim(recent_calls(j))//' '//trim(recent_calls(i))
call fmtmsg(hashmsg,iz)
call hash(hashmsg,22,ihash)
call hash(hashmsg,37,ihash)
ihash=iand(ihash,4095)
nhasharray(j,i)=ihash
endif

View File

@ -115,7 +115,7 @@ void ADIF::add(QString const& call, QString const& grid, QString const& band,
{
QSO q;
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.mode = mode;
q.date = date;
@ -180,11 +180,12 @@ int ADIF::getCount() const
return _data.size();
}
QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode
, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn
, QDateTime const& dateTimeOff, QString const& band, QString const& comments
, QString const& name, QString const& strDialFreq, QString const& m_myCall
, QString const& m_myGrid, QString const& m_txPower, QString const& operator_call)
QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode,
QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
QDateTime const& dateTimeOff, QString const& band, QString const& comments,
QString const& name, QString const& strDialFreq, QString const& m_myCall,
QString const& m_myGrid, QString const& m_txPower, QString const& operator_call,
QString const& xSent, QString const& xRcvd)
{
QString t;
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 += " <band:" + QString::number(band.length()) + ">" + band;
t += " <freq:" + QString::number(strDialFreq.length()) + ">" + strDialFreq;
t += " <station_callsign:" + QString::number(m_myCall.length()) + ">" +
m_myCall;
t += " <my_gridsquare:" + QString::number(m_myGrid.length()) + ">" +
m_myGrid;
if (m_txPower != "")
t += " <tx_pwr:" + QString::number(m_txPower.length()) +
">" + m_txPower;
if (comments != "")
t += " <comment:" + QString::number(comments.length()) +
">" + comments;
if (name != "")
t += " <name:" + QString::number(name.length()) +
">" + name;
if (operator_call!="")
t+=" <operator:" + QString::number(operator_call.length()) +
">" + operator_call;
return t.toLatin1 ();
t += " <station_callsign:" + QString::number(m_myCall.length()) + ">" + m_myCall;
t += " <my_gridsquare:" + QString::number(m_myGrid.length()) + ">" + m_myGrid;
if(m_txPower!="") t += " <tx_pwr:" + QString::number(m_txPower.length()) + ">" + m_txPower;
if(comments!="") t += " <comment:" + QString::number(comments.length()) + ">" + comments;
if(name!="") t += " <name:" + QString::number(name.length()) + ">" + name;
if(operator_call!="") t+=" <operator:" + QString::number(operator_call.length()) + ">" + operator_call;
if(xRcvd!="") {
QString t1="";
if(xRcvd.split(" ").size()==2) t1=xRcvd.split(" ").at(1);
if(t1.toInt()>0) {
t += " <SRX:" + QString::number(t1.length()) + ">" + t1;
} else {
t += " <STATE:" + QString::number(t1.length()) + ">" + t1;
}
}
return t.toLatin1();
}
// open ADIF file and append the QSO details. Return true on success
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
bool addQSOToFile(QByteArray const& ADIF_record);
QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent
, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff
, QString const& band, QString const& comments, QString const& name
, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid
, QString const& m_txPower, QString const& operator_call);
QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode,
QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
QDateTime const& dateTimeOff, QString const& band, QString const& comments,
QString const& name, QString const& strDialFreq, QString const& m_myCall,
QString const& m_myGrid, QString const& m_txPower, QString const& operator_call,
QString const& xSent, QString const& xRcvd);
private:
struct QSO

View File

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

View File

@ -33,7 +33,9 @@ public:
QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
QDateTime const& dateTimeOff,
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:
void accept();
@ -61,6 +63,9 @@ private:
Radio::Frequency m_dialFreq;
QString m_myCall;
QString m_myGrid;
QString m_xSent;
QString m_xRcvd;
qint32 m_nContest;
QDateTime m_dateTimeOn;
QDateTime m_dateTimeOff;
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>377</width>
<height>257</height>
<height>287</height>
</rect>
</property>
<property name="sizePolicy">
@ -16,7 +16,7 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="label">
<property name="font">
@ -390,6 +390,57 @@
</item>
</layout>
</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>
<spacer name="verticalSpacer">
<property name="orientation">
@ -397,7 +448,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<width>20</width>
<height>0</height>
</size>
</property>

View File

@ -17,13 +17,10 @@
#include <QStandardPaths>
#include <QStringList>
#include <QLockFile>
#include <QStack>
#include <QSplashScreen>
#if QT_VERSION >= 0x050200
#include <QCommandLineParser>
#include <QCommandLineOption>
#endif
#include "revision_utils.hpp"
#include "MetaDataRegistry.hpp"
@ -54,38 +51,12 @@ namespace
qsrand (seed); // this is good for rand() as well
}
} 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[])
{
// 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 ();
@ -108,7 +79,6 @@ int main(int argc, char *argv[])
a.setApplicationName ("WSJT-X");
a.setApplicationVersion (version ());
#if QT_VERSION >= 0x050200
QCommandLineParser parser;
parser.setApplicationDescription ("\n" PROJECT_SUMMARY_DESCRIPTION);
auto help_option = parser.addHelpOption ();
@ -210,11 +180,11 @@ int main(int argc, char *argv[])
}
}
}
#endif
#if WSJT_QDEBUG_TO_FILE
// Open a trace file
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";
#endif

View File

@ -58,7 +58,9 @@
#include "MultiSettings.hpp"
#include "MaidenheadLocatorValidator.hpp"
#include "CallsignValidator.hpp"
#include "ExchangeValidator.hpp"
#include "EqualizationToolsDialog.hpp"
#include "LotWUsers.hpp"
#include "ui_mainwindow.h"
#include "moc_mainwindow.cpp"
@ -162,7 +164,6 @@ int fast_jhpeak {0};
int fast_jh2 {0};
int narg[15];
QVector<QColor> g_ColorTbl;
QHash<QString,int> m_LoTW;
namespace
{
@ -203,7 +204,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_configurations_button {0},
m_settings {multi_settings->settings ()},
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_tx_next {false},
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->dxCallEntry->setValidator (new CallsignValidator {this});
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_opCall = m_config.opCall();
@ -555,6 +558,10 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
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};
txMsgButtonGroup->addButton(ui->txrb1,1);
txMsgButtonGroup->addButton(ui->txrb2,2);
@ -721,6 +728,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_msg[0][0]=0;
ui->labDXped->setVisible(false);
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
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->decodedTextLabel2->setText(t);
readSettings(); //Restore user's setup parameters
setColorHighlighting(); //Set the color highlighting scheme for decoded text.
m_audioThread.start (m_audioThreadPriority);
#ifdef WIN32
@ -919,31 +927,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
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
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 ()
{
QDateTime now=QDateTime::currentDateTime();
QDateTime timeout=QDateTime(QDate(2018,10,31));
QDateTime timeout=QDateTime(QDate(2018,11,30));
MessageBox::critical_message (this,
"This version of WSJT-X is a beta-level Release Candidate.\n\n"
"On-the-air use carries an obligation to report problems\n"
"to the WSJT Development group and to upgrade to a GA\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();
}
@ -1107,7 +1090,8 @@ void MainWindow::readSettings()
ui->cbFirst->setChecked(m_settings->value("CallFirst",true).toBool());
ui->comboBoxHoundSort->setCurrentIndex(m_settings->value("HoundSort",3).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());
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_settings->endGroup ();
if (displayMsgAvg) on_actionMessage_averaging_triggered();
setContestType();
if(displayMsgAvg) on_actionMessage_averaging_triggered();
}
void MainWindow::setContestType()
@ -1198,6 +1182,8 @@ void MainWindow::setContestType()
if(m_config.bEU_VHF_Contest()) m_nContest=EU_VHF;
if(m_config.bFieldDay()) m_nContest=FIELD_DAY;
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)
@ -1217,7 +1203,7 @@ void MainWindow::setDecodedTextFont (QFont const& font)
ui->decodedTextBrowser->setContentFont (font);
ui->decodedTextBrowser2->setContentFont (font);
ui->textBrowser4->setContentFont(font);
ui->textBrowser4->displayFoxToBeCalled(" ","#ffffff");
ui->textBrowser4->displayFoxToBeCalled(" ");
ui->textBrowser4->setText("");
auto style_sheet = "QLabel {" + font_as_stylesheet (font) + '}';
ui->decodedTextLabel->setStyleSheet (ui->decodedTextLabel->styleSheet () + style_sheet);
@ -1524,11 +1510,13 @@ void MainWindow::fastSink(qint64 frames)
int RxFreq=ui->RxFreqSpinBox->value ();
int nTRpDepth=m_TRperiod + 1000*(m_ndepth & 3);
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 ()};
bool bshmsg=ui->cbShMsgs->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);
QString dataDir;
dataDir = m_config.writeable_data_dir ().absolutePath ();
@ -1702,23 +1690,8 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog
}
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)
{
if (!m_transmitting) {
@ -1836,6 +1809,9 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
}
}
break;
case Qt::Key_Escape:
on_stopTxButton_clicked();
return;
case Qt::Key_F1:
on_actionOnline_User_Guide_triggered();
return;
@ -1860,21 +1836,33 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
on_actionOpen_next_in_directory_triggered();
return;
case Qt::Key_F11:
n=11;
if(e->modifiers() & Qt::ControlModifier) n+=100;
if(e->modifiers() & Qt::ShiftModifier) {
ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()-60);
} else{
bumpFqso(n);
if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) {
m_bandEdited = true;
band_changed(m_freqNominal-2000);
// qDebug() << "Down" << m_freqNominal;
} else {
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;
case Qt::Key_F12:
n=12;
if(e->modifiers() & Qt::ControlModifier) n+=100;
if(e->modifiers() & Qt::ShiftModifier) {
ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()+60);
if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) {
m_bandEdited = true;
band_changed(m_freqNominal+2000);
// qDebug() << "Up " << m_freqNominal;
} 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;
case Qt::Key_X:
@ -1936,7 +1924,13 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
return;
}
break;
}
case Qt::Key_PageUp:
break;
case Qt::Key_PageDown:
band_changed(m_freqNominal-2000);
qDebug() << "Down" << m_freqNominal;
break; }
QMainWindow::keyPressEvent (e);
}
@ -2184,7 +2178,7 @@ void MainWindow::closeEvent(QCloseEvent * e)
m_prefixes.reset ();
m_shortcuts.reset ();
m_mouseCmnds.reset ();
m_colorHighlighting.reset();
m_colorHighlighting.reset ();
if(m_mode!="MSK144" and m_mode!="FT8") killFile();
float sw=0.0;
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"});
}
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
{
#if defined (CMAKE_BUILD)
@ -2387,32 +2387,29 @@ void MainWindow::on_actionAstronomical_data_toggled (bool checked)
void MainWindow::on_actionFox_Log_triggered()
{
on_actionMessage_averaging_triggered();
m_msgAvgWidget->foxLogSetup();
m_msgAvgWidget->foxLogSetup(m_nContest);
}
void MainWindow::on_actionColors_triggered()
{
if (!m_colorHighlighting) {
m_colorHighlighting.reset (new ColorHighlighting {m_settings});
}
m_colorHighlighting->showNormal();
if (!m_colorHighlighting)
{
m_colorHighlighting.reset (new ColorHighlighting {m_settings, m_config.decode_highlighting ()});
connect (&m_config, &Configuration::decode_highlighting_changed, m_colorHighlighting.data (), &ColorHighlighting::set_items);
}
m_colorHighlighting->showNormal ();
m_colorHighlighting->raise ();
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()
{
if (!m_msgAvgWidget)
{
m_msgAvgWidget.reset (new MessageAveraging {m_settings, m_config.decoded_text_font ()});
if(!m_msgAvgWidget) {
m_msgAvgWidget.reset (new MessageAveraging {m_settings, m_config.decoded_text_font ()});
// Connect signals from Message Averaging window
connect (this, &MainWindow::finished, m_msgAvgWidget.data (), &MessageAveraging::close);
}
// Connect signals from Message Averaging window
connect (this, &MainWindow::finished, m_msgAvgWidget.data (), &MessageAveraging::close);
}
m_msgAvgWidget->showNormal();
m_msgAvgWidget->raise ();
m_msgAvgWidget->activateWindow ();
@ -2943,12 +2940,17 @@ void MainWindow::readFromStdout() //readFromStdout
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
(decodedtext.string().contains("R+") or decodedtext.string().contains("R-"))) {
auto for_us = decodedtext.string().contains(" " + m_config.my_callsign() + " ") 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(for_us) {
QString houndCall,houndGrid;
@ -2956,7 +2958,8 @@ void MainWindow::readFromStdout() //readFromStdout
foxRxSequencer(decodedtext.string(),houndCall,houndGrid);
}
}
//Left (Band activity) window
//Left (Band activity) window
if(!bAvgMsg) {
if(m_mode=="FT8" and m_config.bFox()) {
if(!m_bDisplayedOnce) {
@ -2967,13 +2970,13 @@ void MainWindow::readFromStdout() //readFromStdout
m_bDisplayedOnce=true;
}
} 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(),
(ui->cbCQonly->isVisible() and ui->cbCQonly->isChecked()));
}
}
//Right (Rx Frequency) window
//Right (Rx Frequency) window
bool bDisplayRight=bAvgMsg;
int audioFreq=decodedtext.frequencyOffset();
@ -3002,7 +3005,7 @@ void MainWindow::readFromStdout() //readFromStdout
if (bDisplayRight) {
// This msg is within 10 hertz of our tuned frequency, or a JT4 or JT65 avg,
// 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());
if(m_mode!="JT4") {
@ -3056,8 +3059,9 @@ void MainWindow::readFromStdout() //readFromStdout
//### 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_mode=="QRA64" or m_mode=="JT4" or m_mode=="JT65" or
m_mode=="JT9") auto_sequence (decodedtext, 25, 50);
if(m_mode=="FT8" or m_mode=="QRA64" or m_mode=="JT4" or m_mode=="JT65" or m_mode=="JT9") {
auto_sequence (decodedtext, 25, 50);
}
postDecode (true, decodedtext.string ());
// 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);
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
&& (m_QSOProgress==REPLYING or (!ui->tx1->isEnabled () and m_QSOProgress==REPORT))
&& qAbs (ui->TxFreqSpinBox->value () - df) <= int (stop_tolerance)
@ -3333,13 +3337,9 @@ void MainWindow::guiUpdate()
auto const& message = tr ("Please choose another Tx frequency."
" WSJT-X will not knowingly transmit another"
" mode in the WSPR sub-band on 30m.");
#if QT_VERSION >= 0x050400
QTimer::singleShot (0, [=] { // don't block guiUpdate
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."
" WSJT-X will not operate in Fox mode"
" in the standard FT8 sub-bands.");
#if QT_VERSION >= 0x050400
QTimer::singleShot (0, [=] { // don't block guiUpdate
MessageBox::warning_message (this, tr ("Fox Mode warning"), message);
});
#else
MessageBox::warning_message (this, tr ("Fox Mode warning"), message);
#endif
break;
}
}
@ -3580,7 +3576,6 @@ void MainWindow::guiUpdate()
m_xSent=t.at(n-2) + " " + t.at(n-1);
}
}
}
if(m_isync==1) msgsent[22]=0;
if(m_isync==2) msgsent[37]=0;
@ -3629,18 +3624,20 @@ void MainWindow::guiUpdate()
if(m_config.id_after_73 ()) {
icw[0] = m_ncw;
}
if (m_config.prompt_to_log () && !m_tune) {
logQSOTimer.start (0);
}
if((m_config.prompt_to_log() or m_config.autoLog()) && !m_tune) logQSOTimer.start(0);
}
bool b=(m_mode=="FT8") and ui->cbAutoSeq->isChecked();
if(is_73 and (m_config.disable_TX_on_73() or b)) {
auto_tx_mode (false);
if(b) {
m_ntx=6;
ui->txrb6->setChecked(true);
m_QSOProgress = CALLING;
if(m_nextCall!="") {
useNextCall();
} else {
auto_tx_mode (false);
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(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.
ui->tx1->setEnabled(false);
}
@ -3753,8 +3750,8 @@ void MainWindow::guiUpdate()
//Once per second:
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_bVHFwarned) vhfWarning();
} else {
@ -3762,21 +3759,7 @@ void MainWindow::guiUpdate()
}
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()) {
// m_bWarnedHound=false;
qint32 tHound=QDateTime::currentMSecsSinceEpoch()/1000 - m_tAutoOn;
//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);
@ -3860,6 +3843,22 @@ void MainWindow::guiUpdate()
m_btxok0=m_btxok;
} //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()
{
@ -4218,6 +4217,14 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
QString hiscall;
QString 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 ();
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)
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);
// 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 + "/")
|| (firstcall == "DE")) {
QString w2=message_words.at(2);
QString w2="";
if(message_words.size()>=3) w2=message_words.at(2);
QString w34="";
if(message_words.size()>=4) w34=message_words.at(3);
int nrpt=w2.toInt();
@ -4366,8 +4374,19 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
if (ui->rbGenMsg->isChecked ()) m_ntx=7;
m_gen_message_is_cq = false;
} else {
m_ntx=5;
ui->txrb5->setChecked(true);
m_bTUmsg=false;
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;
} else if((m_QSOProgress >= REPORT
@ -4400,7 +4419,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
}
}
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
if(ui->tabWidget->currentIndex()==1) {
gen_msg = 5;
@ -4414,7 +4434,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
m_QSOProgress = SIGNOFF;
}
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
m_ntx=3;
m_QSOProgress = ROGER_REPORT;
@ -4445,6 +4466,17 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
}
}
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;
}
}
@ -4488,7 +4520,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
ui->txrb5->setChecked(true);
}
m_QSOProgress = SIGNOFF;
} else {// just work them
} else {
// just work them
if (ui->tx1->isEnabled ()) {
m_ntx = 1;
m_QSOProgress = REPLYING;
@ -4554,7 +4587,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
}
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);
if (gen_msg) {
switch (gen_msg) {
@ -4610,7 +4644,8 @@ void MainWindow::genCQMsg ()
}
} else {
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 {
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();
// if(m_nContest==NA_VHF) t="CQ QP" + t.mid(2,-1);
QString t=ui->tx6->text();
if((m_mode=="FT8" or m_mode=="MSK144") and m_nContest!=NONE and
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==RTTY) t="CQ RU" + t.mid(2,-1);
if(m_nContest==FOX) t="CQ HUND" + t.mid(2,-1);
ui->tx6->setText(t);
}
} else {
@ -4661,7 +4699,11 @@ bool MainWindow::stdCall(QString w)
}
void MainWindow::genStdMsgs(QString rpt, bool unconditional)
{
{
if(ui->tx3->text().left(4)=="TU; ") {
return;
}
genCQMsg ();
auto const& hisCall=ui->dxCallEntry->text();
if(!hisCall.size ()) {
@ -4686,19 +4728,22 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
bool bMyCall=stdCall(my_callsign);
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 t0s=hisCall + " " + my_callsign + " ";
QString t0a,t0b;
if(b77) {
// if(bHisCall and bMyCall) t0=hisCall + " " + my_callsign + " ";
if(bHisCall and bMyCall) t0=hisCall + " " + my_callsign + " ";
t0a="<"+hisCall + "> " + my_callsign + " ";
t0b=hisCall + " <" + my_callsign + "> ";
}
QString t00=t0;
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);
if (eme_short_codes) {
t=t+" OOO";
@ -4744,8 +4789,8 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
}
if(m_mode=="MSK144" and m_bShMsgs) {
int i=t0.length()-1;
t0="<" + t0.mid(0,i) + "> ";
int i=t0s.length()-1;
t0="<" + t0s.mid(0,i) + "> ";
if(!m_config.bNA_VHF_Contest()) {
if(n<=-2) n=-3;
if(n>=-1 and n<=1) n=0;
@ -4764,14 +4809,14 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
t=t0 + "R" + rpt;
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;
msgtype(t, ui->tx3);
m_send_RR73=false;
}
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");
}
@ -4779,7 +4824,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
msgtype(t, ui->tx4);
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";
}
@ -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_type_one) {
@ -5180,22 +5225,38 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button
if (dateTimeQSOOff < m_dateTimeQSOOn) dateTimeQSOOff = m_dateTimeQSOOn;
QString grid=m_hisGrid;
if(grid=="....") grid="";
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(), m_opCall);
if(m_nContest!=NONE) {
if(m_nContest>NONE and m_nContest<FOX) {
if(m_nContest==NA_VHF) {
m_xSent=m_config.my_grid().left(4);
m_xRcvd=m_hisGrid;
}
if(m_nContest!=NONE) {
int n=ui->sbSerialNumber->value();
ui->sbSerialNumber->setValue(n+1);
cabLog(); //Call the Cabrillo contest logger
if(m_nContest==EU_VHF) {
m_rptSent=m_xSent.split(" ").at(0).left(2);
m_rptRcvd=m_xRcvd.split(" ").at(0).left(2);
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()
@ -5205,13 +5266,22 @@ void MainWindow::cabLog()
int nfreq=m_freqNominal/1000;
if(m_freqNominal>50000000) nfreq=m_freqNominal/1000000;
QString t;
t.sprintf("QSO: %5d RY ",nfreq);
t.sprintf("QSO: %5d DG ",nfreq);
t=t + QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hhmm ") +
m_config.my_callsign().leftJustified(13,' ') + m_xSent.leftJustified(14,' ') +
m_hisCall.leftJustified(13,' ') + m_xRcvd;
QTextStream out(&f);
out << t << endl;
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 {
MessageBox::warning_message (this, tr("File Open Error"),
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==26) ui->actionEnable_AP_DXcall->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==30) ui->labDXped->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->decodedTextLabel->setText( " UTC dB DT Freq Message");
}
displayWidgets(nWidgets("111010000100111000010000100100001"));
displayWidgets(nWidgets("111010000100111000010000100110001"));
ui->txrb2->setEnabled(true);
ui->txrb4->setEnabled(true);
ui->txrb5->setEnabled(true);
@ -5357,7 +5427,7 @@ void MainWindow::on_actionFT8_triggered()
ui->tabWidget->setCurrentIndex(2);
ui->TxFreqSpinBox->setValue(300);
displayWidgets(nWidgets("111010000100111000010000000000100"));
ui->labDXped->setText("DXpedition: Fox");
ui->labDXped->setText("Fox");
on_actionFox_Log_triggered();
}
if(m_config.bHound()) {
@ -5367,7 +5437,7 @@ void MainWindow::on_actionFT8_triggered()
ui->tabWidget->setCurrentIndex(0);
ui->cbHoldTxFreq->setChecked(true);
displayWidgets(nWidgets("111010000100110000010000000000110"));
ui->labDXped->setText("DXpedition: Hound");
ui->labDXped->setText("Hound");
ui->txrb1->setChecked(true);
ui->txrb2->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()
{
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
if (m_config.pwrBandTuneMemory() || m_config.pwrBandTxMemory()) {
stopTx();
m_pwrBandTuneMemory[curBand] = ui->outAttenuation->value(); // remember our Tune pwr
m_PwrBandSetOK = false;
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->actionEnable_AP_DXcall->setVisible (m_mode=="QRA64");
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();
}
}
@ -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"};
auto const& time_string = time.toString ("~" == mode || "&" == mode ? "hhmmss" : "hhmm");
auto cqtext = format_string
auto message_line = format_string
.arg (time_string)
.arg (snr, 3)
.arg (delta_time, 4, 'f', 1)
.arg (delta_frequency, 4)
.arg (mode, -2)
.arg (message_text);
auto messages = ui->decodedTextBrowser->toPlainText ();
auto position = messages.lastIndexOf (cqtext);
if (position < 0)
QTextCursor start {ui->decodedTextBrowser->document ()};
start.movePosition (QTextCursor::End);
auto cursor = ui->decodedTextBrowser->document ()->find (message_line, start, QTextDocument::FindBackward);
if (cursor.isNull ())
{
// try again with with -0.0 delta time
position = messages.lastIndexOf (format_string
.arg (time_string)
.arg (snr, 3)
.arg ('-' + QString::number (delta_time, 'f', 1), 4)
.arg (delta_frequency, 4)
.arg (mode, -2)
.arg (message_text));
cursor = ui->decodedTextBrowser->document ()->find (format_string
.arg (time_string)
.arg (snr, 3)
.arg ('-' + QString::number (delta_time, 'f', 1), 4)
.arg (delta_frequency, 4)
.arg (mode, -2)
.arg (message_text), start, QTextDocument::FindBackward);
}
if (position >= 0)
if (!cursor.isNull ())
{
if (m_config.udpWindowToFront ())
{
@ -6931,14 +7014,11 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de
showNormal ();
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 ))"})) {
// a message we are willing to accept and auto reply to
m_bDoubleClicked = true;
}
auto start = messages.left (position).lastIndexOf (QChar::LineFeed) + 1;
DecodedText message {messages.mid (start, position - start)};
DecodedText message {message_line};
Qt::KeyboardModifiers kbmod {modifiers << 24};
processMessage (message, kbmod);
tx_watchdog (false);
@ -6946,7 +7026,7 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de
}
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
// attempt to parse the decoded text
Q_FOREACH (auto const& message
, ui->decodedTextBrowser->toPlainText ().split (QChar::LineFeed,
QString::SkipEmptyParts))
for (QTextBlock block = ui->decodedTextBrowser->document ()->firstBlock (); block.isValid (); block = block.next ())
{
auto message = block.text ();
message = message.left (message.indexOf (QChar::Nbsp)); // discard
// any
// appended info
if (message.size() >= 4 && message.left (4) != "----")
{
auto const& parts = message.split (' ', QString::SkipEmptyParts);
@ -6996,14 +7078,8 @@ void MainWindow::replayDecodes ()
}
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
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")
.arg (f.fileName ()).arg (f.errorString ());
#if QT_VERSION >= 0x050400
QTimer::singleShot (0, [=] { // don't block guiUpdate
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(t2.length()==2) t2=t2.mid(0,1) + "0" + t2.mid(1,1);
t1=t1.mid(0,12) + t2;
ui->textBrowser4->displayFoxToBeCalled(t1,"#ffffff"); // Add hound call and rpt to tb4
t1=t1 + " " + houndGrid; // Append the grid
m_houndQueue.enqueue(t1); // Put this hound into the queue
ui->textBrowser4->displayFoxToBeCalled(t1); // Add hound call and rpt to tb4
t1=t1 + " " + houndGrid; // Append the grid
m_houndQueue.enqueue(t1); // Put this hound into the queue
writeFoxQSO(" Sel: " + t1);
QTextCursor cursor = ui->textBrowser4->textCursor();
cursor.setPosition(0); // Scroll to top of list

View File

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

View File

@ -654,9 +654,15 @@ QLabel[oob=&quot;true&quot;] {
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>20</height>
</size>
</property>
@ -698,9 +704,15 @@ QLabel[oob=&quot;true&quot;] {
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>20</height>
</size>
</property>
@ -1034,6 +1046,19 @@ QLabel[oob=&quot;true&quot;] {
</property>
</widget>
</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>
</item>
<item>
@ -2621,10 +2646,12 @@ QPushButton[state=&quot;ok&quot;] {
<addaction name="actionErase_FoxQSO_txt"/>
<addaction name="actionErase_wsjtx_log_adi"/>
<addaction name="actionErase_cabrillo_log"/>
<addaction name="actionExport_Cabrillo_log"/>
<addaction name="actionOpen_log_directory"/>
<addaction name="separator"/>
<addaction name="actionSettings"/>
<addaction name="separator"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuView">
@ -2670,6 +2697,7 @@ QPushButton[state=&quot;ok&quot;] {
<addaction name="actionOnline_User_Guide"/>
<addaction name="actionLocal_User_Guide"/>
<addaction name="actionFT8_DXpedition_Mode_User_Guide"/>
<addaction name="actionQuick_Start_Guide_v2"/>
<addaction name="download_samples_action"/>
<addaction name="separator"/>
<addaction name="actionKeyboard_shortcuts"/>
@ -3275,13 +3303,13 @@ QPushButton[state=&quot;ok&quot;] {
</action>
<action name="actionFox_Log">
<property name="text">
<string>Fox Log</string>
<string>Fox or Contest Log</string>
</property>
<property name="iconText">
<string>Fox Log</string>
<string>Fox or Contest Log</string>
</property>
<property name="toolTip">
<string>Fox Log</string>
<string>Fox or Contest Log</string>
</property>
</action>
<action name="actionErase_FoxQSO_txt">
@ -3304,6 +3332,21 @@ QPushButton[state=&quot;ok&quot;] {
<string>Color highlighting scheme</string>
</property>
</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>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View File

@ -20,6 +20,12 @@ MessageAveraging::MessageAveraging(QSettings * settings, QFont const& font, QWid
read_settings ();
if(m_title_.contains("Fox")) {
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 {
ui->header_label->setText(" UTC Sync DT Freq ");
ui->lab1->setVisible(false);
@ -27,6 +33,7 @@ MessageAveraging::MessageAveraging(QSettings * settings, QFont const& font, QWid
ui->lab3->setVisible(false);
ui->lab4->setVisible(false);
}
setWindowTitle(m_title_);
m_nLogged_=0;
}
@ -74,6 +81,7 @@ void MessageAveraging::read_settings ()
SettingsGroup group {settings_, "MessageAveraging"};
restoreGeometry (settings_->value ("window/geometry").toByteArray ());
m_title_=settings_->value("window/title","Message Averaging").toString();
m_nContest_=settings_->value("nContest",0).toInt();
}
void MessageAveraging::write_settings ()
@ -81,6 +89,7 @@ void MessageAveraging::write_settings ()
SettingsGroup group {settings_, "MessageAveraging"};
settings_->setValue ("window/geometry", saveGeometry ());
settings_->setValue("window/title",m_title_);
settings_->setValue("nContest",m_nContest_);
}
void MessageAveraging::displayAvg(QString const& t)
@ -88,11 +97,19 @@ void MessageAveraging::displayAvg(QString const& t)
ui->msgAvgPlainTextEdit->setPlainText(t);
}
void MessageAveraging::foxLogSetup()
void MessageAveraging::foxLogSetup(int nContest)
{
m_title_=QApplication::applicationName () + " - Fox Log";
setWindowTitle(m_title_);
ui->header_label->setText(" Date Time Call Grid Sent Rcvd Band");
if(nContest==5) {
m_title_=QApplication::applicationName () + " - Fox Log";
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)
@ -124,3 +141,19 @@ void MessageAveraging::foxAddLog(QString logLine)
t.sprintf("Logged: %d",m_nLogged_);
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();
void displayAvg(QString const&);
void changeFont (QFont const&);
void foxLogSetup();
void foxLogSetup(int nContest);
void foxLabCallers(int n);
void foxLabQueued(int n);
void foxLabRate(int n);
void foxAddLog(QString logLine);
void contestAddLog(qint32 nContest, QString logLine);
protected:
void closeEvent (QCloseEvent *) override;
@ -32,7 +33,9 @@ private:
void setContentFont (QFont const&);
QSettings * settings_;
QString m_title_;
qint32 m_nLogged_;
qint32 m_nLogged_=0;
qint32 m_mult_=0;
qint32 m_nContest_;
QScopedPointer<Ui::MessageAveraging> ui;
};

View File

@ -18,7 +18,7 @@
QDataStream& operator << (QDataStream& os, CLASS::ENUM const& v) \
{ \
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) \
@ -47,35 +47,9 @@
QString enum_to_qstring (CLASS::ENUM const& m) \
{ \
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
void throw_qstring (QString const& qs)
{

View File

@ -1,4 +1,5 @@
<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>Shift+F1 </b></td><td>Copyright Notice</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>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>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>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>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>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>

View File

@ -67,8 +67,8 @@ SOURCES += \
echoplot.cpp echograph.cpp fastgraph.cpp fastplot.cpp Modes.cpp \
WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\
MultiSettings.cpp PhaseEqualizationDialog.cpp IARURegions.cpp MessageBox.cpp \
EqualizationToolsDialog.cpp \
colorhighlighting.cpp
EqualizationToolsDialog.cpp CallsignValidator.cpp ExchangeValidator.cpp \
colorhighlighting.cpp ExportCabrillo.cpp LotWUsers.cpp
HEADERS += qt_helpers.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 \
messageaveraging.h echoplot.h echograph.h fastgraph.h fastplot.h Modes.hpp WSPRBandHopping.hpp \
WsprTxScheduler.h SampleDownloader.hpp MultiSettings.hpp PhaseEqualizationDialog.hpp \
IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp \
colorhighlighting.h
IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp CallsignValidator.hpp \
ExchangeValidator.hpp colorhighlighting.h ExportCabrillo.h LotWUsers.h
INCLUDEPATH += qmake_only
@ -97,8 +97,7 @@ HEADERS += OmniRigTransceiver.hpp
FORMS += mainwindow.ui about.ui Configuration.ui widegraph.ui astro.ui \
logqso.ui wf_palette_design_dialog.ui messageaveraging.ui echograph.ui \
fastgraph.ui \
colorhighlighting.ui
fastgraph.ui colorhighlighting.ui ExportCabrillo.ui
RC_FILE = wsjtx.rc
RESOURCES = wsjtx.qrc