Merge branch 'develop' into map65

This commit is contained in:
Joe Taylor 2022-11-21 12:40:23 -05:00
commit 3c8a8d518a
26 changed files with 1580 additions and 497 deletions

View File

@ -180,13 +180,15 @@ void SoundInput::reset (bool report_dropped_frames)
if (cummulative_lost_usec_ != std::numeric_limits<qint64>::min () && report_dropped_frames)
{
auto lost_usec = elapsed_usecs - m_stream->processedUSecs () - cummulative_lost_usec_;
if (std::abs (lost_usec) > 48000 / 5)
{
LOG_WARN ("Detected dropped audio source samples: "
<< m_stream->format ().framesForDuration (lost_usec)
<< " (" << std::setprecision (4) << lost_usec / 1.e6 << " S)");
}
else if (std::abs (lost_usec) > 5 * 48000)
// disable log warnings on dropped audio for now, as detection is not reliable
// if (std::abs (lost_usec) > 48000 / 5)
// {
// LOG_WARN ("Detected dropped audio source samples: "
// << m_stream->format ().framesForDuration (lost_usec)
// << " (" << std::setprecision (4) << lost_usec / 1.e6 << " S)");
// }
// else if (std::abs (lost_usec) > 5 * 48000)
if (std::abs (lost_usec) > 5 * 48000)
{
LOG_ERROR ("Detected excessive dropped audio source samples: "
<< m_stream->format ().framesForDuration (lost_usec)

View File

@ -80,7 +80,7 @@ set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_
set (PROJECT_BUNDLE_NAME "WSJT-X")
set (PROJECT_VENDOR "Joe Taylor, K1JT")
set (PROJECT_CONTACT "Joe Taylor <k1jt@arrl.net>")
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2021 by Joe Taylor, K1JT")
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2022 by Joe Taylor, K1JT")
set (PROJECT_HOMEPAGE https://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html)
set (PROJECT_MANUAL wsjtx-main)
set (PROJECT_MANUAL_DIRECTORY_URL https://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/)
@ -190,6 +190,7 @@ set (wsjt_qt_CXXSRCS
widgets/FrequencyDeltaLineEdit.cpp
item_delegates/CandidateKeyFilter.cpp
item_delegates/ForeignKeyDelegate.cpp
item_delegates/MessageItemDelegate.cpp
validators/LiveFrequencyValidator.cpp
GetUserId.cpp
Audio/AudioDevice.cpp

View File

@ -168,6 +168,11 @@
#include <QHostAddress>
#include <QStandardItem>
#include <QDebug>
#include <QDateTimeEdit>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include "pimpl_impl.hpp"
#include "Logger.hpp"
@ -180,6 +185,7 @@
#include "item_delegates/ForeignKeyDelegate.hpp"
#include "item_delegates/FrequencyDelegate.hpp"
#include "item_delegates/FrequencyDeltaDelegate.hpp"
#include "item_delegates/MessageItemDelegate.hpp"
#include "Transceiver/TransceiverFactory.hpp"
#include "Transceiver/Transceiver.hpp"
#include "models/Bands.hpp"
@ -250,7 +256,8 @@ namespace
// Magic numbers for file validation
constexpr quint32 qrg_magic {0xadbccbdb};
constexpr quint32 qrg_version {100}; // M.mm
constexpr quint32 qrg_version {101}; // M.mm
constexpr quint32 qrg_version_100 {100};
}
@ -263,13 +270,27 @@ class FrequencyDialog final
Q_OBJECT
public:
using Item = FrequencyList_v2::Item;
using Item = FrequencyList_v2_101::Item;
explicit FrequencyDialog (IARURegions * regions_model, Modes * modes_model, QWidget * parent = nullptr)
: QDialog {parent}
{
start_date_time_edit_ = new QDateTimeEdit(QDateTime(QDate::currentDate(), QTime(0,0,0,0), Qt::UTC), parent);
end_date_time_edit_ = new QDateTimeEdit(QDateTime(QDate::currentDate().addDays(2), QTime(0,0,0,0), Qt::UTC), parent);
enable_dates_checkbox_ = new QCheckBox {tr ("")};
start_date_time_edit_->setDisplayFormat("yyyy.MM.dd hh:mm:ss 'UTC'");
start_date_time_edit_->setTimeSpec(Qt::UTC);
start_date_time_edit_->setMinimumDate(QDate::currentDate().addDays(-365));
end_date_time_edit_->setDisplayFormat("yyyy.MM.dd hh:mm:ss 'UTC'");
end_date_time_edit_->setTimeSpec(Qt::UTC);
end_date_time_edit_->setMinimumDate(QDate::currentDate().addDays(-365));
preferred_frequency_checkbox_ = new QCheckBox {tr ("")};
setWindowTitle (QApplication::applicationName () + " - " +
tr ("Add Frequency"));
region_combo_box_.setModel (regions_model);
mode_combo_box_.setModel (modes_model);
@ -277,28 +298,74 @@ public:
form_layout->addRow (tr ("IARU &Region:"), &region_combo_box_);
form_layout->addRow (tr ("&Mode:"), &mode_combo_box_);
form_layout->addRow (tr ("&Frequency (MHz):"), &frequency_line_edit_);
form_layout->addRow (tr ("&Preferred for Band/Mode:"), preferred_frequency_checkbox_);
form_layout->addRow (tr ("&Description:"), &description_line_edit_);
form_layout->addRow (tr ("&Enable Date Range:"), enable_dates_checkbox_);
form_layout->addRow (tr ("S&tart:"), start_date_time_edit_);
form_layout->addRow (tr ("&End:"), end_date_time_edit_);
form_layout->addRow (tr ("&Source:"), &source_line_edit_);
auto main_layout = new QVBoxLayout (this);
main_layout->addLayout (form_layout);
auto button_box = new QDialogButtonBox {QDialogButtonBox::Ok | QDialogButtonBox::Cancel};
button_box = new QDialogButtonBox {QDialogButtonBox::Ok | QDialogButtonBox::Cancel};
main_layout->addWidget (button_box);
connect (button_box, &QDialogButtonBox::accepted, this, &FrequencyDialog::accept);
connect (button_box, &QDialogButtonBox::rejected, this, &FrequencyDialog::reject);
connect(start_date_time_edit_, &QDateTimeEdit::dateTimeChanged, this, &FrequencyDialog::checkSaneDates);
connect(end_date_time_edit_, &QDateTimeEdit::dateTimeChanged, this, &FrequencyDialog::checkSaneDates);
connect(enable_dates_checkbox_, &QCheckBox::stateChanged, this, &FrequencyDialog::toggleValidity);
toggleValidity();
}
void toggleValidity()
{
start_date_time_edit_->setEnabled(enable_dates_checkbox_->isChecked());
end_date_time_edit_->setEnabled(enable_dates_checkbox_->isChecked());
checkSaneDates();
}
void checkSaneDates()
{
if (enable_dates_checkbox_->isChecked() && start_date_time_edit_->dateTime().isValid() && end_date_time_edit_->dateTime().isValid())
{
if (start_date_time_edit_->dateTime() > end_date_time_edit_->dateTime())
{
QMessageBox::warning(this, tr("Invalid Date Range"), tr("Start date must be before end date"));
button_box->button(QDialogButtonBox::Ok)->setEnabled(false);
return;
}
}
button_box->button(QDialogButtonBox::Ok)->setEnabled(true);
}
Item item () const
{
return {frequency_line_edit_.frequency ()
, Modes::value (mode_combo_box_.currentText ())
, IARURegions::value (region_combo_box_.currentText ())};
QDateTime start_time = enable_dates_checkbox_->isChecked() ? start_date_time_edit_->dateTime() : QDateTime();
QDateTime end_time = enable_dates_checkbox_->isChecked() ? end_date_time_edit_->dateTime() : QDateTime();
return {
frequency_line_edit_.frequency(),
Modes::value(mode_combo_box_.currentText()),
IARURegions::value(region_combo_box_.currentText()),
description_line_edit_.text(), source_line_edit_.text(),
start_time,
end_time,
preferred_frequency_checkbox_->isChecked()
};
}
private:
QComboBox region_combo_box_;
QComboBox mode_combo_box_;
FrequencyLineEdit frequency_line_edit_;
QLineEdit description_line_edit_;
QLineEdit source_line_edit_;
QDialogButtonBox * button_box;
QCheckBox *enable_dates_checkbox_;
QCheckBox *preferred_frequency_checkbox_;
QDateTimeEdit *end_date_time_edit_;
QDateTimeEdit *start_date_time_edit_;
};
@ -375,31 +442,7 @@ public:
};
//
// Class MessageItemDelegate
//
// Item delegate for message entry such as free text message macros.
//
class MessageItemDelegate final
: public QStyledItemDelegate
{
public:
explicit MessageItemDelegate (QObject * parent = nullptr)
: QStyledItemDelegate {parent}
{
}
QWidget * createEditor (QWidget * parent
, QStyleOptionViewItem const& /* option*/
, QModelIndex const& /* index */
) const override
{
auto editor = new QLineEdit {parent};
editor->setFrame (false);
editor->setValidator (new QRegularExpressionValidator {message_alphabet, editor});
return editor;
}
};
// Internal implementation of the Configuration class.
class Configuration::impl final
@ -477,7 +520,9 @@ private:
void save_frequencies ();
void reset_frequencies ();
void insert_frequency ();
FrequencyList_v2::FrequencyItems read_frequencies_file (QString const&);
void size_frequency_table_columns();
FrequencyList_v2_101::FrequencyItems read_frequencies_file (QString const&);
void delete_stations ();
void insert_station ();
@ -569,8 +614,8 @@ private:
IARURegions regions_;
IARURegions::Region region_;
Modes modes_;
FrequencyList_v2 frequencies_;
FrequencyList_v2 next_frequencies_;
FrequencyList_v2_101 frequencies_;
FrequencyList_v2_101 next_frequencies_;
StationList stations_;
StationList next_stations_;
FrequencyDelta current_offset_;
@ -776,8 +821,8 @@ Bands const * Configuration::bands () const {return &m_->bands_;}
StationList * Configuration::stations () {return &m_->stations_;}
StationList const * Configuration::stations () const {return &m_->stations_;}
IARURegions::Region Configuration::region () const {return m_->region_;}
FrequencyList_v2 * Configuration::frequencies () {return &m_->frequencies_;}
FrequencyList_v2 const * Configuration::frequencies () const {return &m_->frequencies_;}
FrequencyList_v2_101 * Configuration::frequencies () {return &m_->frequencies_;}
FrequencyList_v2_101 const * Configuration::frequencies () const {return &m_->frequencies_;}
QStringListModel * Configuration::macros () {return &m_->macros_;}
QStringListModel const * Configuration::macros () const {return &m_->macros_;}
QDir Configuration::save_directory () const {return m_->save_directory_;}
@ -1045,7 +1090,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
throw std::runtime_error {"Failed to create save directory"};
}
// we now have a deafult save path that exists
// we now have a default save path that exists
// make sure samples directory exists
QString samples_dir {"samples"};
@ -1194,20 +1239,23 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
//
// setup working frequencies table model & view
//
frequencies_.sort (FrequencyList_v2::frequency_column);
frequencies_.sort (FrequencyList_v2_101::frequency_column);
ui_->frequencies_table_view->setModel (&next_frequencies_);
ui_->frequencies_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
ui_->frequencies_table_view->horizontalHeader ()->setResizeContentsPrecision (0);
ui_->frequencies_table_view->horizontalHeader ()->moveSection(8, 3); // swap preferred to be in front of description
ui_->frequencies_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
ui_->frequencies_table_view->verticalHeader ()->setResizeContentsPrecision (0);
ui_->frequencies_table_view->sortByColumn (FrequencyList_v2::frequency_column, Qt::AscendingOrder);
ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2::frequency_mhz_column, true);
ui_->frequencies_table_view->sortByColumn (FrequencyList_v2_101::frequency_column, Qt::AscendingOrder);
ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2_101::frequency_mhz_column, true);
ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2_101::source_column, true);
// delegates
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::frequency_column, new FrequencyDelegate {this});
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::region_column, new ForeignKeyDelegate {&regions_, 0, this});
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::mode_column, new ForeignKeyDelegate {&modes_, 0, this});
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2_101::frequency_column, new FrequencyDelegate {this});
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2_101::region_column, new ForeignKeyDelegate {&regions_, 0, this});
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2_101::mode_column, new ForeignKeyDelegate {&modes_, 0, this});
// actions
frequency_delete_action_ = new QAction {tr ("&Delete"), ui_->frequencies_table_view};
@ -1452,6 +1500,13 @@ void Configuration::impl::done (int r)
void Configuration::impl::read_settings ()
{
SettingsGroup g {settings_, "Configuration"};
LOG_INFO(QString{"Configuration Settings (%1)"}.arg(settings_->fileName()));
QStringList keys = settings_->allKeys();
//Q_FOREACH (auto const& item, keys)
//{
// LOG_INFO(QString{" %1 = %2"}.arg(item).arg(settings_->value(item).toString()));
//}
restoreGeometry (settings_->value ("window/geometry").toByteArray ());
my_callsign_ = settings_->value ("MyCall", QString {}).toString ();
@ -1505,12 +1560,20 @@ void Configuration::impl::read_settings ()
region_ = settings_->value ("Region", QVariant::fromValue (IARURegions::ALL)).value<IARURegions::Region> ();
if (settings_->contains ("FrequenciesForRegionModes"))
LOG_INFO(QString{"Reading frequencies"});
if (settings_->contains ("FrequenciesForRegionModes_v2"))
{
auto const& v = settings_->value ("FrequenciesForRegionModes");
LOG_INFO(QString{"read_settings found FrequenciesForRegionModes_v2"});
if (settings_->contains ("FrequenciesForRegionModes"))
{
LOG_INFO(QString{"read_settings ALSO found FrequenciesForRegionModes"});
}
auto const& v = settings_->value ("FrequenciesForRegionModes_v2");
if (v.isValid ())
{
frequencies_.frequency_list (v.value<FrequencyList_v2::FrequencyItems> ());
frequencies_.frequency_list (v.value<FrequencyList_v2_101::FrequencyItems> ());
}
else
{
@ -1519,7 +1582,34 @@ void Configuration::impl::read_settings ()
}
else
{
frequencies_.reset_to_defaults ();
LOG_INFO(QString{"read_settings looking for FrequenciesForRegionModes"});
if (settings_->contains ("FrequenciesForRegionModes")) // has the old ones.
{
LOG_INFO(QString{"found FrequenciesForRegionModes"});
auto const& v = settings_->value("FrequenciesForRegionModes");
LOG_INFO(QString{"v is %1"}.arg(v.typeName()));
if (v.isValid())
{
LOG_INFO(QString{"read_settings found VALID FrequenciesForRegionModes"});
FrequencyList_v2_101::FrequencyItems list;
FrequencyList_v2::FrequencyItems v100 = v.value<FrequencyList_v2::FrequencyItems>();
LOG_INFO(QString{"read_settings read %1 old_format items from FrequenciesForRegionModes"}.arg(v100.size()));
Q_FOREACH (auto const& item, v100)
{
list << FrequencyList_v2_101::Item{item.frequency_, item.mode_, item.region_, QString(), QString(), QDateTime(),
QDateTime(), false};
}
LOG_INFO(QString{"converted %1 items to FrequenciesForRegionModes_v2"}.arg(list.size()));
frequencies_.frequency_list(list);
}
else
{
LOG_INFO(QString{"read_settings INVALID FrequenciesForRegionModes"});
frequencies_.reset_to_defaults();
}
}
}
stations_.station_list (settings_->value ("stations").value<StationList::Stations> ());
@ -1661,8 +1751,8 @@ void Configuration::impl::write_settings ()
settings_->setValue ("After73", id_after_73_);
settings_->setValue ("TxQSYAllowed", tx_QSY_allowed_);
settings_->setValue ("Macros", macros_.stringList ());
settings_->setValue ("FrequenciesForRegionModes", QVariant::fromValue (frequencies_.frequency_list ()));
settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ()));
settings_->setValue ("FrequenciesForRegionModes_v2", QVariant::fromValue (frequencies_.frequency_list ()));
settings_->setValue ("DecodeHighlighting", QVariant::fromValue (decode_highlighing_model_.items ()));
settings_->setValue ("HighlightByMode", highlight_by_mode_);
settings_->setValue ("OnlyFieldsSought", highlight_only_fields_);
@ -1989,7 +2079,6 @@ TransceiverFactory::ParameterPack Configuration::impl::gather_rig_data ()
void Configuration::impl::accept ()
{
// Called when OK button is clicked.
if (!validate ())
{
return; // not accepting
@ -2190,7 +2279,7 @@ void Configuration::impl::accept ()
if (frequencies_.frequency_list () != next_frequencies_.frequency_list ())
{
frequencies_.frequency_list (next_frequencies_.frequency_list ());
frequencies_.sort (FrequencyList_v2::frequency_column);
frequencies_.sort (FrequencyList_v2_101::frequency_column);
}
if (stations_.station_list () != next_stations_.station_list ())
@ -2533,17 +2622,25 @@ void Configuration::impl::check_multicast (QHostAddress const& ha)
udp_server_name_edited_ = false;
}
void Configuration::impl::size_frequency_table_columns()
{
ui_->frequencies_table_view->setVisible(false);
ui_->frequencies_table_view->resizeColumnsToContents();
ui_->frequencies_table_view->setVisible(true);
}
void Configuration::impl::delete_frequencies ()
{
auto selection_model = ui_->frequencies_table_view->selectionModel ();
selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
next_frequencies_.removeDisjointRows (selection_model->selectedRows ());
ui_->frequencies_table_view->resizeColumnToContents (FrequencyList_v2::mode_column);
ui_->frequencies_table_view->resizeColumnToContents (FrequencyList_v2_101::mode_column);
size_frequency_table_columns ();
}
void Configuration::impl::load_frequencies ()
{
auto file_name = QFileDialog::getOpenFileName (this, tr ("Load Working Frequencies"), writeable_data_dir_.absolutePath (), tr ("Frequency files (*.qrg);;All files (*.*)"));
auto file_name = QFileDialog::getOpenFileName (this, tr ("Load Working Frequencies"), writeable_data_dir_.absolutePath (), tr ("Frequency files (*.qrg *.qrg.json);;All files (*.*)"));
if (!file_name.isNull ())
{
auto const list = read_frequencies_file (file_name);
@ -2557,24 +2654,42 @@ void Configuration::impl::load_frequencies ()
{
next_frequencies_.frequency_list (list); // update the model
}
size_frequency_table_columns();
}
}
void Configuration::impl::merge_frequencies ()
{
auto file_name = QFileDialog::getOpenFileName (this, tr ("Merge Working Frequencies"), writeable_data_dir_.absolutePath (), tr ("Frequency files (*.qrg);;All files (*.*)"));
auto file_name = QFileDialog::getOpenFileName (this, tr ("Merge Working Frequencies"), writeable_data_dir_.absolutePath (), tr ("Frequency files (*.qrg *.qrg.json);;All files (*.*)"));
if (!file_name.isNull ())
{
next_frequencies_.frequency_list_merge (read_frequencies_file (file_name)); // update the model
size_frequency_table_columns();
}
}
FrequencyList_v2::FrequencyItems Configuration::impl::read_frequencies_file (QString const& file_name)
FrequencyList_v2_101::FrequencyItems Configuration::impl::read_frequencies_file (QString const& file_name)
{
QFile frequencies_file {file_name};
frequencies_file.open (QFile::ReadOnly);
QDataStream ids {&frequencies_file};
FrequencyList_v2::FrequencyItems list;
FrequencyList_v2_101::FrequencyItems list;
FrequencyList_v2::FrequencyItems list_v100;
// read file as json if ends with qrg.json.
if (file_name.endsWith(".qrg.json", Qt::CaseInsensitive))
{
try
{
list = FrequencyList_v2_101::from_json_file(&frequencies_file);
}
catch (ReadFileException const &e)
{
MessageBox::critical_message(this, tr("Error reading frequency file"), e.message_);
}
return list;
}
quint32 magic;
ids >> magic;
if (qrg_magic != magic)
@ -2593,8 +2708,20 @@ FrequencyList_v2::FrequencyItems Configuration::impl::read_frequencies_file (QSt
}
// de-serialize the data using version if necessary to
// handle old schemata
ids >> list;
// handle old schema
if (version == qrg_version_100)
{
ids >> list_v100;
Q_FOREACH (auto const& item, list_v100)
{
list << FrequencyList_v2_101::Item{item.frequency_, item.mode_, item.region_, QString(), QString(), QDateTime(),
QDateTime(), false};
}
}
else
{
ids >> list;
}
if (ids.status () != QDataStream::Ok || !ids.atEnd ())
{
@ -2602,18 +2729,21 @@ FrequencyList_v2::FrequencyItems Configuration::impl::read_frequencies_file (QSt
list.clear ();
return list;
}
return list;
}
void Configuration::impl::save_frequencies ()
{
auto file_name = QFileDialog::getSaveFileName (this, tr ("Save Working Frequencies"), writeable_data_dir_.absolutePath (), tr ("Frequency files (*.qrg);;All files (*.*)"));
auto file_name = QFileDialog::getSaveFileName (this, tr ("Save Working Frequencies"), writeable_data_dir_.absolutePath (), tr ("Frequency files (*.qrg *.qrg.json);;All files (*.*)"));
if (!file_name.isNull ())
{
bool b_write_json = file_name.endsWith(".qrg.json", Qt::CaseInsensitive);
QFile frequencies_file {file_name};
frequencies_file.open (QFile::WriteOnly);
QDataStream ods {&frequencies_file};
auto selection_model = ui_->frequencies_table_view->selectionModel ();
if (selection_model->hasSelection ()
&& MessageBox::Yes == MessageBox::query_message (this
@ -2623,11 +2753,28 @@ void Configuration::impl::save_frequencies ()
"Click No to save all.")))
{
selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
ods << qrg_magic << qrg_version << next_frequencies_.frequency_list (selection_model->selectedRows ());
if (b_write_json)
{
next_frequencies_.to_json_file(&frequencies_file, "0x" + QString::number(qrg_magic, 16).toUpper(),
"0x" + QString::number(qrg_version, 16).toUpper(),
next_frequencies_.frequency_list(selection_model->selectedRows()));
} else
{
ods << qrg_magic << qrg_version << next_frequencies_.frequency_list(selection_model->selectedRows());
}
}
else
{
ods << qrg_magic << qrg_version << next_frequencies_.frequency_list ();
if (b_write_json)
{
next_frequencies_.to_json_file(&frequencies_file,
"0x" + QString::number(qrg_magic, 16).toUpper(),
"0x" + QString::number(qrg_version, 16).toUpper(),
next_frequencies_.frequency_list());
} else
{
ods << qrg_magic << qrg_version << next_frequencies_.frequency_list();
}
}
}
}
@ -2641,6 +2788,7 @@ void Configuration::impl::reset_frequencies ()
{
next_frequencies_.reset_to_defaults ();
}
size_frequency_table_columns ();
}
void Configuration::impl::insert_frequency ()
@ -2648,7 +2796,8 @@ void Configuration::impl::insert_frequency ()
if (QDialog::Accepted == frequency_dialog_->exec ())
{
ui_->frequencies_table_view->setCurrentIndex (next_frequencies_.add (frequency_dialog_->item ()));
ui_->frequencies_table_view->resizeColumnToContents (FrequencyList_v2::mode_column);
ui_->frequencies_table_view->resizeColumnToContents (FrequencyList_v2_101::mode_column);
size_frequency_table_columns();
}
}

