IARU region specific working frequencies

Working  frequencies can  be for  all regions  or for  individual IARU
regions. This allows each mode band  tuple to have one or more working
frequencies which  can include local  ones only offered when  the user
configures their IARU region.

Change  working  frequency  default   suggestions  to  better  fit  in
FT8. General  rule is FT8  is at JT65 -2kHz  except where that  is not
possible e.g. where  that would fall into a segment  not allocated for
narrow band data modes. For tight  bands like top band sqeeze existing
JT65 and JT allocations to allow space for FT8.

NOTE: this change changes the WSPR frequency on 80m to allow access to
JA stations that currently have no allocation where it was placed.

ALSO NOTE: the JT65 and JT9 frequencies for 80m move down 6 kHz, again
to  accommodate region  3  users. Other  appliactions  not within  our
control should be asked to move in step when 1.8.0 is released.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7810 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2017-07-07 23:11:41 +00:00
parent 3de4ef1f44
commit 94cec5bdc1
14 changed files with 865 additions and 395 deletions

View File

@ -183,6 +183,7 @@ set (wsjt_qt_CXXSRCS
WFPalette.cpp WFPalette.cpp
Radio.cpp Radio.cpp
RadioMetaType.cpp RadioMetaType.cpp
IARURegions.cpp
Bands.cpp Bands.cpp
Modes.cpp Modes.cpp
FrequencyList.cpp FrequencyList.cpp

View File

@ -172,6 +172,7 @@
#include "TransceiverFactory.hpp" #include "TransceiverFactory.hpp"
#include "Transceiver.hpp" #include "Transceiver.hpp"
#include "Bands.hpp" #include "Bands.hpp"
#include "IARURegions.hpp"
#include "Modes.hpp" #include "Modes.hpp"
#include "FrequencyList.hpp" #include "FrequencyList.hpp"
#include "StationList.hpp" #include "StationList.hpp"
@ -193,6 +194,10 @@ namespace
// QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"}; // QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"}; QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"};
// Magic numbers for file validation
constexpr quint32 qrg_magic {0xadbccbdb};
constexpr quint32 qrg_version {100}; // M.mm
} }
@ -205,14 +210,16 @@ class FrequencyDialog final
public: public:
using Item = FrequencyList::Item; using Item = FrequencyList::Item;
explicit FrequencyDialog (Modes * modes_model, QWidget * parent = nullptr) explicit FrequencyDialog (IARURegions * regions_model, Modes * modes_model, QWidget * parent = nullptr)
: QDialog {parent} : QDialog {parent}
{ {
setWindowTitle (QApplication::applicationName () + " - " + setWindowTitle (QApplication::applicationName () + " - " +
tr ("Add Frequency")); tr ("Add Frequency"));
region_combo_box_.setModel (regions_model);
mode_combo_box_.setModel (modes_model); mode_combo_box_.setModel (modes_model);
auto form_layout = new QFormLayout (); auto form_layout = new QFormLayout ();
form_layout->addRow (tr ("IARU &Region:"), &region_combo_box_);
form_layout->addRow (tr ("&Mode:"), &mode_combo_box_); form_layout->addRow (tr ("&Mode:"), &mode_combo_box_);
form_layout->addRow (tr ("&Frequency (MHz):"), &frequency_line_edit_); form_layout->addRow (tr ("&Frequency (MHz):"), &frequency_line_edit_);
@ -228,10 +235,13 @@ public:
Item item () const Item item () const
{ {
return {frequency_line_edit_.frequency (), Modes::value (mode_combo_box_.currentText ())}; return {frequency_line_edit_.frequency ()
, Modes::value (mode_combo_box_.currentText ())
, IARURegions::value (region_combo_box_.currentText ())};
} }
private: private:
QComboBox region_combo_box_;
QComboBox mode_combo_box_; QComboBox mode_combo_box_;
FrequencyLineEdit frequency_line_edit_; FrequencyLineEdit frequency_line_edit_;
}; };
@ -391,6 +401,17 @@ private:
Frequency apply_calibration (Frequency) const; Frequency apply_calibration (Frequency) const;
Frequency remove_calibration (Frequency) const; Frequency remove_calibration (Frequency) const;
void delete_frequencies ();
void load_frequencies ();
void merge_frequencies ();
void save_frequencies ();
void reset_frequencies ();
void insert_frequency ();
FrequencyList::FrequencyItems read_frequencies_file (QString const&);
void delete_stations ();
void insert_station ();
Q_SLOT void on_font_push_button_clicked (); Q_SLOT void on_font_push_button_clicked ();
Q_SLOT void on_decoded_text_font_push_button_clicked (); Q_SLOT void on_decoded_text_font_push_button_clicked ();
Q_SLOT void on_PTT_port_combo_box_activated (int); Q_SLOT void on_PTT_port_combo_box_activated (int);
@ -418,11 +439,6 @@ private:
Q_SLOT void on_azel_path_select_push_button_clicked (bool); Q_SLOT void on_azel_path_select_push_button_clicked (bool);
Q_SLOT void on_calibration_intercept_spin_box_valueChanged (double); Q_SLOT void on_calibration_intercept_spin_box_valueChanged (double);
Q_SLOT void on_calibration_slope_ppm_spin_box_valueChanged (double); Q_SLOT void on_calibration_slope_ppm_spin_box_valueChanged (double);
Q_SLOT void delete_frequencies ();
Q_SLOT void on_reset_frequencies_push_button_clicked (bool);
Q_SLOT void insert_frequency ();
Q_SLOT void delete_stations ();
Q_SLOT void insert_station ();
Q_SLOT void handle_transceiver_update (TransceiverState const&, unsigned sequence_number); Q_SLOT void handle_transceiver_update (TransceiverState const&, unsigned sequence_number);
Q_SLOT void handle_transceiver_failure (QString const& reason); Q_SLOT void handle_transceiver_failure (QString const& reason);
Q_SLOT void on_pbCQmsg_clicked(); Q_SLOT void on_pbCQmsg_clicked();
@ -450,6 +466,7 @@ private:
QDir doc_dir_; QDir doc_dir_;
QDir data_dir_; QDir data_dir_;
QDir temp_dir_; QDir temp_dir_;
QDir writeable_data_dir_;
QDir default_save_directory_; QDir default_save_directory_;
QDir save_directory_; QDir save_directory_;
QDir default_azel_directory_; QDir default_azel_directory_;
@ -471,6 +488,8 @@ private:
QAction * macro_delete_action_; QAction * macro_delete_action_;
Bands bands_; Bands bands_;
IARURegions regions_;
IARURegions::Region region_;
Modes modes_; Modes modes_;
FrequencyList frequencies_; FrequencyList frequencies_;
FrequencyList next_frequencies_; FrequencyList next_frequencies_;
@ -481,6 +500,10 @@ private:
QAction * frequency_delete_action_; QAction * frequency_delete_action_;
QAction * frequency_insert_action_; QAction * frequency_insert_action_;
QAction * load_frequencies_action_;
QAction * save_frequencies_action_;
QAction * merge_frequencies_action_;
QAction * reset_frequencies_action_;
FrequencyDialog * frequency_dialog_; FrequencyDialog * frequency_dialog_;
QAction * station_delete_action_; QAction * station_delete_action_;
@ -577,6 +600,7 @@ Configuration::~Configuration ()
QDir Configuration::doc_dir () const {return m_->doc_dir_;} QDir Configuration::doc_dir () const {return m_->doc_dir_;}
QDir Configuration::data_dir () const {return m_->data_dir_;} QDir Configuration::data_dir () const {return m_->data_dir_;}
QDir Configuration::writeable_data_dir () const {return m_->writeable_data_dir_;}
QDir Configuration::temp_dir () const {return m_->temp_dir_;} QDir Configuration::temp_dir () const {return m_->temp_dir_;}
int Configuration::exec () {return m_->exec ();} int Configuration::exec () {return m_->exec ();}
@ -640,6 +664,7 @@ Bands * Configuration::bands () {return &m_->bands_;}
Bands const * Configuration::bands () const {return &m_->bands_;} Bands const * Configuration::bands () const {return &m_->bands_;}
StationList * Configuration::stations () {return &m_->stations_;} StationList * Configuration::stations () {return &m_->stations_;}
StationList const * Configuration::stations () const {return &m_->stations_;} StationList const * Configuration::stations () const {return &m_->stations_;}
IARURegions::Region Configuration::region () const {return m_->region_;}
FrequencyList * Configuration::frequencies () {return &m_->frequencies_;} FrequencyList * Configuration::frequencies () {return &m_->frequencies_;}
FrequencyList const * Configuration::frequencies () const {return &m_->frequencies_;} FrequencyList const * Configuration::frequencies () const {return &m_->frequencies_;}
QStringListModel * Configuration::macros () {return &m_->macros_;} QStringListModel * Configuration::macros () {return &m_->macros_;}
@ -774,13 +799,14 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
, doc_dir_ {doc_path ()} , doc_dir_ {doc_path ()}
, data_dir_ {data_path ()} , data_dir_ {data_path ()}
, temp_dir_ {temp_directory} , temp_dir_ {temp_directory}
, writeable_data_dir_ {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}
, frequencies_ {&bands_} , frequencies_ {&bands_}
, next_frequencies_ {&bands_} , next_frequencies_ {&bands_}
, stations_ {&bands_} , stations_ {&bands_}
, next_stations_ {&bands_} , next_stations_ {&bands_}
, current_offset_ {0} , current_offset_ {0}
, current_tx_offset_ {0} , current_tx_offset_ {0}
, frequency_dialog_ {new FrequencyDialog {&modes_, this}} , frequency_dialog_ {new FrequencyDialog {&regions_, &modes_, this}}
, station_dialog_ {new StationDialog {&next_stations_, &bands_, this}} , station_dialog_ {new StationDialog {&next_stations_, &bands_, this}}
, last_port_type_ {TransceiverFactory::Capabilities::none} , last_port_type_ {TransceiverFactory::Capabilities::none}
, rig_is_dummy_ {false} , rig_is_dummy_ {false}
@ -799,18 +825,17 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
{ {
// Find a suitable data file location // Find a suitable data file location
QDir writeable_data_dir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}; if (!writeable_data_dir_.mkpath ("."))
if (!writeable_data_dir.mkpath ("."))
{ {
MessageBox::critical_message (this, tr ("Failed to create data directory"), MessageBox::critical_message (this, tr ("Failed to create data directory"),
tr ("path: \"%1\"").arg (writeable_data_dir.absolutePath ())); tr ("path: \"%1\"").arg (writeable_data_dir_.absolutePath ()));
throw std::runtime_error {"Failed to create data directory"}; throw std::runtime_error {"Failed to create data directory"};
} }
// Make sure the default save directory exists // Make sure the default save directory exists
QString save_dir {"save"}; QString save_dir {"save"};
default_save_directory_ = writeable_data_dir; default_save_directory_ = writeable_data_dir_;
default_azel_directory_ = writeable_data_dir; default_azel_directory_ = writeable_data_dir_;
if (!default_save_directory_.mkpath (save_dir) || !default_save_directory_.cd (save_dir)) if (!default_save_directory_.mkpath (save_dir) || !default_save_directory_.cd (save_dir))
{ {
MessageBox::critical_message (this, tr ("Failed to create save directory"), MessageBox::critical_message (this, tr ("Failed to create save directory"),
@ -920,6 +945,8 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
ui_->macros_list_view->insertAction (nullptr, macro_delete_action_); ui_->macros_list_view->insertAction (nullptr, macro_delete_action_);
connect (macro_delete_action_, &QAction::triggered, this, &Configuration::impl::delete_macro); connect (macro_delete_action_, &QAction::triggered, this, &Configuration::impl::delete_macro);
// setup IARU region combo box model
ui_->region_combo_box->setModel (&regions_);
// //
// setup working frequencies table model & view // setup working frequencies table model & view
@ -934,6 +961,7 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
auto frequencies_item_delegate = new QStyledItemDelegate {this}; auto frequencies_item_delegate = new QStyledItemDelegate {this};
frequencies_item_delegate->setItemEditorFactory (item_editor_factory ()); frequencies_item_delegate->setItemEditorFactory (item_editor_factory ());
ui_->frequencies_table_view->setItemDelegate (frequencies_item_delegate); ui_->frequencies_table_view->setItemDelegate (frequencies_item_delegate);
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList::region_column, new ForeignKeyDelegate {&regions_, 0, this});
ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList::mode_column, new ForeignKeyDelegate {&modes_, 0, this}); ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList::mode_column, new ForeignKeyDelegate {&modes_, 0, this});
// actions // actions
@ -945,6 +973,22 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
ui_->frequencies_table_view->insertAction (nullptr, frequency_insert_action_); ui_->frequencies_table_view->insertAction (nullptr, frequency_insert_action_);
connect (frequency_insert_action_, &QAction::triggered, this, &Configuration::impl::insert_frequency); connect (frequency_insert_action_, &QAction::triggered, this, &Configuration::impl::insert_frequency);
load_frequencies_action_ = new QAction {tr ("&Load ..."), ui_->frequencies_table_view};
ui_->frequencies_table_view->insertAction (nullptr, load_frequencies_action_);
connect (load_frequencies_action_, &QAction::triggered, this, &Configuration::impl::load_frequencies);
save_frequencies_action_ = new QAction {tr ("&Save as ..."), ui_->frequencies_table_view};
ui_->frequencies_table_view->insertAction (nullptr, save_frequencies_action_);
connect (save_frequencies_action_, &QAction::triggered, this, &Configuration::impl::save_frequencies);
merge_frequencies_action_ = new QAction {tr ("&Merge ..."), ui_->frequencies_table_view};
ui_->frequencies_table_view->insertAction (nullptr, merge_frequencies_action_);
connect (merge_frequencies_action_, &QAction::triggered, this, &Configuration::impl::merge_frequencies);
reset_frequencies_action_ = new QAction {tr ("&Reset"), ui_->frequencies_table_view};
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 // setup stations table model & view
@ -1099,6 +1143,8 @@ void Configuration::impl::initialize_models ()
ui_->PTT_port_combo_box->setCurrentText (rig_params_.ptt_port); ui_->PTT_port_combo_box->setCurrentText (rig_params_.ptt_port);
} }
ui_->region_combo_box->setCurrentText (regions_.name (region_));
next_macros_.setStringList (macros_.stringList ()); next_macros_.setStringList (macros_.stringList ());
next_frequencies_.frequency_list (frequencies_.frequency_list ()); next_frequencies_.frequency_list (frequencies_.frequency_list ());
next_stations_.station_list (stations_.station_list ()); next_stations_.station_list (stations_.station_list ());
@ -1224,9 +1270,11 @@ void Configuration::impl::read_settings ()
macros_.setStringList (settings_->value ("Macros", QStringList {"TNX 73 GL"}).toStringList ()); macros_.setStringList (settings_->value ("Macros", QStringList {"TNX 73 GL"}).toStringList ());
if (settings_->contains ("FrequenciesForModes")) region_ = settings_->value ("Region", IARURegions::ALL).value<IARURegions::Region> ();
if (settings_->contains ("FrequenciesForRegionModes"))
{ {
auto const& v = settings_->value ("FrequenciesForModes"); auto const& v = settings_->value ("FrequenciesForRegionModes");
if (v.isValid ()) if (v.isValid ())
{ {
frequencies_.frequency_list (v.value<FrequencyList::FrequencyItems> ()); frequencies_.frequency_list (v.value<FrequencyList::FrequencyItems> ());
@ -1341,7 +1389,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("After73", id_after_73_); settings_->setValue ("After73", id_after_73_);
settings_->setValue ("TxQSYAllowed", tx_QSY_allowed_); settings_->setValue ("TxQSYAllowed", tx_QSY_allowed_);
settings_->setValue ("Macros", macros_.stringList ()); settings_->setValue ("Macros", macros_.stringList ());
settings_->setValue ("FrequenciesForModes", QVariant::fromValue (frequencies_.frequency_list ())); settings_->setValue ("FrequenciesForRegionModes", QVariant::fromValue (frequencies_.frequency_list ()));
settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ())); settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ()));
settings_->setValue ("toRTTY", log_as_RTTY_); settings_->setValue ("toRTTY", log_as_RTTY_);
settings_->setValue ("dBtoComments", report_in_comments_); settings_->setValue ("dBtoComments", report_in_comments_);
@ -1386,6 +1434,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("CalibrationSlopePPM", frequency_calibration_slope_ppm_); settings_->setValue ("CalibrationSlopePPM", frequency_calibration_slope_ppm_);
settings_->setValue ("pwrBandTxMemory", pwrBandTxMemory_); settings_->setValue ("pwrBandTxMemory", pwrBandTxMemory_);
settings_->setValue ("pwrBandTuneMemory", pwrBandTuneMemory_); settings_->setValue ("pwrBandTuneMemory", pwrBandTuneMemory_);
settings_->setValue ("Region", region_);
} }
void Configuration::impl::set_rig_invariants () void Configuration::impl::set_rig_invariants ()
@ -1799,6 +1848,8 @@ void Configuration::impl::accept ()
macros_.setStringList (next_macros_.stringList ()); macros_.setStringList (next_macros_.stringList ());
} }
region_ = regions_.value (ui_->region_combo_box->currentText ());
if (frequencies_.frequency_list () != next_frequencies_.frequency_list ()) if (frequencies_.frequency_list () != next_frequencies_.frequency_list ())
{ {
frequencies_.frequency_list (next_frequencies_.frequency_list ()); frequencies_.frequency_list (next_frequencies_.frequency_list ());
@ -2072,7 +2123,98 @@ void Configuration::impl::delete_frequencies ()
ui_->frequencies_table_view->resizeColumnToContents (FrequencyList::mode_column); ui_->frequencies_table_view->resizeColumnToContents (FrequencyList::mode_column);
} }
void Configuration::impl::on_reset_frequencies_push_button_clicked (bool /* checked */) 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 (*.*)"));
if (!file_name.isNull ())
{
auto const list = read_frequencies_file (file_name);
if (list.size ()
&& (!next_frequencies_.frequency_list ().size ()
|| MessageBox::Yes == MessageBox::query_message (this
, tr ("Replace Working Frequencies")
, tr ("Are you sure you want to discard your current "
"working frequencies and replace them with the "
"loaded ones?"))))
{
next_frequencies_.frequency_list (list); // update the model
}
}
}
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 (*.*)"));
if (!file_name.isNull ())
{
next_frequencies_.frequency_list_merge (read_frequencies_file (file_name)); // update the model
}
}
FrequencyList::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::FrequencyItems list;
quint32 magic;
ids >> magic;
if (qrg_magic != magic)
{
MessageBox::warning_message (this, tr ("Not a valid frequencies file"), tr ("Incorrect file magic"));
return list;
}
quint32 version;
ids >> version;
// handle version checks and QDataStream version here if
// necessary
if (version > qrg_version)
{
MessageBox::warning_message (this, tr ("Not a valid frequencies file"), tr ("Version is too new"));
return list;
}
// de-serialize the data using version if necessary to
// handle old schemata
ids >> list;
if (ids.status () != QDataStream::Ok || !ids.atEnd ())
{
MessageBox::warning_message (this, tr ("Not a valid frequencies file"), tr ("Contents corrupt"));
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 (*.*)"));
if (!file_name.isNull ())
{
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
, tr ("Only Save Selected Working Frequencies")
, tr ("Are you sure you want to save only the "
"working frequencies that are currently selected? "
"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 ());
}
else
{
ods << qrg_magic << qrg_version << next_frequencies_.frequency_list ();
}
}
}
void Configuration::impl::reset_frequencies ()
{ {
if (MessageBox::Yes == MessageBox::query_message (this, tr ("Reset Working Frequencies") if (MessageBox::Yes == MessageBox::query_message (this, tr ("Reset Working Frequencies")
, tr ("Are you sure you want to discard your current " , tr ("Are you sure you want to discard your current "

View File

@ -5,6 +5,7 @@
#include <QFont> #include <QFont>
#include "Radio.hpp" #include "Radio.hpp"
#include "IARURegions.hpp"
#include "AudioDevice.hpp" #include "AudioDevice.hpp"
#include "Transceiver.hpp" #include "Transceiver.hpp"
@ -78,6 +79,7 @@ public:
QDir temp_dir () const; QDir temp_dir () const;
QDir doc_dir () const; QDir doc_dir () const;
QDir data_dir () const; QDir data_dir () const;
QDir writeable_data_dir () const;
QAudioDeviceInfo const& audio_input_device () const; QAudioDeviceInfo const& audio_input_device () const;
AudioDevice::Channel audio_input_channel () const; AudioDevice::Channel audio_input_channel () const;
@ -137,6 +139,7 @@ public:
bool udpWindowRestore () const; bool udpWindowRestore () const;
Bands * bands (); Bands * bands ();
Bands const * bands () const; Bands const * bands () const;
IARURegions::Region region () const;
FrequencyList * frequencies (); FrequencyList * frequencies ();
FrequencyList const * frequencies () const; FrequencyList const * frequencies () const;
StationList * stations (); StationList * stations ();

View File

@ -27,94 +27,114 @@
<property name="title"> <property name="title">
<string>Station Details</string> <string>Station Details</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_14"> <layout class="QVBoxLayout" name="verticalLayout_12">
<item row="0" column="3"> <item>
<widget class="QLabel" name="grid_label"> <layout class="QHBoxLayout" name="horizontalLayout_14">
<property name="text">
<string>M&amp;y Grid:</string>
</property>
<property name="buddy">
<cstring>grid_line_edit</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="callsign_label">
<property name="text">
<string>My C&amp;all:</string>
</property>
<property name="buddy">
<cstring>callsign_line_edit</cstring>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLineEdit" name="grid_line_edit">
<property name="toolTip">
<string>Maidenhead locator (only the first four characters are required).</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="callsign_line_edit">
<property name="toolTip">
<string>Station callsign.</string>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_4">
<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 row="1" column="4">
<widget class="QComboBox" name="type_2_msg_gen_combo_box">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Type 2 compound callsigns are those with prefixes or suffixes not included in the allowed shortlist (See Help-&amp;gt;Add-on prefixes and suffixes).&lt;/p&gt;&lt;p&gt;This option determines which generated messages should contain your full type 2 compound call sign rather than your base callsign. It only applies if you have a type 2 compound callsign.&lt;/p&gt;&lt;p&gt;This option controls the way the messages that are used to answer CQ calls are generated. Generated messages 6 (CQ) and 5 (73) will always contain your full callsign. The JT65 and JT9 protocols allow for some standard messages with your full call at the expense of another piece of information such as the DX call or your locator.&lt;/p&gt;&lt;p&gt;Choosing message 1 omits the DX callsign which may be an issue when replying to CQ calls. Choosing message 3 also omits the DX callsign and many versions of this and other software will not extract the report. Choosing neither means that your full callsign only goes in your message 5 (73) so your QSO partner my log the wrong callsign.&lt;/p&gt;&lt;p&gt;None of these options are perfect, message 3 is best but be aware your QSO partner may not log the report you send them.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<item> <item>
<property name="text"> <layout class="QFormLayout" name="formLayout_3">
<string>Full call in Tx1</string> <item row="0" column="0">
</property> <widget class="QLabel" name="callsign_label">
<property name="text">
<string>My C&amp;all:</string>
</property>
<property name="buddy">
<cstring>callsign_line_edit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="callsign_line_edit">
<property name="toolTip">
<string>Station callsign.</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<property name="text"> <layout class="QFormLayout" name="formLayout_12">
<string>Full call in Tx3</string> <item row="0" column="0">
</property> <widget class="QLabel" name="grid_label">
<property name="text">
<string>M&amp;y Grid:</string>
</property>
<property name="buddy">
<cstring>grid_line_edit</cstring>
</property>
</widget>
</item>
<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>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<property name="text"> <layout class="QFormLayout" name="formLayout_2">
<string>Full call in Tx5 only</string> <item row="0" column="1">
</property> <widget class="QComboBox" name="region_combo_box"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>IARU Region:</string>
</property>
<property name="buddy">
<cstring>region_combo_box</cstring>
</property>
</widget>
</item>
</layout>
</item> </item>
</widget> </layout>
</item> </item>
<item row="1" column="0" colspan="4"> <item>
<widget class="QLabel" name="label_5"> <layout class="QFormLayout" name="formLayout_13">
<property name="text"> <item row="0" column="0">
<string>Message generation for type 2 compound callsign holders:</string> <widget class="QLabel" name="label_5">
</property> <property name="text">
<property name="alignment"> <string>Message generation for type 2 compound callsign holders:</string>
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property>
</property> <property name="alignment">
<property name="buddy"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<cstring>type_2_msg_gen_combo_box</cstring> </property>
</property> <property name="buddy">
</widget> <cstring>type_2_msg_gen_combo_box</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="type_2_msg_gen_combo_box">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Type 2 compound callsigns are those with prefixes or suffixes not included in the allowed shortlist (See Help-&amp;gt;Add-on prefixes and suffixes).&lt;/p&gt;&lt;p&gt;This option determines which generated messages should contain your full type 2 compound call sign rather than your base callsign. It only applies if you have a type 2 compound callsign.&lt;/p&gt;&lt;p&gt;This option controls the way the messages that are used to answer CQ calls are generated. Generated messages 6 (CQ) and 5 (73) will always contain your full callsign. The JT65 and JT9 protocols allow for some standard messages with your full call at the expense of another piece of information such as the DX call or your locator.&lt;/p&gt;&lt;p&gt;Choosing message 1 omits the DX callsign which may be an issue when replying to CQ calls. Choosing message 3 also omits the DX callsign and many versions of this and other software will not extract the report. Choosing neither means that your full callsign only goes in your message 5 (73) so your QSO partner my log the wrong callsign.&lt;/p&gt;&lt;p&gt;None of these options are perfect, message 3 is best but be aware your QSO partner may not log the report you send them.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<item>
<property name="text">
<string>Full call in Tx1</string>
</property>
</item>
<item>
<property name="text">
<string>Full call in Tx3</string>
</property>
</item>
<item>
<property name="text">
<string>Full call in Tx5 only</string>
</property>
</item>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -424,6 +444,19 @@ text message.</string>
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<spacer name="verticalSpacer_11">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="radio_tab"> <widget class="QWidget" name="radio_tab">
@ -1776,6 +1809,106 @@ for assessing propagation and system performance.</string>
<string>Default frequencies and band specific station details setup</string> <string>Default frequencies and band specific station details setup</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_10"> <layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="toolTip">
<string>See WSPR documentattion Appendix C for details of how to determine these factors for your radio.</string>
</property>
<property name="title">
<string>Frequency Calibration</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<layout class="QFormLayout" name="formLayout_7">
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Slope:</string>
</property>
<property name="buddy">
<cstring>calibration_slope_ppm_spin_box</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="calibration_slope_ppm_spin_box">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> ppm</string>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-999.999900000000025</double>
</property>
<property name="maximum">
<double>999.999900000000025</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout_14">
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Intercept:</string>
</property>
<property name="buddy">
<cstring>calibration_intercept_spin_box</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="calibration_intercept_spin_box">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-99999.990000000005239</double>
</property>
<property name="maximum">
<double>99999.990000000005239</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
@ -1794,7 +1927,7 @@ for assessing propagation and system performance.</string>
<enum>Qt::ActionsContextMenu</enum> <enum>Qt::ActionsContextMenu</enum>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Right click to add or delete frequencies.</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Right click to maintain the working frequencies list.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="dragDropMode"> <property name="dragDropMode">
<enum>QAbstractItemView::DragOnly</enum> <enum>QAbstractItemView::DragOnly</enum>
@ -1816,129 +1949,6 @@ for assessing propagation and system performance.</string>
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="reset_frequencies_push_button">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="toolTip">
<string>See WSPR documentattion Appendix C for details of how to determine these factors for your radio.</string>
</property>
<property name="title">
<string>Frequency Calibration</string>
</property>
<layout class="QFormLayout" name="formLayout_7">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Intercept:</string>
</property>
<property name="buddy">
<cstring>calibration_intercept_spin_box</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="calibration_intercept_spin_box">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-99999.990000000005239</double>
</property>
<property name="maximum">
<double>99999.990000000005239</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Slope:</string>
</property>
<property name="buddy">
<cstring>calibration_slope_ppm_spin_box</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="calibration_slope_ppm_spin_box">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> ppm</string>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-999.999900000000025</double>
</property>
<property name="maximum">
<double>999.999900000000025</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</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>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -2460,6 +2470,7 @@ soundcard changes</string>
<tabstop>configuration_tabs</tabstop> <tabstop>configuration_tabs</tabstop>
<tabstop>callsign_line_edit</tabstop> <tabstop>callsign_line_edit</tabstop>
<tabstop>grid_line_edit</tabstop> <tabstop>grid_line_edit</tabstop>
<tabstop>region_combo_box</tabstop>
<tabstop>type_2_msg_gen_combo_box</tabstop> <tabstop>type_2_msg_gen_combo_box</tabstop>
<tabstop>insert_blank_check_box</tabstop> <tabstop>insert_blank_check_box</tabstop>
<tabstop>miles_check_box</tabstop> <tabstop>miles_check_box</tabstop>
@ -2528,11 +2539,10 @@ soundcard changes</string>
<tabstop>accept_udp_requests_check_box</tabstop> <tabstop>accept_udp_requests_check_box</tabstop>
<tabstop>udpWindowToFront</tabstop> <tabstop>udpWindowToFront</tabstop>
<tabstop>udpWindowRestore</tabstop> <tabstop>udpWindowRestore</tabstop>
<tabstop>calibration_slope_ppm_spin_box</tabstop>
<tabstop>calibration_intercept_spin_box</tabstop>
<tabstop>frequencies_table_view</tabstop> <tabstop>frequencies_table_view</tabstop>
<tabstop>stations_table_view</tabstop> <tabstop>stations_table_view</tabstop>
<tabstop>reset_frequencies_push_button</tabstop>
<tabstop>calibration_intercept_spin_box</tabstop>
<tabstop>calibration_slope_ppm_spin_box</tabstop>
<tabstop>pbCQmsg</tabstop> <tabstop>pbCQmsg</tabstop>
<tabstop>pbMyCall</tabstop> <tabstop>pbMyCall</tabstop>
<tabstop>pbTxMsg</tabstop> <tabstop>pbTxMsg</tabstop>
@ -2557,8 +2567,8 @@ soundcard changes</string>
<slot>accept()</slot> <slot>accept()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>272</x> <x>281</x>
<y>606</y> <y>488</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>157</x> <x>157</x>
@ -2573,8 +2583,8 @@ soundcard changes</string>
<slot>reject()</slot> <slot>reject()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>340</x> <x>349</x>
<y>606</y> <y>488</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>286</x> <x>286</x>
@ -2616,12 +2626,12 @@ soundcard changes</string>
</connection> </connection>
</connections> </connections>
<buttongroups> <buttongroups>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="split_mode_button_group"/> <buttongroup name="split_mode_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="TX_mode_button_group"/> <buttongroup name="TX_mode_button_group"/>
<buttongroup name="PTT_method_button_group"/> <buttongroup name="PTT_method_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
</buttongroups> </buttongroups>
</ui> </ui>

View File

@ -14,7 +14,6 @@
#include <QMimeData> #include <QMimeData>
#include <QDataStream> #include <QDataStream>
#include <QByteArray> #include <QByteArray>
#include <QDebug>
#include <QDebugStateSaver> #include <QDebugStateSaver>
#include "Radio.hpp" #include "Radio.hpp"
@ -27,105 +26,149 @@ namespace
{ {
FrequencyList::FrequencyItems const default_frequency_list = FrequencyList::FrequencyItems const default_frequency_list =
{ {
{136000, Modes::WSPR}, {198000, Modes::FreqCal, IARURegions::R1}, // BBC Radio 4 Droitwich
{136130, Modes::JT65}, {4996000, Modes::FreqCal, IARURegions::R1}, // RWM time signal
{474200, Modes::JT65}, {9996000, Modes::FreqCal, IARURegions::R1}, // RWM time signal
{474200, Modes::JT9}, {14996000, Modes::FreqCal, IARURegions::R1}, // RWM time signal
{474200, Modes::WSPR},
{660000, Modes::FreqCal}, {660000, Modes::FreqCal, IARURegions::R2},
{880000, Modes::FreqCal}, {880000, Modes::FreqCal, IARURegions::R2},
{1210000, Modes::FreqCal}, {1210000, Modes::FreqCal, IARURegions::R2},
{1836600, Modes::WSPR},
{1838000, Modes::JT65}, {2500000, Modes::FreqCal, IARURegions::ALL},
{1840000, Modes::JT9}, {3330000, Modes::FreqCal, IARURegions::ALL},
{1841000, Modes::FT8}, {5000000, Modes::FreqCal, IARURegions::ALL},
{2500000, Modes::FreqCal}, {7850000, Modes::FreqCal, IARURegions::ALL},
{3330000, Modes::FreqCal}, {10000000, Modes::FreqCal, IARURegions::ALL},
{3576000, Modes::JT65}, {14670000, Modes::FreqCal, IARURegions::ALL},
{3578000, Modes::JT9}, {15000000, Modes::FreqCal, IARURegions::ALL},
{3579000, Modes::FT8}, {20000000, Modes::FreqCal, IARURegions::ALL},
{3592600, Modes::WSPR},
{5357000, Modes::JT65}, {136000, Modes::WSPR, IARURegions::ALL},
{5000000, Modes::FreqCal}, {136130, Modes::JT65, IARURegions::ALL},
{7038600, Modes::WSPR}, {136130, Modes::JT9, IARURegions::ALL},
{7076000, Modes::JT65},
{7078000, Modes::JT9}, {474200, Modes::JT65, IARURegions::ALL},
{7079000, Modes::FT8}, {474200, Modes::JT9, IARURegions::ALL},
{7850000, Modes::FreqCal}, {474200, Modes::WSPR, IARURegions::ALL},
{10000000, Modes::FreqCal},
{10138000, Modes::JT65}, {1836600, Modes::WSPR, IARURegions::ALL},
{10138700, Modes::WSPR}, {1838000, Modes::JT65, IARURegions::ALL}, // squeezed allocations
{10140000, Modes::JT9}, {1839000, Modes::JT9, IARURegions::ALL},
{10141000, Modes::FT8}, {1840000, Modes::FT8, IARURegions::ALL},
{14095600, Modes::WSPR},
{14076000, Modes::JT65}, {3570000, Modes::JT65, IARURegions::ALL}, // JA compatible
{14078000, Modes::JT9}, {3572000, Modes::JT9, IARURegions::ALL},
{14079000, Modes::FT8}, {3573000, Modes::FT8, IARURegions::ALL}, // above as below JT65
{14670000, Modes::FreqCal}, // is out of DM allocation
{15000000, Modes::FreqCal}, {3572600, Modes::WSPR, IARURegions::ALL}, // needs guard marker
{18102000, Modes::JT65}, // and lock out
{18104000, Modes::JT9},
{18105000, Modes::FT8}, {7038600, Modes::WSPR, IARURegions::ALL},
{18104600, Modes::WSPR}, {7074000, Modes::FT8, IARURegions::ALL},
{20000000, Modes::FreqCal}, {7076000, Modes::JT65, IARURegions::ALL},
{21076000, Modes::JT65}, {7078000, Modes::JT9, IARURegions::ALL},
{21078000, Modes::JT9},
{21079000, Modes::FT8}, {10136000, Modes::FT8, IARURegions::ALL},
{21094600, Modes::WSPR}, {10138000, Modes::JT65, IARURegions::ALL},
{24917000, Modes::JT65}, {10138700, Modes::WSPR, IARURegions::ALL},
{24919000, Modes::JT9}, {10140000, Modes::JT9, IARURegions::ALL},
{24920000, Modes::FT8},
{24924600, Modes::WSPR}, {14095600, Modes::WSPR, IARURegions::ALL},
{28076000, Modes::JT65}, {14074000, Modes::FT8, IARURegions::ALL},
{28078000, Modes::JT9}, {14076000, Modes::JT65, IARURegions::ALL},
{28079000, Modes::FT8}, {14078000, Modes::JT9, IARURegions::ALL},
{28124600, Modes::WSPR},
{50000000, Modes::Echo}, {18100000, Modes::FT8, IARURegions::ALL},
{50276000, Modes::JT65}, {18102000, Modes::JT65, IARURegions::ALL},
{50280000, Modes::MSK144}, {18104000, Modes::JT9, IARURegions::ALL},
{50293000, Modes::WSPR}, {18104600, Modes::WSPR, IARURegions::ALL},
{50310000, Modes::JT65},
{50313000, Modes::FT8}, {21074000, Modes::FT8, IARURegions::ALL},
{70091000, Modes::JT65}, {21076000, Modes::JT65, IARURegions::ALL},
{70091000, Modes::WSPR}, {21078000, Modes::JT9, IARURegions::ALL},
{70094000, Modes::FT8}, {21094600, Modes::WSPR, IARURegions::ALL},
{144000000, Modes::Echo},
{144120000, Modes::JT65}, {24915000, Modes::FT8, IARURegions::ALL},
{144120000, Modes::Echo}, {24917000, Modes::JT65, IARURegions::ALL},
{144140000, Modes::MSK144}, {24919000, Modes::JT9, IARURegions::ALL},
{144489000, Modes::WSPR}, {24924600, Modes::WSPR, IARURegions::ALL},
{222065000, Modes::JT65},
{222065000, Modes::Echo}, {28074000, Modes::FT8, IARURegions::ALL},
{432065000, Modes::Echo}, {28076000, Modes::JT65, IARURegions::ALL},
{432065000, Modes::JT65}, {28078000, Modes::JT9, IARURegions::ALL},
{432300000, Modes::WSPR}, {28124600, Modes::WSPR, IARURegions::ALL},
{902065000, Modes::JT65},
{1296065000, Modes::Echo}, {50000000, Modes::Echo, IARURegions::ALL},
{1296065000, Modes::JT65}, {50276000, Modes::JT65, IARURegions::R2},
{1296500000, Modes::WSPR}, {50276000, Modes::JT65, IARURegions::R3},
{2301000000, Modes::Echo}, {50260000, Modes::MSK144, IARURegions::R2},
{2301065000, Modes::JT4}, {50260000, Modes::MSK144, IARURegions::R3},
{2301065000, Modes::JT65}, {50293000, Modes::WSPR, IARURegions::R2},
{2304065000, Modes::Echo}, {50293000, Modes::WSPR, IARURegions::R3},
{2304065000, Modes::JT4}, {50310000, Modes::JT65, IARURegions::ALL},
{2304065000, Modes::JT65}, {50312000, Modes::JT9, IARURegions::ALL},
{2320065000, Modes::Echo}, {50313000, Modes::FT8, IARURegions::ALL},
{2320065000, Modes::JT4}, {50360000, Modes::MSK144, IARURegions::R1},
{2320065000, Modes::JT65},
{3400065000, Modes::Echo}, {70100000, Modes::FT8, IARURegions::R1},
{3400065000, Modes::JT4}, {70102000, Modes::JT65, IARURegions::R1},
{3400065000, Modes::JT65}, {70104000, Modes::JT9, IARURegions::R1},
{3456065000, Modes::JT4}, {70091000, Modes::WSPR, IARURegions::R1},
{3456065000, Modes::JT65}, {70230000, Modes::MSK144, IARURegions::R1},
{5760065000, Modes::Echo},
{5760065000, Modes::JT4}, {144000000, Modes::Echo, IARURegions::ALL},
{5760065000, Modes::JT65}, {144120000, Modes::JT65, IARURegions::ALL},
{10368100000, Modes::Echo}, {144120000, Modes::Echo, IARURegions::ALL},
{10368100000, Modes::JT4}, {144360000, Modes::MSK144, IARURegions::R1},
{10368100000, Modes::JT65}, {144150000, Modes::MSK144, IARURegions::R2},
{24048100000, Modes::Echo}, {144489000, Modes::WSPR, IARURegions::ALL},
{24048100000, Modes::JT4},
{24048100000, Modes::JT65}, {222065000, Modes::Echo, IARURegions::R2},
{222065000, Modes::JT65, IARURegions::R2},
{432065000, Modes::Echo, IARURegions::ALL},
{432065000, Modes::JT65, IARURegions::ALL},
{432300000, Modes::WSPR, IARURegions::ALL},
{432360000, Modes::MSK144, IARURegions::ALL},
{902065000, Modes::JT65, IARURegions::ALL},
{1296065000, Modes::Echo, IARURegions::ALL},
{1296065000, Modes::JT65, IARURegions::ALL},
{1296500000, Modes::WSPR, IARURegions::ALL},
{2301000000, Modes::Echo, IARURegions::ALL},
{2301065000, Modes::JT4, IARURegions::ALL},
{2301065000, Modes::JT65, IARURegions::ALL},
{2304065000, Modes::Echo, IARURegions::ALL},
{2304065000, Modes::JT4, IARURegions::ALL},
{2304065000, Modes::JT65, IARURegions::ALL},
{2320065000, Modes::Echo, IARURegions::ALL},
{2320065000, Modes::JT4, IARURegions::ALL},
{2320065000, Modes::JT65, IARURegions::ALL},
{3400065000, Modes::Echo, IARURegions::ALL},
{3400065000, Modes::JT4, IARURegions::ALL},
{3400065000, Modes::JT65, IARURegions::ALL},
{3456065000, Modes::Echo, IARURegions::ALL},
{3456065000, Modes::JT4, IARURegions::ALL},
{3456065000, Modes::JT65, IARURegions::ALL},
{5760065000, Modes::Echo, IARURegions::ALL},
{5760065000, Modes::JT4, IARURegions::ALL},
{5760065000, Modes::JT65, IARURegions::ALL},
{10368100000, Modes::Echo, IARURegions::ALL},
{10368100000, Modes::JT4, IARURegions::ALL},
{10368100000, Modes::JT65, IARURegions::ALL},
{24048100000, Modes::Echo, IARURegions::ALL},
{24048100000, Modes::JT4, IARURegions::ALL},
{24048100000, Modes::JT65, IARURegions::ALL},
}; };
} }
@ -135,6 +178,7 @@ QDebug operator << (QDebug debug, FrequencyList::Item const& item)
QDebugStateSaver saver {debug}; QDebugStateSaver saver {debug};
debug.nospace () << "FrequencyItem(" debug.nospace () << "FrequencyItem("
<< item.frequency_ << ", " << item.frequency_ << ", "
<< item.region_ << ", "
<< item.mode_ << ')'; << item.mode_ << ')';
return debug; return debug;
} }
@ -143,13 +187,15 @@ QDebug operator << (QDebug debug, FrequencyList::Item const& item)
QDataStream& operator << (QDataStream& os, FrequencyList::Item const& item) QDataStream& operator << (QDataStream& os, FrequencyList::Item const& item)
{ {
return os << item.frequency_ return os << item.frequency_
<< item.mode_; << item.mode_
<< item.region_;
} }
QDataStream& operator >> (QDataStream& is, FrequencyList::Item& item) QDataStream& operator >> (QDataStream& is, FrequencyList::Item& item)
{ {
return is >> item.frequency_ return is >> item.frequency_
>> item.mode_; >> item.mode_
>> item.region_;
} }
class FrequencyList::impl final class FrequencyList::impl final
@ -159,12 +205,14 @@ public:
impl (Bands const * bands, QObject * parent) impl (Bands const * bands, QObject * parent)
: QAbstractTableModel {parent} : QAbstractTableModel {parent}
, bands_ {bands} , bands_ {bands}
, mode_filter_ {Modes::NULL_MODE} , region_filter_ {IARURegions::ALL}
, mode_filter_ {Modes::ALL}
{ {
} }
FrequencyItems frequency_list (FrequencyItems); FrequencyItems frequency_list (FrequencyItems);
QModelIndex add (Item); QModelIndex add (Item);
void add (FrequencyItems);
// Implement the QAbstractTableModel interface // Implement the QAbstractTableModel interface
int rowCount (QModelIndex const& parent = QModelIndex {}) const override; int rowCount (QModelIndex const& parent = QModelIndex {}) const override;
@ -178,11 +226,12 @@ public:
QStringList mimeTypes () const override; QStringList mimeTypes () const override;
QMimeData * mimeData (QModelIndexList const&) const override; QMimeData * mimeData (QModelIndexList const&) const override;
static int constexpr num_cols {3}; static int constexpr num_cols {SENTINAL};
static auto constexpr mime_type = "application/wsjt.Frequencies"; static auto constexpr mime_type = "application/wsjt.Frequencies";
Bands const * bands_; Bands const * bands_;
FrequencyItems frequency_list_; FrequencyItems frequency_list_;
Region region_filter_;
Mode mode_filter_; Mode mode_filter_;
}; };
@ -208,6 +257,21 @@ auto FrequencyList::frequency_list () const -> FrequencyItems const&
return m_->frequency_list_; return m_->frequency_list_;
} }
auto FrequencyList::frequency_list (QModelIndexList const& model_index_list) const -> FrequencyItems
{
FrequencyItems list;
Q_FOREACH (auto const& index, model_index_list)
{
list << m_->frequency_list_[mapToSource (index).row ()];
}
return list;
}
void FrequencyList::frequency_list_merge (FrequencyItems const& items)
{
m_->add (items);
}
int FrequencyList::best_working_frequency (Frequency f) const int FrequencyList::best_working_frequency (Frequency f) const
{ {
int result {-1}; int result {-1};
@ -309,8 +373,9 @@ bool FrequencyList::removeDisjointRows (QModelIndexList rows)
return result; return result;
} }
void FrequencyList::filter (Mode mode) void FrequencyList::filter (Region region, Mode mode)
{ {
m_->region_filter_ = region;
m_->mode_filter_ = mode; m_->mode_filter_ = mode;
invalidateFilter (); invalidateFilter ();
} }
@ -318,11 +383,15 @@ void FrequencyList::filter (Mode mode)
bool FrequencyList::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const bool FrequencyList::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const
{ {
bool result {true}; bool result {true};
if (m_->mode_filter_ != Modes::NULL_MODE) auto const& item = m_->frequency_list_[source_row];
if (m_->region_filter_ != IARURegions::ALL)
{ {
auto const& item = m_->frequency_list_[source_row]; result = IARURegions::ALL == item.region_ || m_->region_filter_ == item.region_;
// we pass NULL_MODE mode rows unless filtering for FreqCal mode }
result = (Modes::NULL_MODE == item.mode_ && m_->mode_filter_ != Modes::FreqCal) if (result && m_->mode_filter_ != Modes::ALL)
{
// we pass ALL mode rows unless filtering for FreqCal mode
result = (Modes::ALL == item.mode_ && m_->mode_filter_ != Modes::FreqCal)
|| m_->mode_filter_ == item.mode_; || m_->mode_filter_ == item.mode_;
} }
return result; return result;
@ -353,6 +422,31 @@ QModelIndex FrequencyList::impl::add (Item f)
return QModelIndex {}; return QModelIndex {};
} }
void FrequencyList::impl::add (FrequencyItems items)
{
// Any Frequency that isn't in the list may be added
for (auto p = items.begin (); p != items.end ();)
{
if (frequency_list_.contains (*p))
{
p = items.erase (p);
}
else
{
++p;
}
}
if (items.size ())
{
auto row = frequency_list_.size ();
beginInsertRows (QModelIndex {}, row, row + items.size () - 1);
frequency_list_.append (items);
endInsertRows ();
}
}
int FrequencyList::impl::rowCount (QModelIndex const& parent) const int FrequencyList::impl::rowCount (QModelIndex const& parent) const
{ {
return parent.isValid () ? 0 : frequency_list_.size (); return parent.isValid () ? 0 : frequency_list_.size ();
@ -394,6 +488,27 @@ QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const
auto const& frequency_item = frequency_list_.at (row); auto const& frequency_item = frequency_list_.at (row);
switch (column) switch (column)
{ {
case region_column:
switch (role)
{
case SortRole:
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::AccessibleTextRole:
item = IARURegions::name (frequency_item.region_);
break;
case Qt::ToolTipRole:
case Qt::AccessibleDescriptionRole:
item = tr ("IARU Region");
break;
case Qt::TextAlignmentRole:
item = Qt::AlignHCenter + Qt::AlignVCenter;
break;
}
break;
case mode_column: case mode_column:
switch (role) switch (role)
{ {
@ -489,6 +604,19 @@ bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant cons
auto& item = frequency_list_[row]; auto& item = frequency_list_[row];
switch (model_index.column ()) switch (model_index.column ())
{ {
case region_column:
if (value.canConvert<Region> ())
{
auto region = IARURegions::value (value.toString ());
if (region != item.region_)
{
item.region_ = region;
Q_EMIT dataChanged (model_index, model_index, roles);
changed = true;
}
}
break;
case mode_column: case mode_column:
if (value.canConvert<Mode> ()) if (value.canConvert<Mode> ())
{ {
@ -530,6 +658,7 @@ QVariant FrequencyList::impl::headerData (int section, Qt::Orientation orientati
{ {
switch (section) switch (section)
{ {
case region_column: header = tr ("IARU Region"); break;
case mode_column: header = tr ("Mode"); break; case mode_column: header = tr ("Mode"); break;
case frequency_column: header = tr ("Frequency"); break; case frequency_column: header = tr ("Frequency"); break;
case frequency_mhz_column: header = tr ("Frequency (MHz)"); break; case frequency_mhz_column: header = tr ("Frequency (MHz)"); break;
@ -564,7 +693,7 @@ bool FrequencyList::impl::insertRows (int row, int count, QModelIndex const& par
beginInsertRows (parent, row, row + count - 1); beginInsertRows (parent, row, row + count - 1);
for (auto r = 0; r < count; ++r) for (auto r = 0; r < count; ++r)
{ {
frequency_list_.insert (row, Item {0, Mode::NULL_MODE}); frequency_list_.insert (row, Item {0, Mode::ALL, IARURegions::ALL});
} }
endInsertRows (); endInsertRows ();
return true; return true;
@ -656,12 +785,13 @@ auto FrequencyList::filtered_bands () const -> BandSet
return result; return result;
} }
auto FrequencyList::all_bands (Mode mode) const -> BandSet auto FrequencyList::all_bands (Region region, Mode mode) const -> BandSet
{ {
BandSet result; BandSet result;
for (auto const& item : m_->frequency_list_) for (auto const& item : m_->frequency_list_)
{ {
if (mode == Modes::NULL_MODE || item.mode_ == mode) if (region == IARURegions::ALL || item.region_ == region
|| mode == Modes::ALL || item.mode_ == mode)
{ {
result << m_->bands_->find (item.frequency_); result << m_->bands_->find (item.frequency_);
} }

View File

@ -7,6 +7,7 @@
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include "Radio.hpp" #include "Radio.hpp"
#include "IARURegions.hpp"
#include "Modes.hpp" #include "Modes.hpp"
class Bands; class Bands;
@ -15,19 +16,20 @@ class Bands;
// Class FrequencyList // Class FrequencyList
// //
// Encapsulates a collection of frequencies with associated modes. // Encapsulates a collection of frequencies with associated modes.
// The implementation is a table containing the list of Frequency and // The implementation is a table containing the list of IARU region,
// mode tuples which are editable. A third column is modeled in the // Frequency and mode tuples which are editable. A third column is
// model which is an immutable double representation of the // modeled in the model which is an immutable double representation
// corresponding Frequency item scaled to mega-Hertz. // of the corresponding Frequency item scaled to mega-Hertz.
// //
// The list is ordered. A filter on mode is available and is set by // The list is ordered. A filter on IARU region and mode is
// the filter(Mode) method. The Mode value Modes::NULL_MODE passes // available and is set by the filter(Region, Mode) method. The
// all rows in the filter. // Region value IARURegions::ALL and the Mode value Modes::ALL may be
// optionally given which passes all rows in the filtered column.
// //
// Responsibilities // Responsibilities
// //
// Stores internally a list of unique frequency mode tuples. // Stores internally a list of unique region, frequency mode tuples.
// Provides methods to add and delete list elements. Provides range // Provides methods to add and delete list elements. Provides range
// iterators for a filtered view of the underlying table. // iterators for a filtered view of the underlying table.
// //
// Collaborations // Collaborations
@ -41,6 +43,7 @@ class FrequencyList final
Q_OBJECT; Q_OBJECT;
public: public:
using Region = IARURegions::Region;
using Frequency = Radio::Frequency; using Frequency = Radio::Frequency;
using Mode = Modes::Mode; using Mode = Modes::Mode;
@ -48,11 +51,12 @@ public:
{ {
Frequency frequency_; Frequency frequency_;
Mode mode_; Mode mode_;
Region region_;
}; };
using FrequencyItems = QList<Item>; using FrequencyItems = QList<Item>;
using BandSet = QSet<QString>; using BandSet = QSet<QString>;
enum Column {mode_column, frequency_column, frequency_mhz_column}; enum Column {region_column, mode_column, frequency_column, frequency_mhz_column, SENTINAL};
// an iterator that meets the requirements of the C++ for range statement // an iterator that meets the requirements of the C++ for range statement
class const_iterator class const_iterator
@ -81,6 +85,8 @@ public:
// Load and store underlying items // Load and store underlying items
FrequencyItems frequency_list (FrequencyItems); FrequencyItems frequency_list (FrequencyItems);
FrequencyItems const& frequency_list () const; FrequencyItems const& frequency_list () const;
FrequencyItems frequency_list (QModelIndexList const&) const;
void frequency_list_merge (FrequencyItems const&);
// Iterators for the sorted and filtered items // Iterators for the sorted and filtered items
// //
@ -95,7 +101,7 @@ public:
const_iterator find (Frequency) const; const_iterator find (Frequency) const;
// Bands of the frequencies // Bands of the frequencies
BandSet all_bands (Mode = Modes::NULL_MODE) const; BandSet all_bands (Region = IARURegions::ALL, Mode = Modes::ALL) const;
BandSet filtered_bands () const; BandSet filtered_bands () const;
// Find the row of the nearest best working frequency given a // Find the row of the nearest best working frequency given a
@ -109,7 +115,7 @@ public:
int best_working_frequency (QString const& band) const; int best_working_frequency (QString const& band) const;
// Set filter // Set filter
Q_SLOT void filter (Mode); Q_SLOT void filter (Region, Mode);
// Reset // Reset
Q_SLOT void reset_to_defaults (); Q_SLOT void reset_to_defaults ();
@ -135,6 +141,7 @@ bool operator == (FrequencyList::Item const& lhs, FrequencyList::Item const& rhs
{ {
return return
lhs.frequency_ == rhs.frequency_ lhs.frequency_ == rhs.frequency_
&& lhs.region_ == rhs.region_
&& lhs.mode_ == rhs.mode_; && lhs.mode_ == rhs.mode_;
} }

99
IARURegions.cpp Normal file
View File

@ -0,0 +1,99 @@
#include "IARURegions.hpp"
#include <algorithm>
#include <QString>
#include <QVariant>
#include <QModelIndex>
#include "moc_IARURegions.cpp"
namespace
{
// human readable strings for each Region enumeration value
char const * const region_names[] =
{
"All",
"Region 1",
"Region 2",
"Region 3",
};
std::size_t constexpr region_names_size = sizeof (region_names) / sizeof (region_names[0]);
}
IARURegions::IARURegions (QObject * parent)
: QAbstractListModel {parent}
{
static_assert (region_names_size == REGIONS_END_SENTINAL_AND_COUNT,
"region_names array must match Region enumeration");
}
char const * IARURegions::name (Region r)
{
return region_names[static_cast<int> (r)];
}
auto IARURegions::value (QString const& s) -> Region
{
auto end = region_names + region_names_size;
auto p = std::find_if (region_names, end
, [&s] (char const * const name) {
return name == s;
});
return p != end ? static_cast<Region> (p - region_names) : ALL;
}
QVariant IARURegions::data (QModelIndex const& index, int role) const
{
QVariant item;
if (index.isValid ())
{
auto const& row = index.row ();
switch (role)
{
case Qt::ToolTipRole:
case Qt::AccessibleDescriptionRole:
item = tr ("IARU Region");
break;
case Qt::EditRole:
item = static_cast<Region> (row);
break;
case Qt::DisplayRole:
case Qt::AccessibleTextRole:
item = region_names[row];
break;
case Qt::TextAlignmentRole:
item = Qt::AlignHCenter + Qt::AlignVCenter;
break;
}
}
return item;
}
QVariant IARURegions::headerData (int section, Qt::Orientation orientation, int role) const
{
QVariant result;
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
{
result = tr ("IARU Region");
}
else
{
result = QAbstractListModel::headerData (section, orientation, role);
}
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);

81
IARURegions.hpp Normal file
View File

@ -0,0 +1,81 @@
#ifndef IARU_REGIONS_HPP__
#define IARU_REGIONS_HPP__
#include <QAbstractListModel>
#include "qt_helpers.hpp"
class QString;
class QVariant;
class QModelIndex;
//
// Class IARURegions - Qt model that implements the list of IARU regions
//
//
// Responsibilities
//
// Provides a single column list model that contains the human
// readable string version of the data region in the display
// role. Also provided is a translatable column header string and
// tool tip string.
//
//
// Collaborations
//
// Implements a concrete sub-class of the QAbstractListModel class.
//
class IARURegions final
: public QAbstractListModel
{
Q_OBJECT
Q_ENUMS (Region)
public:
//
// This enumeration contains the supported regions, to complement
// this an array of human readable strings in the implementation
// (IARURegions.cpp) must be maintained in parallel.
//
enum Region
{
ALL, // matches with all regions
R1,
R2,
R3,
REGIONS_END_SENTINAL_AND_COUNT // this must be last
};
Q_ENUM (Region)
explicit IARURegions (QObject * parent = nullptr);
// translate between enumeration and human readable strings
static char const * name (Region);
static Region value (QString const&);
// Implement the QAbstractListModel interface
int rowCount (QModelIndex const& parent = QModelIndex {}) const override
{
return parent.isValid () ? 0 : REGIONS_END_SENTINAL_AND_COUNT; // Number of regionss in Region enumeration class
}
QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override;
QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override;
};
// Qt boilerplate to make the IARURegions::region enumeration a type
// that can be streamed and queued as a signal argument as well as
// showing the human readable string when output to debug streams.
#if QT_VERSION < 0x050500
// Qt 5.6 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);
#endif

View File

@ -13,7 +13,7 @@ namespace
// human readable strings for each Mode enumeration value // human readable strings for each Mode enumeration value
char const * const mode_names[] = char const * const mode_names[] =
{ {
"", "All",
"JT65", "JT65",
"JT9", "JT9",
"JT4", "JT4",
@ -47,7 +47,7 @@ auto Modes::value (QString const& s) -> Mode
, [&s] (char const * const name) { , [&s] (char const * const name) {
return name == s; return name == s;
}); });
return p != end ? static_cast<Mode> (p - mode_names) : NULL_MODE; return p != end ? static_cast<Mode> (p - mode_names) : ALL;
} }
QVariant Modes::data (QModelIndex const& index, int role) const QVariant Modes::data (QModelIndex const& index, int role) const

View File

@ -39,7 +39,7 @@ public:
// //
enum Mode enum Mode
{ {
NULL_MODE, // NULL Mode - matches with all modes ALL, // matches with all modes
JT65, JT65,
JT9, JT9,
JT4, JT4,

View File

@ -270,10 +270,10 @@ WSPRBandHopping::WSPRBandHopping (QSettings * settings, Configuration const * co
: m_ {settings, configuration, parent_widget} : m_ {settings, configuration, parent_widget}
{ {
// detect changes to the working frequencies model // detect changes to the working frequencies model
m_->WSPR_bands_ = m_->configuration_->frequencies ()->all_bands (Modes::WSPR).toList (); m_->WSPR_bands_ = m_->configuration_->frequencies ()->all_bands (m_->configuration_->region (), Modes::WSPR).toList ();
connect (m_->configuration_->frequencies (), &QAbstractItemModel::layoutChanged connect (m_->configuration_->frequencies (), &QAbstractItemModel::layoutChanged
, [this] () { , [this] () {
m_->WSPR_bands_ = m_->configuration_->frequencies ()->all_bands (Modes::WSPR).toList (); m_->WSPR_bands_ = m_->configuration_->frequencies ()->all_bands (m_->configuration_->region (), Modes::WSPR).toList ();
}); });
// load settings // load settings

View File

@ -7,7 +7,6 @@
#include <QTextStream> #include <QTextStream>
#include <QSettings> #include <QSettings>
#include <QDateTime> #include <QDateTime>
#include <QStandardPaths>
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>

View File

@ -183,7 +183,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_network_manager {this}, m_network_manager {this},
m_valid {true}, m_valid {true},
m_splash {splash}, m_splash {splash},
m_dataDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)},
m_revision {revision ()}, m_revision {revision ()},
m_multiple {multiple}, m_multiple {multiple},
m_multi_settings {multi_settings}, m_multi_settings {multi_settings},
@ -526,7 +525,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
connect (ui->view_phase_response_action, &QAction::triggered, [this] () { connect (ui->view_phase_response_action, &QAction::triggered, [this] () {
if (!m_phaseEqualizationDialog) if (!m_phaseEqualizationDialog)
{ {
m_phaseEqualizationDialog.reset (new PhaseEqualizationDialog {m_settings, m_dataDir, m_phaseEqCoefficients, this}); m_phaseEqualizationDialog.reset (new PhaseEqualizationDialog {m_settings, m_config.writeable_data_dir (), m_phaseEqCoefficients, this});
connect (m_phaseEqualizationDialog.data (), &PhaseEqualizationDialog::phase_equalization_changed, connect (m_phaseEqualizationDialog.data (), &PhaseEqualizationDialog::phase_equalization_changed,
[this] (QVector<double> const& coeffs) { [this] (QVector<double> const& coeffs) {
m_phaseEqCoefficients = coeffs; m_phaseEqCoefficients = coeffs;
@ -768,7 +767,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
, "-m", QString::number (qMin (qMax (QThread::idealThreadCount () - 1, 1), 3)) //FFTW threads , "-m", QString::number (qMin (qMax (QThread::idealThreadCount () - 1, 1), 3)) //FFTW threads
, "-e", QDir::toNativeSeparators (m_appDir) , "-e", QDir::toNativeSeparators (m_appDir)
, "-a", QDir::toNativeSeparators (m_dataDir.absolutePath ()) , "-a", QDir::toNativeSeparators (m_config.writeable_data_dir ().absolutePath ())
, "-t", QDir::toNativeSeparators (m_config.temp_dir ().absolutePath ()) , "-t", QDir::toNativeSeparators (m_config.temp_dir ().absolutePath ())
}; };
QProcessEnvironment env {QProcessEnvironment::systemEnvironment ()}; QProcessEnvironment env {QProcessEnvironment::systemEnvironment ()};
@ -777,7 +776,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
proc_jt9.start(QDir::toNativeSeparators (m_appDir) + QDir::separator () + proc_jt9.start(QDir::toNativeSeparators (m_appDir) + QDir::separator () +
"jt9", jt9_args, QIODevice::ReadWrite | QIODevice::Unbuffered); "jt9", jt9_args, QIODevice::ReadWrite | QIODevice::Unbuffered);
QString fname {QDir::toNativeSeparators(m_dataDir.absoluteFilePath ("wsjtx_wisdom.dat"))}; QString fname {QDir::toNativeSeparators(m_config.writeable_data_dir ().absoluteFilePath ("wsjtx_wisdom.dat"))};
QByteArray cfname=fname.toLocal8Bit(); QByteArray cfname=fname.toLocal8Bit();
fftwf_import_wisdom_from_filename(cfname); fftwf_import_wisdom_from_filename(cfname);
@ -934,7 +933,7 @@ void MainWindow::on_the_minute ()
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
m_astroWidget.reset (); m_astroWidget.reset ();
QString fname {QDir::toNativeSeparators(m_dataDir.absoluteFilePath ("wsjtx_wisdom.dat"))}; QString fname {QDir::toNativeSeparators(m_config.writeable_data_dir ().absoluteFilePath ("wsjtx_wisdom.dat"))};
QByteArray cfname=fname.toLocal8Bit(); QByteArray cfname=fname.toLocal8Bit();
fftwf_export_wisdom_to_filename(cfname); fftwf_export_wisdom_to_filename(cfname);
m_audioThread.quit (); m_audioThread.quit ();
@ -1142,7 +1141,7 @@ void MainWindow::dataSink(qint64 frames)
char line[80]; char line[80];
int k (frames); int k (frames);
QString fname {QDir::toNativeSeparators(m_dataDir.absoluteFilePath ("refspec.dat"))}; QString fname {QDir::toNativeSeparators(m_config.writeable_data_dir ().absoluteFilePath ("refspec.dat"))};
QByteArray bafname = fname.toLatin1(); QByteArray bafname = fname.toLatin1();
const char *c_fname = bafname.data(); const char *c_fname = bafname.data();
int len=fname.length(); int len=fname.length();
@ -1196,7 +1195,7 @@ void MainWindow::dataSink(qint64 frames)
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(), m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
m_config.color_NewCall()); m_config.color_NewCall());
// Append results text to file "fmt.all". // Append results text to file "fmt.all".
QFile f {m_dataDir.absoluteFilePath ("fmt.all")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("fmt.all")};
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
QTextStream out(&f); QTextStream out(&f);
out << t << endl; out << t << endl;
@ -1296,15 +1295,15 @@ void MainWindow::dataSink(qint64 frames)
if(m_diskData) { if(m_diskData) {
cmnd='"' + m_appDir + '"' + "/wsprd -a \"" + cmnd='"' + m_appDir + '"' + "/wsprd -a \"" +
QDir::toNativeSeparators(m_dataDir.absolutePath()) + "\" \"" + m_path + "\""; QDir::toNativeSeparators(m_config.writeable_data_dir ().absolutePath()) + "\" \"" + m_path + "\"";
} else { } else {
if(m_mode=="WSPR-LF") { if(m_mode=="WSPR-LF") {
cmnd='"' + m_appDir + '"' + "/wspr_fsk8d " + degrade + t2 +" -a \"" + cmnd='"' + m_appDir + '"' + "/wspr_fsk8d " + degrade + t2 +" -a \"" +
QDir::toNativeSeparators(m_dataDir.absolutePath()) + "\" " + QDir::toNativeSeparators(m_config.writeable_data_dir ().absolutePath()) + "\" " +
'"' + m_fnameWE + ".wav\""; '"' + m_fnameWE + ".wav\"";
} else { } else {
cmnd='"' + m_appDir + '"' + "/wsprd -a \"" + cmnd='"' + m_appDir + '"' + "/wsprd -a \"" +
QDir::toNativeSeparators(m_dataDir.absolutePath()) + "\" " + QDir::toNativeSeparators(m_config.writeable_data_dir ().absolutePath()) + "\" " +
t2 + '"' + m_fnameWE + ".wav\""; t2 + '"' + m_fnameWE + ".wav\"";
} }
} }
@ -1407,7 +1406,7 @@ void MainWindow::fastSink(qint64 frames)
strncpy(dec_data.params.hiscall,(hisCall + " ").toLatin1 ().constData (), 12); strncpy(dec_data.params.hiscall,(hisCall + " ").toLatin1 ().constData (), 12);
strncpy(dec_data.params.mygrid, (m_config.my_grid()+" ").toLatin1(),6); strncpy(dec_data.params.mygrid, (m_config.my_grid()+" ").toLatin1(),6);
QString dataDir; QString dataDir;
dataDir = m_dataDir.absolutePath (); dataDir = m_config.writeable_data_dir ().absolutePath ();
char ddir[512]; char ddir[512];
strncpy(ddir,dataDir.toLatin1(), sizeof (ddir) - 1); strncpy(ddir,dataDir.toLatin1(), sizeof (ddir) - 1);
float pxmax = 0; float pxmax = 0;
@ -2612,7 +2611,7 @@ void::MainWindow::fast_decode_done()
void MainWindow::writeAllTxt(QString message) void MainWindow::writeAllTxt(QString message)
{ {
// Write decoded text to file "ALL.TXT". // Write decoded text to file "ALL.TXT".
QFile f {m_dataDir.absoluteFilePath ("ALL.TXT")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("ALL.TXT")};
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
QTextStream out(&f); QTextStream out(&f);
if(m_RxLog==1) { if(m_RxLog==1) {
@ -2693,7 +2692,7 @@ void MainWindow::readFromStdout() //readFromStdout
if(navg>1 or t.indexOf("f*")>0) bAvgMsg=true; if(navg>1 or t.indexOf("f*")>0) bAvgMsg=true;
} }
} }
QFile f {m_dataDir.absoluteFilePath ("ALL.TXT")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("ALL.TXT")};
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
QTextStream out(&f); QTextStream out(&f);
if(m_RxLog==1) { if(m_RxLog==1) {
@ -3082,7 +3081,7 @@ void MainWindow::guiUpdate()
m_currentMessageType = -1; m_currentMessageType = -1;
} }
if(m_restart) { if(m_restart) {
QFile f {m_dataDir.absoluteFilePath ("ALL.TXT")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("ALL.TXT")};
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
{ {
QTextStream out(&f); QTextStream out(&f);
@ -3192,7 +3191,7 @@ void MainWindow::guiUpdate()
} }
if(!m_tune) { if(!m_tune) {
QFile f {m_dataDir.absoluteFilePath ("ALL.TXT")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("ALL.TXT")};
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
QTextStream out(&f); QTextStream out(&f);
out << QDateTime::currentDateTimeUtc().toString("hhmm") out << QDateTime::currentDateTimeUtc().toString("hhmm")
@ -3339,7 +3338,7 @@ void MainWindow::startTx2()
ui->decodedTextBrowser->appendText(t); ui->decodedTextBrowser->appendText(t);
} }
QFile f {m_dataDir.absoluteFilePath ("ALL_WSPR.TXT")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("ALL_WSPR.TXT")};
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
QTextStream out(&f); QTextStream out(&f);
out << QDateTime::currentDateTimeUtc().toString("yyMMdd hhmm") out << QDateTime::currentDateTimeUtc().toString("yyMMdd hhmm")
@ -4021,7 +4020,7 @@ void MainWindow::lookup() //lookup()
{ {
QString hisCall {ui->dxCallEntry->text()}; QString hisCall {ui->dxCallEntry->text()};
if (!hisCall.size ()) return; if (!hisCall.size ()) return;
QFile f {m_dataDir.absoluteFilePath ("CALL3.TXT")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("CALL3.TXT")};
if (f.open (QIODevice::ReadOnly | QIODevice::Text)) if (f.open (QIODevice::ReadOnly | QIODevice::Text))
{ {
char c[132]; char c[132];
@ -4075,7 +4074,7 @@ void MainWindow::on_addButton_clicked() //Add button
newEntry += ",,,"; newEntry += ",,,";
// } // }
QFile f1 {m_dataDir.absoluteFilePath ("CALL3.TXT")}; QFile f1 {m_config.writeable_data_dir ().absoluteFilePath ("CALL3.TXT")};
if(!f1.open(QIODevice::ReadWrite | QIODevice::Text)) { if(!f1.open(QIODevice::ReadWrite | QIODevice::Text)) {
MessageBox::warning_message (this, tr ("Add to CALL3.TXT") MessageBox::warning_message (this, tr ("Add to CALL3.TXT")
, tr ("Cannot open \"%1\" for read/write: %2") , tr ("Cannot open \"%1\" for read/write: %2")
@ -4088,7 +4087,7 @@ void MainWindow::on_addButton_clicked() //Add button
f1.close(); f1.close();
f1.open(QIODevice::ReadOnly | QIODevice::Text); f1.open(QIODevice::ReadOnly | QIODevice::Text);
} }
QFile f2 {m_dataDir.absoluteFilePath ("CALL3.TMP")}; QFile f2 {m_config.writeable_data_dir ().absoluteFilePath ("CALL3.TMP")};
if(!f2.open(QIODevice::WriteOnly | QIODevice::Text)) { if(!f2.open(QIODevice::WriteOnly | QIODevice::Text)) {
MessageBox::warning_message (this, tr ("Add to CALL3.TXT") MessageBox::warning_message (this, tr ("Add to CALL3.TXT")
, tr ("Cannot open \"%1\" for writing: %2") , tr ("Cannot open \"%1\" for writing: %2")
@ -4130,11 +4129,11 @@ void MainWindow::on_addButton_clicked() //Add button
f1.close(); f1.close();
if(hc>hc1 && !m_call3Modified) out << newEntry + QChar::LineFeed; if(hc>hc1 && !m_call3Modified) out << newEntry + QChar::LineFeed;
if(m_call3Modified) { if(m_call3Modified) {
QFile f0 {m_dataDir.absoluteFilePath ("CALL3.OLD")}; QFile f0 {m_config.writeable_data_dir ().absoluteFilePath ("CALL3.OLD")};
if(f0.exists()) f0.remove(); if(f0.exists()) f0.remove();
QFile f1 {m_dataDir.absoluteFilePath ("CALL3.TXT")}; QFile f1 {m_config.writeable_data_dir ().absoluteFilePath ("CALL3.TXT")};
f1.rename(m_dataDir.absoluteFilePath ("CALL3.OLD")); f1.rename(m_config.writeable_data_dir ().absoluteFilePath ("CALL3.OLD"));
f2.rename(m_dataDir.absoluteFilePath ("CALL3.TXT")); f2.rename(m_config.writeable_data_dir ().absoluteFilePath ("CALL3.TXT"));
f2.close(); f2.close();
} }
} }
@ -4797,7 +4796,7 @@ void MainWindow::on_actionFreqCal_triggered()
void MainWindow::switch_mode (Mode mode) void MainWindow::switch_mode (Mode mode)
{ {
m_fastGraph->setMode(m_mode); m_fastGraph->setMode(m_mode);
m_config.frequencies ()->filter (mode); m_config.frequencies ()->filter (m_config.region (), mode);
auto const& row = m_config.frequencies ()->best_working_frequency (m_freqNominal); auto const& row = m_config.frequencies ()->best_working_frequency (m_freqNominal);
if (row >= 0) { if (row >= 0) {
ui->bandComboBox->setCurrentIndex (row); ui->bandComboBox->setCurrentIndex (row);
@ -4938,7 +4937,7 @@ void MainWindow::on_actionErase_ALL_TXT_triggered() //Erase ALL.TXT
int ret = MessageBox::query_message (this, tr ("Confirm Erase"), int ret = MessageBox::query_message (this, tr ("Confirm Erase"),
tr ("Are you sure you want to erase file ALL.TXT?")); tr ("Are you sure you want to erase file ALL.TXT?"));
if(ret==MessageBox::Yes) { if(ret==MessageBox::Yes) {
QFile f {m_dataDir.absoluteFilePath ("ALL.TXT")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("ALL.TXT")};
f.remove(); f.remove();
m_RxLog=1; m_RxLog=1;
} }
@ -4949,14 +4948,14 @@ void MainWindow::on_actionErase_wsjtx_log_adi_triggered()
int ret = MessageBox::query_message (this, tr ("Confirm Erase"), int ret = MessageBox::query_message (this, tr ("Confirm Erase"),
tr ("Are you sure you want to erase file wsjtx_log.adi?")); tr ("Are you sure you want to erase file wsjtx_log.adi?"));
if(ret==MessageBox::Yes) { if(ret==MessageBox::Yes) {
QFile f {m_dataDir.absoluteFilePath ("wsjtx_log.adi")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("wsjtx_log.adi")};
f.remove(); f.remove();
} }
} }
void MainWindow::on_actionOpen_log_directory_triggered () void MainWindow::on_actionOpen_log_directory_triggered ()
{ {
QDesktopServices::openUrl (QUrl::fromLocalFile (m_dataDir.absolutePath ())); QDesktopServices::openUrl (QUrl::fromLocalFile (m_config.writeable_data_dir ().absolutePath ()));
} }
void MainWindow::on_bandComboBox_currentIndexChanged (int index) void MainWindow::on_bandComboBox_currentIndexChanged (int index)
@ -5394,7 +5393,7 @@ void MainWindow::handle_transceiver_update (Transceiver::TransceiverState const&
m_secBandChanged=QDateTime::currentMSecsSinceEpoch()/1000; m_secBandChanged=QDateTime::currentMSecsSinceEpoch()/1000;
if(s.frequency () < 30000000u && !m_mode.startsWith ("WSPR")) { if(s.frequency () < 30000000u && !m_mode.startsWith ("WSPR")) {
// Write freq changes to ALL.TXT only below 30 MHz. // Write freq changes to ALL.TXT only below 30 MHz.
QFile f2 {m_dataDir.absoluteFilePath ("ALL.TXT")}; QFile f2 {m_config.writeable_data_dir ().absoluteFilePath ("ALL.TXT")};
if (f2.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { if (f2.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
QTextStream out(&f2); QTextStream out(&f2);
out << QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hh:mm") out << QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hh:mm")
@ -6024,7 +6023,7 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
int msdelay=20000*x; int msdelay=20000*x;
uploadTimer.start(msdelay); //Upload delay uploadTimer.start(msdelay); //Upload delay
} else { } else {
QFile f(QDir::toNativeSeparators(m_dataDir.absolutePath()) + "/wspr_spots.txt"); QFile f(QDir::toNativeSeparators(m_config.writeable_data_dir ().absolutePath()) + "/wspr_spots.txt");
if(f.exists()) f.remove(); if(f.exists()) f.remove();
} }
m_RxLog=0; m_RxLog=0;
@ -6117,7 +6116,7 @@ void MainWindow::WSPR_history(Frequency dialFreq, int ndecodes)
t4.sprintf("%4d",ndecodes); t4.sprintf("%4d",ndecodes);
t1=t1 + " " + t2 + t3 + " R" + t4; t1=t1 + " " + t2 + t3 + " R" + t4;
} }
QFile f {m_dataDir.absoluteFilePath ("WSPR_history.txt")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("WSPR_history.txt")};
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
QTextStream out(&f); QTextStream out(&f);
out << t1 << endl; out << t1 << endl;
@ -6145,7 +6144,7 @@ void MainWindow::uploadSpots()
wsprNet->upload(m_config.my_callsign(), m_config.my_grid(), rfreq, tfreq, wsprNet->upload(m_config.my_callsign(), m_config.my_grid(), rfreq, tfreq,
m_mode, QString::number(ui->autoButton->isChecked() ? m_pctx : 0), m_mode, QString::number(ui->autoButton->isChecked() ? m_pctx : 0),
QString::number(m_dBm), version(), QString::number(m_dBm), version(),
QDir::toNativeSeparators(m_dataDir.absolutePath()) + "/wspr_spots.txt"); QDir::toNativeSeparators(m_config.writeable_data_dir ().absolutePath()) + "/wspr_spots.txt");
m_uploading = true; m_uploading = true;
} }

View File

@ -303,7 +303,6 @@ private:
NetworkAccessManager m_network_manager; NetworkAccessManager m_network_manager;
bool m_valid; bool m_valid;
QSplashScreen * m_splash; QSplashScreen * m_splash;
QDir m_dataDir;
QString m_revision; QString m_revision;
bool m_multiple; bool m_multiple;
MultiSettings * m_multi_settings; MultiSettings * m_multi_settings;