View File

@ -18,7 +18,7 @@ class QAudioDeviceInfo;
class QDir;
class QNetworkAccessManager;
class Bands;
class FrequencyList_v2;
class FrequencyList_v2_101;
class StationList;
class QStringListModel;
class LotWUsers;
@ -164,8 +164,8 @@ public:
Bands * bands ();
Bands const * bands () const;
IARURegions::Region region () const;
FrequencyList_v2 * frequencies ();
FrequencyList_v2 const * frequencies () const;
FrequencyList_v2_101 * frequencies ();
FrequencyList_v2_101 const * frequencies () const;
StationList * stations ();
StationList const * stations () const;
QStringListModel * macros ();

View File

@ -52,9 +52,13 @@ void register_types ()
item_editor_factory->registerEditor (qMetaTypeId<QDateTime> (), new QStandardItemEditorCreator<DateTimeEdit> ());
// Frequency list model
// V101 Frequency list model
qRegisterMetaTypeStreamOperators<FrequencyList_v2_101::Item> ("Item_v2_101");
QMetaType::registerConverter<FrequencyList_v2_101::Item, QString> (&FrequencyList_v2_101::Item::toString);
qRegisterMetaTypeStreamOperators<FrequencyList_v2_101::FrequencyItems> ("FrequencyItems_v2_101");
// V100 Frequency list model
qRegisterMetaTypeStreamOperators<FrequencyList_v2::Item> ("Item_v2");
QMetaType::registerConverter<FrequencyList_v2::Item, QString> (&FrequencyList_v2::Item::toString);
qRegisterMetaTypeStreamOperators<FrequencyList_v2::FrequencyItems> ("FrequencyItems_v2");
// defunct old versions

94
NEWS
View File

@ -11,11 +11,103 @@
Copyright 2001 - 2022 by Joe Taylor, K1JT, and the WSJT Development Team
Release: WSJT-X 2.6.0-rc5
November 29, 2022
-------------------------
WSJT-X 2.6.0 Release Candidate 5 brings a number of improvements as
well as some bug fixes.
In program WSJT-X:
- Better calibration for FST4/W SNR estimates.
- Improved FT8 decoding on crowded bands.
- The Working frequency table now offers the following options:
- Better handling of more than one frequency per band.
- Set your preferred frequencies, WSJT-X always comes back to these
QRGs when changing band or mode.
- You can label your frequencies with discriptions (e.g. DXp AB0YXZ).
- Option to set Start and End Date/Time, so that the frequencies
automatically appear and disappear. Useful for contest or
DXpedition QRGs.
- Load a frequency table from a file to easily get all such data
implemented.
- In Fox mode, there are now a few additional functions that allow
operators to react even better to different QSO situations:
- A new two-column table in Tab 2 provides a better overview of
the queue and of the callsigns with QSOs in progress.
- Fox operator can now change the ordering of callsigns in the
queue so that he can react if there is only a narrow time slot
for a particular QSO due to propagation.
- Fox now responds for another two cycles to stations whose
report was not received, increasing the success rate for a
difficult QSO.
- Correct a flaw in Hound mode that sometimes prevented completion of
QSOs with non-standard calls.
- Improvements to EME Echo mode:
- New control "Avg" sets the number of Echo cycles to be averaged.
- New capability to display measurements of wideband noise power as
a function of time. This can be useful for measuring Sun noise,
antenna tracking errors, and the like.
- Several minor bug fixes
- Correct a flaw that prevented WSJT-X from always initializing
correctly when special operating activities were enabled.
- Correct a flaw that caused wrong Tx frequencies to be written to
ALL.TXT.
- The GUI has been improved regarding some details. The controls now
scale better at different font sizes and on different operating
systems.
- When in Hound mode and click the "H" button again, the frequency
is now kept. This gives the user the following two options to return
to normal FT8 mode:
- Click the "H" button again. Then you will stay on the QRG.
- Click the "FT8" button (or use the Settings menu). It brings
you back to the default FT8 QRG.
- Decodes flagged as 'a7' are now disabled when "Enable AP" is not
checked, and during the first period after a band change.
- The network address of the UDP server is now checked for errors
before being accepted.
- Some improvements to the DX Lab Suite Commander interface.
- Correct some possible flaws that could cause segfault errors in
certain unusual situations.
- Warnings on dropped audio have been disabled for now, as detection
has turned out to be not reliable enough.
- Correct a long-standing flaw which caused the "Transmit digital gain"
overlay toappear somewhere on the screen.
- "Highlight DX Call" now also works when the other station is <...>.
- CQ messages without a grid are now sent to PSK reporter.
- Several other minor corrections (tool tips, etc.).
Program MAP65 (Windows only) includes several minor bug fixes and two
tentative new features:
- an aid for measuring antenna pointing errors
- an ability to read the file wsjtx.log (kept by WSJT-X) to recognize
EME contest dupes.
Release: WSJT-X 2.6.0-rc4
September 8, 2022
-------------------------
WSJT-X 2.6.0 Release Candidate 4 provides further improvements to Echo mode, a new File menu item, and several bug fixes.
WSJT-X 2.6.0 Release Candidate 4 provides further improvements to Echo
mode, a new File menu item, and several bug fixes.
- New features and fixes for Echo mode
- Created a new simulator echosim[.exe]

View File

@ -11,11 +11,103 @@
Copyright 2001 - 2022 by Joe Taylor, K1JT, and the WSJT Development Team
Release: WSJT-X 2.6.0-rc5
November 29, 2022
-------------------------
WSJT-X 2.6.0 Release Candidate 5 brings a number of improvements as
well as some bug fixes.
In program WSJT-X:
- Better calibration for FST4/W SNR estimates.
- Improved FT8 decoding on crowded bands.
- The Working frequency table now offers the following options:
- Better handling of more than one frequency per band.
- Set your preferred frequencies, WSJT-X always comes back to these
QRGs when changing band or mode.
- You can label your frequencies with discriptions (e.g. DXp AB0YXZ).
- Option to set Start and End Date/Time, so that the frequencies
automatically appear and disappear. Useful for contest or
DXpedition QRGs.
- Load a frequency table from a file to easily get all such data
implemented.
- In Fox mode, there are now a few additional functions that allow
operators to react even better to different QSO situations:
- A new two-column table in Tab 2 provides a better overview of
the queue and of the callsigns with QSOs in progress.
- Fox operator can now change the ordering of callsigns in the
queue so that he can react if there is only a narrow time slot
for a particular QSO due to propagation.
- Fox now responds for another two cycles to stations whose
report was not received, increasing the success rate for a
difficult QSO.
- Correct a flaw in Hound mode that sometimes prevented completion of
QSOs with non-standard calls.
- Improvements to EME Echo mode:
- New control "Avg" sets the number of Echo cycles to be averaged.
- New capability to display measurements of wideband noise power as
a function of time. This can be useful for measuring Sun noise,
antenna tracking errors, and the like.
- Several minor bug fixes
- Correct a flaw that prevented WSJT-X from always initializing
correctly when special operating activities were enabled.
- Correct a flaw that caused wrong Tx frequencies to be written to
ALL.TXT.
- The GUI has been improved regarding some details. The controls now
scale better at different font sizes and on different operating
systems.
- When in Hound mode and click the "H" button again, the frequency
is now kept. This gives the user the following two options to return
to normal FT8 mode:
- Click the "H" button again. Then you will stay on the QRG.
- Click the "FT8" button (or use the Settings menu). It brings
you back to the default FT8 QRG.
- Decodes flagged as 'a7' are now disabled when "Enable AP" is not
checked, and during the first period after a band change.
- The network address of the UDP server is now checked for errors
before being accepted.
- Some improvements to the DX Lab Suite Commander interface.
- Correct some possible flaws that could cause segfault errors in
certain unusual situations.
- Warnings on dropped audio have been disabled for now, as detection
has turned out to be not reliable enough.
- Correct a long-standing flaw which caused the "Transmit digital gain"
overlay toappear somewhere on the screen.
- "Highlight DX Call" now also works when the other station is <...>.
- CQ messages without a grid are now sent to PSK reporter.
- Several other minor corrections (tool tips, etc.).
Program MAP65 (Windows only) includes several minor bug fixes and two
tentative new features:
- an aid for measuring antenna pointing errors
- an ability to read the file wsjtx.log (kept by WSJT-X) to recognize
EME contest dupes.
Release: WSJT-X 2.6.0-rc4
September 8, 2022
-------------------------
WSJT-X 2.6.0 Release Candidate 4 provides further improvements to Echo mode, a new File menu item, and several bug fixes.
WSJT-X 2.6.0 Release Candidate 4 provides further improvements to Echo
mode, a new File menu item, and several bug fixes.
- New features and fixes for Echo mode
- Created a new simulator echosim[.exe]

View File

@ -41,7 +41,7 @@ class QWidget;
// storage using the provided QSettings object instance.
//
// A passed in Configuration object instance is used to query the
// FrequencyList_v2 model to determine working frequencies for each
// FrequencyList_v2_101 model to determine working frequencies for each
// band. The row index of this model is returned by this classes
// hopping scheduling method so it may be conveniently used to select
// a new working frequency by a client.

View File

@ -0,0 +1,26 @@
//
// Moved from Configuration.cpp
//
#include "MessageItemDelegate.hpp"
#include <QLineEdit>
#include <QRegExpValidator>
//
// Class MessageItemDelegate
//
// Item delegate for message entry such as free text message macros.
//
MessageItemDelegate::MessageItemDelegate(QObject *parent): QStyledItemDelegate{parent}
{
}
QWidget *MessageItemDelegate::createEditor(QWidget *parent, QStyleOptionViewItem const &, QModelIndex const &) const
{
QRegularExpression message_alphabet{"[- @A-Za-z0-9+./?#<>;$]*"};
auto editor = new QLineEdit{parent};
editor->setFrame(false);
editor->setValidator(new QRegularExpressionValidator{message_alphabet, editor});
return editor;
}

View File

@ -0,0 +1,20 @@
//
//
//
#ifndef WSJTX_MESSAGEITEMDELEGATE_H
#define WSJTX_MESSAGEITEMDELEGATE_H
#include <QStyledItemDelegate>
class MessageItemDelegate: public QStyledItemDelegate
{
Q_OBJECT
public:
explicit MessageItemDelegate(QObject *parent = nullptr);
QWidget *createEditor(QWidget *parent, QStyleOptionViewItem const & /* option*/
, QModelIndex const & /* index */
) const override;
};
#endif //WSJTX_MESSAGEITEMDELEGATE_H

View File

@ -24,7 +24,7 @@
//
// Implements the QAbstractTableModel interface as an immutable table
// where rows are bands and columns are band name, lower frequency
// limit and, upper ferquency limit respectively.
// limit and, upper frequency limit respectively.
//
class Bands final
: public QAbstractTableModel

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,11 @@
#include <QList>
#include <QSortFilterProxyModel>
#include <QDateTime>
#include <QJsonObject>
#include <QJsonDocument>
#include <QFile>
#include <QException>
#include "Radio.hpp"
#include "IARURegions.hpp"
@ -37,7 +42,7 @@ class Bands;
// Implements the QSortFilterProxyModel interface for a list of spot
// frequencies.
//
class FrequencyList_v2 final
class FrequencyList_v2_101 final
: public QSortFilterProxyModel
{
Q_OBJECT;
@ -52,18 +57,26 @@ public:
Frequency frequency_;
Mode mode_;
Region region_;
QString description_;
QString source_;
QDateTime start_time_;
QDateTime end_time_;
bool preferred_; // preferred frequency for this band and mode
QString toString () const;
bool isSane() const;
QJsonObject toJson () const;
};
using FrequencyItems = QList<Item>;
using BandSet = QSet<QString>;
enum Column {region_column, mode_column, frequency_column, frequency_mhz_column, SENTINAL};
enum Column {region_column, mode_column, frequency_column, frequency_mhz_column, description_column, start_time_column, end_time_column, source_column, preferred_column, SENTINAL};
// an iterator that meets the requirements of the C++ for range statement
class const_iterator
{
public:
const_iterator (FrequencyList_v2 const * parent, int row)
const_iterator (FrequencyList_v2_101 const * parent, int row)
: parent_ {parent}
, row_ {row}
{
@ -76,18 +89,21 @@ public:
const_iterator& operator ++ ();
private:
FrequencyList_v2 const * parent_;
FrequencyList_v2_101 const * parent_;
int row_;
};
explicit FrequencyList_v2 (Bands const *, QObject * parent = nullptr);
~FrequencyList_v2 ();
explicit FrequencyList_v2_101 (Bands const *, QObject * parent = nullptr);
~FrequencyList_v2_101 ();
// Load and store underlying items
FrequencyItems frequency_list (FrequencyItems);
FrequencyItems const& frequency_list () const;
FrequencyItems frequency_list (QModelIndexList const&) const;
void frequency_list_merge (FrequencyItems const&);
void to_json_file(QFile *, QString, QString, FrequencyItems const&);
static FrequencyItems from_json_file(QFile *);
// Iterators for the sorted and filtered items
//
@ -116,7 +132,7 @@ public:
int best_working_frequency (QString const& band) const;
// Set filter
Q_SLOT void filter (Region, Mode);
Q_SLOT void filter (Region, Mode, bool);
// Reset
Q_SLOT void reset_to_defaults ();
@ -129,6 +145,9 @@ public:
// Proxy API
bool filterAcceptsRow (int source_row, QModelIndex const& parent) const override;
// Refresh the filter based on the current filter settings (underlying data may have changed)
void filter_refresh ();
// Custom roles.
static int constexpr SortRole = Qt::UserRole;
@ -138,25 +157,56 @@ private:
};
inline
bool operator == (FrequencyList_v2::Item const& lhs, FrequencyList_v2::Item const& rhs)
bool operator == (FrequencyList_v2_101::Item const& lhs, FrequencyList_v2_101::Item const& rhs)
{
return
lhs.frequency_ == rhs.frequency_
&& lhs.region_ == rhs.region_
&& lhs.mode_ == rhs.mode_;
&& lhs.mode_ == rhs.mode_
&& lhs.description_ == rhs.description_
&& lhs.source_ == rhs.source_
&& lhs.start_time_ == rhs.start_time_
&& lhs.end_time_ == rhs.end_time_
&& lhs.preferred_ == rhs.preferred_;
}
QDataStream& operator << (QDataStream&, FrequencyList_v2_101::Item const&);
QDataStream& operator >> (QDataStream&, FrequencyList_v2_101::Item&);
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug, FrequencyList_v2_101::Item const&);
#endif
Q_DECLARE_METATYPE (FrequencyList_v2_101::Item);
Q_DECLARE_METATYPE (FrequencyList_v2_101::FrequencyItems);
class FrequencyList_v2 final
{
public:
using Frequency = Radio::Frequency;
using Mode = Modes::Mode;
using Region = IARURegions::Region;
struct Item
{
Frequency frequency_;
Mode mode_;
Region region_;
QString toString () const;
};
using FrequencyItems = QList<Item>;
private:
FrequencyItems frequency_list_;
};
QDataStream& operator << (QDataStream&, FrequencyList_v2::Item const&);
QDataStream& operator >> (QDataStream&, FrequencyList_v2::Item&);
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug, FrequencyList_v2::Item const&);
#endif
Q_DECLARE_METATYPE (FrequencyList_v2::Item);
Q_DECLARE_METATYPE (FrequencyList_v2::FrequencyItems);
//
// Obsolete version of FrequencyList no longer used but needed to
// allow loading and saving of old settings contents without damage
@ -184,4 +234,18 @@ QDataStream& operator >> (QDataStream&, FrequencyList::Item&);
Q_DECLARE_METATYPE (FrequencyList::Item);
Q_DECLARE_METATYPE (FrequencyList::FrequencyItems);
class ReadFileException : public QException {
public:
ReadFileException (QString const& message)
: message_ {message}
{
}
void raise () const override { throw *this; }
ReadFileException * clone () const override { return new ReadFileException {*this}; }
QString filename_;
QString message_;
};
#endif

View File

@ -527,7 +527,7 @@ bool StationList::impl::dropMimeData (QMimeData const * data, Qt::DropAction act
QDataStream stream {&encoded_data, QIODevice::ReadOnly};
while (!stream.atEnd ())
{
FrequencyList_v2::Item item;
FrequencyList_v2_101::Item item;
stream >> item;
auto const& band = bands_->find (item.frequency_);
if (stations_.cend () == std::find_if (stations_.cbegin ()

View File

@ -1477,7 +1477,7 @@ Error: %2 - %3</translation>
</message>
</context>
<context>
<name>FrequencyList_v2</name>
<name>FrequencyList_v2_100</name>
<message>
<location filename="../models/FrequencyList.cpp" line="680"/>
<location filename="../models/FrequencyList.cpp" line="836"/>

View File

@ -1630,7 +1630,7 @@ Error: %2 - %3</translation>
</message>
</context>
<context>
<name>FrequencyList_v2</name>
<name>FrequencyList_v2_100</name>
<message>
<location filename="../models/FrequencyList.cpp" line="680"/>
<location filename="../models/FrequencyList.cpp" line="836"/>

View File

@ -1475,7 +1475,7 @@ Error: %2 - %3</source>
</message>
</context>
<context>
<name>FrequencyList_v2</name>
<name>FrequencyList_v2_100</name>
<message>
<location filename="../models/FrequencyList.cpp" line="680"/>
<location filename="../models/FrequencyList.cpp" line="836"/>

View File

@ -1475,7 +1475,7 @@ Error: %2 - %3</source>
</message>
</context>
<context>
<name>FrequencyList_v2</name>
<name>FrequencyList_v2_100</name>
<message>
<location filename="../models/FrequencyList.cpp" line="680"/>
<location filename="../models/FrequencyList.cpp" line="836"/>

View File

@ -12,7 +12,7 @@
LiveFrequencyValidator::LiveFrequencyValidator (QComboBox * combo_box
, Bands const * bands
, FrequencyList_v2 const * frequencies
, FrequencyList_v2_101 const * frequencies
, Frequency const * nominal_frequency
, QWidget * parent)
: QRegExpValidator {

View File

@ -7,7 +7,7 @@
#include "Radio.hpp"
class Bands;
class FrequencyList_v2;
class FrequencyList_v2_101;
class QComboBox;
class QWidget;
@ -35,7 +35,7 @@ public:
LiveFrequencyValidator (QComboBox * combo_box // associated combo box
, Bands const * bands // bands model
, FrequencyList_v2 const * frequencies // working frequencies model
, FrequencyList_v2_101 const * frequencies // working frequencies model
, Frequency const * nominal_frequency
, QWidget * parent = nullptr);
@ -46,7 +46,7 @@ public:
private:
Bands const * bands_;
FrequencyList_v2 const * frequencies_;
FrequencyList_v2_101 const * frequencies_;
Frequency const * nominal_frequency_;
QComboBox * combo_box_;
};

View File

@ -15,7 +15,7 @@ BandComboBox::BandComboBox (QWidget * parent)
// item text.
void BandComboBox::showPopup ()
{
auto minimum_width = view ()->sizeHintForColumn (FrequencyList_v2::frequency_mhz_column);
auto minimum_width = view ()->sizeHintForColumn (FrequencyList_v2_101::frequency_mhz_column);
if (count () > maxVisibleItems ())
{
// for some as yet unknown reason, in FT8 mode the scrollbar

View File

@ -86,7 +86,7 @@ void DisplayText::mouseDoubleClickEvent(QMouseEvent *e)
void DisplayText::insertLineSpacer(QString const& line)
{
appendText (line, "#d3d3d3");
insertText (line, "#d3d3d3");
}
namespace
@ -123,11 +123,11 @@ namespace
}
}
void DisplayText::appendText(QString const& text, QColor bg, QColor fg
, QString const& call1, QString const& call2)
void DisplayText::insertText(QString const& text, QColor bg, QColor fg
, QString const& call1, QString const& call2, QTextCursor::MoveOperation location)
{
auto cursor = textCursor ();
cursor.movePosition (QTextCursor::End);
cursor.movePosition (location);
auto block_format = cursor.blockFormat ();
auto format = cursor.blockCharFormat ();
format.setFont (char_font_);
@ -484,7 +484,7 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
}
}
appendText (message.trimmed (), bg, fg, decodedText.call (), dxCall);
insertText (message.trimmed (), bg, fg, decodedText.call (), dxCall);
}
@ -516,18 +516,19 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx
QColor fg;
highlight_types types {Highlight::Tx};
set_colours (m_config, &bg, &fg, types);
appendText (t, bg, fg);
insertText (t, bg, fg);
}
void DisplayText::displayQSY(QString text)
{
QString t = QDateTime::currentDateTimeUtc().toString("hhmmss") + " " + text;
appendText (t, "hotpink");
insertText (t, "hotpink");
}
void DisplayText::displayFoxToBeCalled(QString t, QColor bg, QColor fg)
void DisplayText::displayHoundToBeCalled(QString t, bool bAtTop, QColor bg, QColor fg)
{
appendText (t, bg, fg);
if (bAtTop) t = t + "\n"; // need a newline when insertion at top
insertText(t, bg, fg, "", "", bAtTop ? QTextCursor::Start : QTextCursor::End);
}
namespace

View File

@ -33,7 +33,7 @@ public:
bool haveFSpread = false, float fSpread = 0.0, bool bDisplayPoints=false, int points=-99);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode, double TRperiod);
void displayQSY(QString text);
void displayFoxToBeCalled(QString t, QColor bg = QColor {}, QColor fg = QColor {});
void displayHoundToBeCalled(QString t, bool bAtTop=false, QColor bg = QColor {}, QColor fg = QColor {});
void new_period ();
QString CQPriority(){return m_CQPriority;};
qint32 m_points;
@ -42,8 +42,8 @@ public:
Q_SIGNAL void selectCallsign (Qt::KeyboardModifiers);
Q_SIGNAL void erased ();
Q_SLOT void appendText (QString const& text, QColor bg = QColor {}, QColor fg = QColor {}
, QString const& call1 = QString {}, QString const& call2 = QString {});
Q_SLOT void insertText (QString const& text, QColor bg = QColor {}, QColor fg = QColor {}
, QString const& call1 = QString {}, QString const& call2 = QString {}, QTextCursor::MoveOperation location=QTextCursor::End);
Q_SLOT void erase ();
Q_SLOT void highlight_callsign (QString const& callsign, QColor const& bg, QColor const& fg, bool last_period_only);
@ -62,6 +62,7 @@ private:
, QString const& currentMode, QString extra);
QFont char_font_;
QAction * erase_action_;
QHash<QString, QPair<QColor, QColor>> highlighted_calls_;
bool high_volume_;
QMetaObject::Connection vertical_scroll_connection_;

View File

@ -657,7 +657,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
connect(txMsgButtonGroup,SIGNAL(buttonClicked(int)),SLOT(set_ntx(int)));
connect (ui->decodedTextBrowser, &DisplayText::selectCallsign, this, &MainWindow::doubleClickOnCall2);
connect (ui->decodedTextBrowser2, &DisplayText::selectCallsign, this, &MainWindow::doubleClickOnCall);
connect (ui->textBrowser4, &DisplayText::selectCallsign, this, &MainWindow::doubleClickOnFoxQueue);
connect (ui->houndQueueTextBrowser, &DisplayText::selectCallsign, this, &MainWindow::doubleClickOnFoxQueue);
connect (ui->foxTxListTextBrowser, &DisplayText::selectCallsign, this, &MainWindow::doubleClickOnFoxInProgress);
connect (ui->decodedTextBrowser, &DisplayText::erased, this, &MainWindow::band_activity_cleared);
connect (ui->decodedTextBrowser2, &DisplayText::erased, this, &MainWindow::rx_frequency_activity_cleared);
@ -768,7 +769,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
// Hook up working frequencies.
ui->bandComboBox->setModel (m_config.frequencies ());
ui->bandComboBox->setModelColumn (FrequencyList_v2::frequency_mhz_column);
ui->bandComboBox->setModelColumn (FrequencyList_v2_101::frequency_mhz_column);
// Enable live band combo box entry validation and action.
auto band_validator = new LiveFrequencyValidator {ui->bandComboBox
@ -1020,6 +1021,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_wideGraph->setMode(m_mode);
connect (&minuteTimer, &QTimer::timeout, this, &MainWindow::on_the_minute);
connect (&minuteTimer, &QTimer::timeout, this, &MainWindow::invalidate_frequencies_filter);
minuteTimer.setSingleShot (true);
minuteTimer.start (ms_minute_error () + 60 * 1000);
@ -1046,9 +1049,9 @@ void MainWindow::not_GA_warning_message ()
MessageBox::critical_message (this,
"This is a pre-release version of WSJT-X 2.6.0 made\n"
"available for testing purposes. By design it will\n"
"be nonfunctional after Dec 31, 2022.");
"be nonfunctional after Mar 31, 2023.");
auto now = QDateTime::currentDateTimeUtc ();
if (now >= QDateTime {{2022, 12, 31}, {23, 59, 59, 999}, Qt::UTC}) {
if (now >= QDateTime {{2023, 03, 31}, {23, 59, 59, 999}, Qt::UTC}) {
Q_EMIT finished ();
}
}
@ -1064,6 +1067,14 @@ void MainWindow::splash_done ()
m_splash && m_splash->close ();
}
void MainWindow::invalidate_frequencies_filter ()
{
// every interval, invalidate the frequency filter, so that if any
// working frequency goes in/out of scope, we pick it up.
m_config.frequencies ()->filter_refresh ();
ui->bandComboBox->update ();
}
void MainWindow::on_the_minute ()
{
if (minuteTimer.isSingleShot ())
@ -1427,9 +1438,14 @@ void MainWindow::setDecodedTextFont (QFont const& font)
{
ui->decodedTextBrowser->setContentFont (font);
ui->decodedTextBrowser2->setContentFont (font);
ui->textBrowser4->setContentFont(font);
ui->textBrowser4->displayFoxToBeCalled(" ");
ui->textBrowser4->setText("");
ui->houndQueueTextBrowser->setContentFont(font);
ui->houndQueueTextBrowser->displayHoundToBeCalled(" ");
ui->houndQueueTextBrowser->setText("");
ui->foxTxListTextBrowser->setContentFont(font);
ui->foxTxListTextBrowser->displayHoundToBeCalled(" ");
ui->foxTxListTextBrowser->setText("");
auto style_sheet = "QLabel {" + font_as_stylesheet (font) + '}';
ui->lh_decodes_headings_label->setStyleSheet (ui->lh_decodes_headings_label->styleSheet () + style_sheet);
ui->rh_decodes_headings_label->setStyleSheet (ui->rh_decodes_headings_label->styleSheet () + style_sheet);
@ -1655,7 +1671,7 @@ void MainWindow::dataSink(qint64 frames)
t = t.asprintf("%9.6f %5.2f %7d %7.1f %7d %7d %7d %7.1f %7.1f",hour,xlevel,
nDopTotal,width,echocom_.nsum,nqual,qRound(dfreq),sigdb,dBerr);
t = t0 + t;
if (ui) ui->decodedTextBrowser->appendText(t);
if (ui) ui->decodedTextBrowser->insertText(t);
t=t1+t;
write_all("Rx",t);
}
@ -2095,7 +2111,6 @@ void MainWindow::auto_tx_mode (bool state)
void MainWindow::keyPressEvent (QKeyEvent * e)
{
if(SpecOp::FOX == m_specOp) {
switch (e->key()) {
case Qt::Key_Return:
@ -2107,6 +2122,13 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
case Qt::Key_Backspace:
qDebug() << "Key Backspace";
return;
#ifdef DEBUG_FOX
case Qt::Key_X:
if(e->modifiers() & Qt::AltModifier) {
foxTest();
return;
}
#endif
}
QMainWindow::keyPressEvent (e);
}
@ -3873,8 +3895,13 @@ void MainWindow::readFromStdout() //readFromStdout
bool bProcessMsgNormally=ui->respondComboBox->currentText()=="CQ: First" or
(ui->respondComboBox->currentText()=="CQ: Max Dist" and m_ActiveStationsWidget==NULL) or
(m_ActiveStationsWidget!=NULL and !m_ActiveStationsWidget->isVisible());
QString t=decodedtext.messageWords()[4];
if(t.contains("R+") or t.contains("R-") or t=="R" or t=="RRR" or t=="RR73") bProcessMsgNormally=true;
if (decodedtext.messageWords().length() >= 2) {
QString t=decodedtext.messageWords()[2];
if(t.contains("R+") or t.contains("R-") or t=="R" or t=="RRR" or t=="RR73") bProcessMsgNormally=true;
}
else {
bProcessMsgNormally=true;
}
if(bProcessMsgNormally) {
m_bDoubleClicked=true;
m_bAutoReply = true;
@ -3885,6 +3912,9 @@ void MainWindow::readFromStdout() //readFromStdout
QString deCall;
QString deGrid;
decodedtext.deCallAndGrid(/*out*/deCall,deGrid);
// if they dont' send their grid we'll use ours and assume dx=0
if (deGrid.length() == 0) deGrid = m_config.my_grid();
if(deGrid.contains(grid_regexp) or
(deGrid.contains("+") or deGrid.contains("-"))) {
int points=0;
@ -4885,7 +4915,7 @@ void MainWindow::startTx2()
t = " Transmitting " + m_mode + " ----------------------- " +
m_config.bands ()->find (m_freqNominal);
t=beacon_start_time (m_TRperiod / 2) + ' ' + t.rightJustified (66, '-');
ui->decodedTextBrowser->appendText(t);
ui->decodedTextBrowser->insertText(t);
}
write_all("Tx",m_currentMessage);
}
@ -5164,7 +5194,7 @@ void MainWindow::doubleClickOnCall(Qt::KeyboardModifiers modifiers)
if(SpecOp::FOX==m_specOp and m_decodedText2) {
if(m_houndQueue.count()<10 and m_nSortedHounds>0) {
QString t=cursor.block().text();
selectHound(t);
selectHound(t, modifiers==(Qt::AltModifier)); // alt double-click gets put at top of queue
}
return;
}
@ -7196,7 +7226,7 @@ void MainWindow::on_actionFreqCal_triggered()
void MainWindow::switch_mode (Mode mode)
{
m_fastGraph->setMode(m_mode);
m_config.frequencies ()->filter (m_config.region (), mode);
m_config.frequencies ()->filter (m_config.region (), mode, true); // filter on current time
auto const& row = m_config.frequencies ()->best_working_frequency (m_freqNominal);
ui->bandComboBox->setCurrentIndex (row);
if (row >= 0) {
@ -7441,7 +7471,7 @@ void MainWindow::on_actionOpen_log_directory_triggered ()
void MainWindow::on_bandComboBox_currentIndexChanged (int index)
{
auto const& frequencies = m_config.frequencies ();
auto const& source_index = frequencies->mapToSource (frequencies->index (index, FrequencyList_v2::frequency_column));
auto const& source_index = frequencies->mapToSource (frequencies->index (index, FrequencyList_v2_101::frequency_column));
Frequency frequency {m_freqNominal};
if (source_index.isValid ())
{
@ -7469,7 +7499,7 @@ void MainWindow::on_bandComboBox_editTextChanged (QString const& text)
void MainWindow::on_bandComboBox_activated (int index)
{
auto const& frequencies = m_config.frequencies ();
auto const& source_index = frequencies->mapToSource (frequencies->index (index, FrequencyList_v2::frequency_column));
auto const& source_index = frequencies->mapToSource (frequencies->index (index, FrequencyList_v2_101::frequency_column));
Frequency frequency {m_freqNominal};
if (source_index.isValid ())
{
@ -7484,7 +7514,7 @@ void MainWindow::band_changed (Frequency f)
{
// Don't allow a7 decodes during the first period because they can be leftovers from the previous band
no_a7_decodes = true;
QTimer::singleShot ((int(1000.0*m_TRperiod)), [=] {no_a7_decodes = false;});
QTimer::singleShot ((int(1500.0*m_TRperiod)), [=] {no_a7_decodes = false;});
// Set the attenuation value if options are checked
if (m_config.pwrBandTxMemory() && !m_tune) {
@ -8506,7 +8536,7 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
t = " " + tr ("Receiving") + " " + m_mode + " ----------------------- " +
m_config.bands ()->find (m_dialFreqRxWSPR);
t=beacon_start_time (-m_TRperiod / 2) + ' ' + t.rightJustified (66, '-');
ui->decodedTextBrowser->appendText(t);
ui->decodedTextBrowser->insertText(t);
}
killFileTimer.start (45*1000); //Kill in 45s (for slow modes)
}
@ -8580,12 +8610,12 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
QString band;
Frequency f=1000000.0*rxFields.at(3).toDouble()+0.5;
band = ' ' + m_config.bands ()->find (f);
ui->decodedTextBrowser->appendText(band.rightJustified (71, '-'));
ui->decodedTextBrowser->insertText(band.rightJustified (71, '-'));
}
m_tBlankLine = rxLine.left(4);
}
m_nWSPRdecodes += 1;
ui->decodedTextBrowser->appendText(rxLine);
ui->decodedTextBrowser->insertText(rxLine);
}
}
}
@ -9168,7 +9198,9 @@ void MainWindow::on_pbFoxReset_clicked()
QFile f(m_config.temp_dir().absoluteFilePath("houndcallers.txt"));
f.remove();
ui->decodedTextBrowser->setText("");
ui->textBrowser4->setText("");
ui->houndQueueTextBrowser->setText("");
ui->foxTxListTextBrowser->setText("");
m_houndQueue.clear();
m_foxQSO.clear();
m_foxQSOinProgress.clear();
@ -9288,19 +9320,18 @@ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB)
}
//------------------------------------------------------------------------------
void MainWindow::selectHound(QString line)
void MainWindow::selectHound(QString line, bool bTopQueue)
{
/* Called from doubleClickOnCall() in DXpedition Fox mode.
* QString "line" is a user-selected line from left text window.
* The line may be selected by double-clicking; alternatively, hitting
* <Enter> is equivalent to double-clicking on the top-most line.
*/
if(line.length()==0) return;
QString houndCall=line.split(" ",SkipEmptyParts).at(0);
// Don't add a call already enqueued or in QSO
if(ui->textBrowser4->toPlainText().indexOf(houndCall) >= 0) return;
if(ui->houndQueueTextBrowser->toPlainText().indexOf(houndCall) >= 0) return;
QString houndGrid=line.split(" ",SkipEmptyParts).at(1); // Hound caller's grid
QString rpt=line.split(" ",SkipEmptyParts).at(2); // Hound SNR
@ -9310,16 +9341,25 @@ void MainWindow::selectHound(QString line)
ui->decodedTextBrowser->setText(m_houndCallers); // Populate left window with Hound callers
QString t1=houndCall + " ";
QString t2=rpt;
QString t1_with_grid;
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); // 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();
ui->houndQueueTextBrowser->displayHoundToBeCalled(t1, bTopQueue); // Add hound call and rpt to tb4
t1_with_grid=t1 + " " + houndGrid; // Append the grid
if (bTopQueue)
{
m_houndQueue.prepend(t1_with_grid); // Put this hound into the queue at the top
}
else
{
m_houndQueue.enqueue(t1_with_grid); // Put this hound into the queue
}
writeFoxQSO(" Sel: " + t1_with_grid);
QTextCursor cursor = ui->houndQueueTextBrowser->textCursor();
cursor.setPosition(0); // Scroll to top of list
ui->textBrowser4->setTextCursor(cursor);
ui->houndQueueTextBrowser->setTextCursor(cursor);
}
//------------------------------------------------------------------------------
@ -9348,7 +9388,7 @@ void MainWindow::houndCallers()
houndCall=line.mid(0,i0);
paddedHoundCall=houndCall + " ";
//Don't list a hound already in the queue
if(!ui->textBrowser4->toPlainText().contains(paddedHoundCall)) {
if(!ui->houndQueueTextBrowser->toPlainText().contains(paddedHoundCall)) {
if(m_loggedByFox[houndCall].contains(m_lastBand)) continue; //already logged on this band
if(m_foxQSO.contains(houndCall)) continue; //still in the QSO map
auto const& entity = m_logBook.countries ()->lookup (houndCall);
@ -9405,6 +9445,19 @@ void MainWindow::foxRxSequencer(QString msg, QString houndCall, QString rptRcvd)
}
}
}
void MainWindow::updateFoxQSOsInProgressDisplay()
{
ui->foxTxListTextBrowser->clear();
for (int i = 0; i < m_foxQSOinProgress.count(); i++)
{
//First do those for QSOs in progress
QString hc = m_foxQSOinProgress.at(i);
QString status = m_foxQSO[hc].ncall > m_maxStrikes ? QString(" (rx) ") : QString(" ");
QString str = (hc + " ").left(13) + QString::number(m_foxQSO[hc].ncall) + status;
ui->foxTxListTextBrowser->displayHoundToBeCalled(str);
}
}
void MainWindow::foxTxSequencer()
{
@ -9601,13 +9654,14 @@ Transmit:
m_foxLogWindow->rate (m_foxRateQueue.size ());
m_foxLogWindow->queued (m_foxQSOinProgress.count ());
}
updateFoxQSOsInProgressDisplay();
}
void MainWindow::rm_tb4(QString houndCall)
{
if(houndCall=="") return;
QString t="";
QString tb4=ui->textBrowser4->toPlainText();
QString tb4=ui->houndQueueTextBrowser->toPlainText();
QStringList list=tb4.split("\n");
int n=list.size();
int j=0;
@ -9620,24 +9674,78 @@ void MainWindow::rm_tb4(QString houndCall)
}
}
t.replace("\n\n","\n");
ui->textBrowser4->setText(t);
ui->houndQueueTextBrowser->setText(t);
}
void MainWindow::doubleClickOnFoxQueue(Qt::KeyboardModifiers modifiers)
{
if(modifiers==9999) return; //Silence compiler warning
QTextCursor cursor=ui->textBrowser4->textCursor();
QTextCursor cursor=ui->houndQueueTextBrowser->textCursor();
cursor.setPosition(cursor.selectionStart());
QString houndCall=cursor.block().text().mid(0,12).trimmed();
rm_tb4(houndCall);
writeFoxQSO(" Del: " + houndCall);
QQueue<QString> tmpQueue;
while(!m_houndQueue.isEmpty()) {
QString t=m_houndQueue.dequeue();
QString hc=t.mid(0,12).trimmed();
if(hc != houndCall) tmpQueue.enqueue(t);
}
m_houndQueue.swap(tmpQueue);
QString houndLine=cursor.block().text();
QString houndCall=houndLine.mid(0,12).trimmed();
if (modifiers == (Qt::AltModifier))
{
//Alt-click on a Fox queue entry - put on top of queue
// remove
for(auto i=0; i<m_houndQueue.size(); i++) {
QString t = m_houndQueue[i];
QString hc = t.mid(0, 12).trimmed();
if (hc == houndCall) {
m_houndQueue.removeAt(i);
break;
}
}
m_houndQueue.prepend(houndLine);
ui->houndQueueTextBrowser->clear();
for (QString line: m_houndQueue)
{
ui->houndQueueTextBrowser->displayHoundToBeCalled(line.mid(0,16), false);
}
} else
{
rm_tb4(houndCall);
writeFoxQSO(" Del: " + houndCall);
QQueue <QString> tmpQueue;
while (!m_houndQueue.isEmpty())
{
QString t = m_houndQueue.dequeue();
QString hc = t.mid(0, 12).trimmed();
if (hc != houndCall) tmpQueue.enqueue(t);
}
m_houndQueue.swap(tmpQueue);
}
}
void MainWindow::doubleClickOnFoxInProgress(Qt::KeyboardModifiers modifiers)
{
if (modifiers == 9999) return; //Silence compiler warning
QTextCursor cursor = ui->foxTxListTextBrowser->textCursor();
cursor.setPosition(cursor.selectionStart());
QString houndLine = cursor.block().text();
QString houndCall = houndLine.mid(0, 12).trimmed();
if (modifiers == 0)
{
m_foxQSO[houndCall].ncall = m_maxStrikes + 1; // time them out
updateFoxQSOsInProgressDisplay();
}
}
void MainWindow::foxQueueTopCallCommand()
{
m_decodedText2 = true;
if(SpecOp::FOX==m_specOp && m_decodedText2 && m_houndQueue.count() < 10)
{
QTextCursor cursor = ui->decodedTextBrowser->textCursor();
cursor.setPosition(cursor.selectionStart());
QString houndCallLine = cursor.block().text();
writeFoxQSO(" QTop: " + houndCallLine);
selectHound(houndCallLine, true); // alt double-click gets put at top of queue
}
}
void MainWindow::foxGenWaveform(int i,QString fm)
@ -9691,14 +9799,29 @@ void MainWindow::writeFoxQSO(QString const& msg)
/*################################################################################### */
void MainWindow::foxTest()
{
QFile f("steps.txt");
if(!f.open(QIODevice::ReadOnly | QIODevice::Text)) return;
QString curdir = QDir::currentPath();
bool b_hounds_written = false;
QFile fdiag("diag.txt");
QFile fdiag(m_config.writeable_data_dir ().absoluteFilePath("diag.txt"));
if(!fdiag.open(QIODevice::WriteOnly | QIODevice::Text)) return;
QFile f(m_config.writeable_data_dir ().absoluteFilePath("steps.txt"));
if(!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
fdiag.write("Cannot open steps.txt");
return;
}
QTextStream s(&f);
QTextStream sdiag(&fdiag);
QFile fhounds(m_config.temp_dir().absoluteFilePath("houndcallers.txt"));
if(!fhounds.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
{
sdiag << "can't write to houndcallers.txt";
return;
}
QTextStream houndstream(&fhounds);
QString line;
QString t;
QString msg;
@ -9716,7 +9839,19 @@ void MainWindow::foxTest()
}
if(line.contains("Sel:")) {
t=line.mid(43,6) + " " + line.mid(54,4) + " " + line.mid(50,3);
selectHound(t);
selectHound(t, false);
}
auto line_trimmed = line.trimmed();
if(line_trimmed.startsWith("Hound:")) {
t=line_trimmed.mid(6,-1).trimmed();
b_hounds_written = true;
houndstream << t
#if QT_VERSION >= QT_VERSION_CHECK (5, 15, 0)
<< Qt::endl
#else
<< endl
#endif
;
}
if(line.contains("Del:")) {
@ -9756,6 +9891,11 @@ void MainWindow::foxTest()
sdiag << t << line.mid(37).trimmed() << "\n";
}
}
if (b_hounds_written)
{
fhounds.close();
houndCallers();
}
}
void MainWindow::write_all(QString txRx, QString message)

View File

@ -127,6 +127,7 @@ public slots:
void doubleClickOnCall (Qt::KeyboardModifiers);
void doubleClickOnCall2(Qt::KeyboardModifiers);
void doubleClickOnFoxQueue(Qt::KeyboardModifiers);
void doubleClickOnFoxInProgress(Qt::KeyboardModifiers modifiers);
void readFromStdout();
void p1ReadFromStdout();
void setXIT(int n, Frequency base = 0u);
@ -476,7 +477,7 @@ private:
qint32 m_k0;
qint32 m_kdone;
qint32 m_nPick;
FrequencyList_v2::const_iterator m_frequency_list_fcal_iter;
FrequencyList_v2_101::const_iterator m_frequency_list_fcal_iter;
qint32 m_nTx73;
qint32 m_UTCdisk;
qint32 m_wait;
@ -823,6 +824,7 @@ private:
void subProcessError (QProcess *, QProcess::ProcessError);
void statusUpdate () const;
void update_watchdog_label ();
void invalidate_frequencies_filter ();
void on_the_minute ();
void add_child_to_event_filter (QObject *);
void remove_child_from_event_filter (QObject *);
@ -832,8 +834,10 @@ private:
void displayWidgets(qint64 n);
QChar current_submode () const; // returns QChar {0} if submode is not appropriate
void write_transmit_entry (QString const& file_name);
void selectHound(QString t);
void selectHound(QString t, bool bTopQueue);
void houndCallers();
void updateFoxQSOsInProgressDisplay();
void foxQueueTopCallCommand();
void foxRxSequencer(QString msg, QString houndCall, QString rptRcvd);
void foxTxSequencer();
void foxGenWaveform(int i,QString fm);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>901</width>
<height>665</height>
<width>991</width>
<height>690</height>
</rect>
</property>
<property name="windowTitle">
@ -1018,7 +1018,7 @@ Yellow when too low</string>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6" stretch="0,1">
<layout class="QHBoxLayout" name="horizontalLayout_6" stretch="1,2">
<property name="leftMargin">
<number>0</number>
</property>
@ -1454,7 +1454,7 @@ When not checked you can view the calibration results.</string>
<item>
<widget class="QStackedWidget" name="opt_controls_stack">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="page_0">
<layout class="QVBoxLayout" name="verticalLayout">
@ -2005,10 +2005,31 @@ Double-click to reset to the standard 73 message</string>
<string>2</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_11" columnstretch="1,0">
<item row="0" column="1" rowspan="2">
<layout class="QGridLayout" name="gridLayout_10">
<item row="2" column="0">
<widget class="QSpinBox" name="sbMax_dB">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>4</number>
</property>
<item row="0" column="0" rowspan="2">
<layout class="QGridLayout" name="gridLayout" columnstretch="2,2,1">
<property name="topMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<item row="1" column="2">
<widget class="QComboBox" name="comboBoxHoundSort">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -2021,21 +2042,62 @@ Double-click to reset to the standard 73 message</string>
<height>16777215</height>
</size>
</property>
<property name="prefix">
<string>Max dB </string>
<property name="currentText">
<string>Random</string>
</property>
<property name="minimum">
<number>-15</number>
<property name="maxVisibleItems">
<number>5</number>
</property>
<property name="maximum">
<number>70</number>
<item>
<property name="text">
<string>Random</string>
</property>
</item>
<item>
<property name="text">
<string>Call</string>
</property>
</item>
<item>
<property name="text">
<string>Grid</string>
</property>
</item>
<item>
<property name="text">
<string>S/N (dB)</string>
</property>
</item>
<item>
<property name="text">
<string>Distance</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_queue">
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="value">
<number>30</number>
<property name="text">
<string>Queue</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="6" column="2">
<widget class="QCheckBox" name="cbMoreCQs">
<property name="text">
<string>More CQs</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QComboBox" name="comboBoxCQ">
<property name="currentText">
<string>CQ</string>
@ -2132,14 +2194,7 @@ Double-click to reset to the standard 73 message</string>
</item>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="pbFoxReset">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="2">
<widget class="QSpinBox" name="sbNlist">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -2167,7 +2222,35 @@ Double-click to reset to the standard 73 message</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="3" column="2">
<widget class="QSpinBox" name="sbMax_dB">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="prefix">
<string>Max dB </string>
</property>
<property name="minimum">
<number>-15</number>
</property>
<property name="maximum">
<number>70</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QSpinBox" name="sbNslots">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -2201,54 +2284,24 @@ Double-click to reset to the standard 73 message</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="comboBoxHoundSort">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="7" column="2">
<widget class="QPushButton" name="pbFoxReset">
<property name="text">
<string>Reset</string>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="currentText">
<string>Random</string>
</property>
<property name="maxVisibleItems">
<number>5</number>
</property>
<item>
<property name="text">
<string>Random</string>
</property>
</item>
<item>
<property name="text">
<string>Call</string>
</property>
</item>
<item>
<property name="text">
<string>Grid</string>
</property>
</item>
<item>
<property name="text">
<string>S/N (dB)</string>
</property>
</item>
<item>
<property name="text">
<string>Distance</string>
</property>
</item>
</widget>
</item>
<item row="7" column="0">
<item row="0" column="1">
<widget class="QLabel" name="label_inProcess">
<property name="text">
<string>In Progress</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="8" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -2261,34 +2314,49 @@ Double-click to reset to the standard 73 message</string>
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="cbMoreCQs">
<property name="text">
<string>More CQs</string>
<item row="1" column="1" rowspan="8">
<widget class="DisplayText" name="foxTxListTextBrowser">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="8">
<widget class="DisplayText" name="houndQueueTextBrowser">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="DisplayText" name="textBrowser4">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -3076,7 +3144,7 @@ QPushButton[state=&quot;ok&quot;] {
<rect>
<x>0</x>
<y>0</y>
<width>901</width>
<width>991</width>
<height>22</height>
</rect>
</property>
@ -3836,14 +3904,6 @@ QPushButton[state=&quot;ok&quot;] {
<tabstop>tx6</tabstop>
<tabstop>txrb6</tabstop>
<tabstop>txb6</tabstop>
<tabstop>textBrowser4</tabstop>
<tabstop>comboBoxHoundSort</tabstop>
<tabstop>sbNlist</tabstop>
<tabstop>sbMax_dB</tabstop>
<tabstop>sbNslots</tabstop>
<tabstop>comboBoxCQ</tabstop>
<tabstop>cbMoreCQs</tabstop>
<tabstop>pbFoxReset</tabstop>
<tabstop>WSPRfreqSpinBox</tabstop>
<tabstop>sbFST4W_RxFreq</tabstop>
<tabstop>sbFST4W_FTol</tabstop>