diff --git a/CMakeLists.txt b/CMakeLists.txt index 66f5f127f..b07964a7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Configuration.cpp b/Configuration.cpp index 565b73b2e..cc977fd7c 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -168,6 +168,11 @@ #include #include #include +#include +#include +#include +#include + #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:"), ®ion_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 {®ions_, 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 {®ions_, 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 (); - 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 ()); + frequencies_.frequency_list (v.value ()); } 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(); + 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 ()); @@ -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(); } } diff --git a/Configuration.hpp b/Configuration.hpp index cb32f0365..85b887ae7 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -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 (); diff --git a/MetaDataRegistry.cpp b/MetaDataRegistry.cpp index c39551fa1..f6c50c1f1 100644 --- a/MetaDataRegistry.cpp +++ b/MetaDataRegistry.cpp @@ -52,9 +52,13 @@ void register_types () item_editor_factory->registerEditor (qMetaTypeId (), new QStandardItemEditorCreator ()); - // Frequency list model + // V101 Frequency list model + qRegisterMetaTypeStreamOperators ("Item_v2_101"); + QMetaType::registerConverter (&FrequencyList_v2_101::Item::toString); + qRegisterMetaTypeStreamOperators ("FrequencyItems_v2_101"); + + // V100 Frequency list model qRegisterMetaTypeStreamOperators ("Item_v2"); - QMetaType::registerConverter (&FrequencyList_v2::Item::toString); qRegisterMetaTypeStreamOperators ("FrequencyItems_v2"); // defunct old versions diff --git a/WSPR/WSPRBandHopping.hpp b/WSPR/WSPRBandHopping.hpp index 9af27b5f3..9f65de177 100644 --- a/WSPR/WSPRBandHopping.hpp +++ b/WSPR/WSPRBandHopping.hpp @@ -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. diff --git a/item_delegates/MessageItemDelegate.cpp b/item_delegates/MessageItemDelegate.cpp new file mode 100644 index 000000000..df9953e45 --- /dev/null +++ b/item_delegates/MessageItemDelegate.cpp @@ -0,0 +1,26 @@ +// +// Moved from Configuration.cpp +// + +#include "MessageItemDelegate.hpp" + +#include +#include + +// +// 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; +} diff --git a/item_delegates/MessageItemDelegate.hpp b/item_delegates/MessageItemDelegate.hpp new file mode 100644 index 000000000..eede221c1 --- /dev/null +++ b/item_delegates/MessageItemDelegate.hpp @@ -0,0 +1,20 @@ +// +// +// + +#ifndef WSJTX_MESSAGEITEMDELEGATE_H +#define WSJTX_MESSAGEITEMDELEGATE_H + +#include + +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 diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 38e8a15bb..5d9ccc827 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -586,13 +586,26 @@ contains xsig=xsig+s4(itone(i),i) enddo base=candidates(icand,5) - arg=600.0*(xsig/base)-1.0 + select case(ntrperiod) + case(15) + snr_calfac=800.0 + case(30) + snr_calfac=600.0 + case(60) + snr_calfac=430.0 + case(120) + snr_calfac=390.0 + case(300) + snr_calfac=340.0 + case(900) + snr_calfac=320.0 + case(1800) + snr_calfac=320.0 + case default + end select + arg=snr_calfac*xsig/base - 1.0 if(arg.gt.0.0) then - xsnr=10*log10(arg)-35.5-12.5*log10(nsps/8200.0) - if(ntrperiod.eq. 15) xsnr=xsnr+2 - if(ntrperiod.eq. 30) xsnr=xsnr+1 - if(ntrperiod.eq. 900) xsnr=xsnr+1 - if(ntrperiod.eq.1800) xsnr=xsnr+2 + xsnr=10*log10(arg)+10*log10(1.46/2500)+10*log10(8200.0/nsps) else xsnr=-99.9 endif diff --git a/map65/libm65/decode0.f90 b/map65/libm65/decode0.f90 index 7401c509a..ba167cddf 100644 --- a/map65/libm65/decode0.f90 +++ b/map65/libm65/decode0.f90 @@ -14,6 +14,7 @@ subroutine decode0(dd,ss,savg,nstandalone) mcall3,nkeep,ntol,nxant,nrxlog,nfsample,nxpol,nmode, & nfast,nsave,max_drift,nhsym,mycall,mygrid,hiscall,hisgrid,datetime common/early/nhsym1,nhsym2,ldecoded(32768) + common/decodes/ndecodes data neme0/-99/,mcall3b/1/ save @@ -62,8 +63,8 @@ subroutine decode0(dd,ss,savg,nstandalone) call sec0(1,tdec) if(nhsym.eq.nhsym1) write(*,1010) nsum,nsave,nstandalone,nhsym,tdec 1010 format('',3i4,i6,f6.2) - if(nhsym.eq.nhsym2) write(*,1012) nsum,nsave,nstandalone,nhsym,tdec -1012 format('',3i4,i6,f6.2) + if(nhsym.eq.nhsym2) write(*,1012) nsum,nsave,nstandalone,nhsym,tdec,ndecodes +1012 format('',3i4,i6,f6.2,i5) flush(6) return diff --git a/map65/libm65/map65a.f90 b/map65/libm65/map65a.f90 index 25eae0aef..87afa48cd 100644 --- a/map65/libm65/map65a.f90 +++ b/map65/libm65/map65a.f90 @@ -34,12 +34,15 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, & common/c3com/ mcall3a common/testcom/ifreq common/early/nhsym1,nhsym2,ldecoded(32768) + common/decodes/ndecodes data blank/' '/,cm/'#'/ data shmsg0/'ATT','RO ','RRR','73 '/ data nfile/0/,nutc0/-999/,nid/0/,ip000/1/,ip001/1/,mousefqso0/-999/ save + ndecodes=0 + ! Clean start for Q65 at early decode if(nhsym.eq.nhsym1 .or. nagain.ne.0) ldecoded=.false. if(ndiskdat.eq.1) ldecoded=.false. @@ -499,6 +502,7 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, & write(26,1014) f0,ndf,ndf0,ndf1,ndf2,dt,npol,nsync1, & nsync2,nutc,decoded,cp,cmode 1014 format(f8.3,i5,3i3,f5.1,i4,i3,i4,i5.4,4x,a22,2x,a1,3x,a2) + ndecodes=ndecodes+1 write(21,1100) f0,ndf,dt,npol,nsync2,nutc,decoded,cp, & cmode(1:1),cmode(2:2) 1100 format(f8.3,i5,f5.1,2i4,i5.4,2x,a22,2x,a1,3x,a1,1x,a1) diff --git a/map65/libm65/q65b.f90 b/map65/libm65/q65b.f90 index 3366694d5..92be6528a 100644 --- a/map65/libm65/q65b.f90 +++ b/map65/libm65/q65b.f90 @@ -35,6 +35,7 @@ subroutine q65b(nutc,nqd,nxant,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, & character*1 cp,cmode*2 common/cacb/ca,cb common/early/nhsym1,nhsym2,ldecoded(32768) + common/decodes/ndecodes data nutc00/-1/,msg00/' '/ save @@ -179,6 +180,7 @@ subroutine q65b(nutc,nqd,nxant,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, & ! to map65_rx.log if(nutc.ne.nutc00 .or. msg0(1:28).ne.msg00 .or. freq1.ne.freq1_00) then ! Write to file map65_rx.log: + ndecodes=ndecodes+1 write(21,1110) freq1,ndf,xdt0,npol,nsnr0,nutc,msg0(1:28),cq0 1110 format(f8.3,i5,f5.1,2i4,i5.4,2x,a28,': A',2x,a3) nutc00=nutc diff --git a/map65/mainwindow.cpp b/map65/mainwindow.cpp index 99dd59527..4ab500f65 100644 --- a/map65/mainwindow.cpp +++ b/map65/mainwindow.cpp @@ -1416,6 +1416,8 @@ void MainWindow::readFromStdout() //readFromStdout QFile lockFile(m_appDir + "/.lock"); lockFile.open(QIODevice::ReadWrite); if(t.indexOf("") >= 0) { + int ndecodes=t.mid(40,5).toInt(); + lab5->setText(QString::number(ndecodes)); m_map65RxLog=0; m_startAnother=m_loopall; } diff --git a/map65/mainwindow.h b/map65/mainwindow.h index bbf3e707c..ebee97403 100644 --- a/map65/mainwindow.h +++ b/map65/mainwindow.h @@ -194,7 +194,6 @@ private: qint32 m_RxState; qint32 m_dB; - double m_fAdd; // double m_IQamp; // double m_IQphase; diff --git a/models/Bands.hpp b/models/Bands.hpp index 170d4c756..77ae5766b 100644 --- a/models/Bands.hpp +++ b/models/Bands.hpp @@ -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 diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp index cac85ea5a..323dda126 100644 --- a/models/FrequencyList.cpp +++ b/models/FrequencyList.cpp @@ -5,6 +5,7 @@ #include #include + #include #include #include @@ -17,51 +18,59 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "Radio.hpp" #include "Bands.hpp" #include "pimpl_impl.hpp" +#include "revision_utils.hpp" +#include "Logger.hpp" #include "moc_FrequencyList.cpp" namespace { - FrequencyList_v2::FrequencyItems const default_frequency_list = + FrequencyList_v2_101::FrequencyItems const default_frequency_list = { - {198000, Modes::FreqCal, IARURegions::R1}, // BBC Radio 4 Droitwich - {4996000, Modes::FreqCal, IARURegions::R1}, // RWM time signal - {9996000, Modes::FreqCal, IARURegions::R1}, // RWM time signal - {14996000, Modes::FreqCal, IARURegions::R1}, // RWM time signal + {198000, Modes::FreqCal, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, // BBC Radio 4 Droitwich + {4996000, Modes::FreqCal, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, // RWM time signal + {9996000, Modes::FreqCal, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, // RWM time signal + {14996000, Modes::FreqCal, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, // RWM time signal - {660000, Modes::FreqCal, IARURegions::R2}, - {880000, Modes::FreqCal, IARURegions::R2}, - {1210000, Modes::FreqCal, IARURegions::R2}, + {660000, Modes::FreqCal, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {880000, Modes::FreqCal, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {1210000, Modes::FreqCal, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, - {2500000, Modes::FreqCal, IARURegions::ALL}, - {3330000, Modes::FreqCal, IARURegions::ALL}, - {5000000, Modes::FreqCal, IARURegions::ALL}, - {7850000, Modes::FreqCal, IARURegions::ALL}, - {10000000, Modes::FreqCal, IARURegions::ALL}, - {14670000, Modes::FreqCal, IARURegions::ALL}, - {15000000, Modes::FreqCal, IARURegions::ALL}, - {20000000, Modes::FreqCal, IARURegions::ALL}, + {2500000, Modes::FreqCal, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {3330000, Modes::FreqCal, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {5000000, Modes::FreqCal, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {7850000, Modes::FreqCal, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {10000000, Modes::FreqCal, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {14670000, Modes::FreqCal, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {15000000, Modes::FreqCal, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {20000000, Modes::FreqCal, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, - {136000, Modes::WSPR, IARURegions::ALL}, - {136000, Modes::FST4, IARURegions::ALL}, - {136000, Modes::FST4W, IARURegions::ALL}, - {136000, Modes::JT9, IARURegions::ALL}, + {136000, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {136000, Modes::FST4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {136000, Modes::FST4W, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {136000, Modes::JT9, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {474200, Modes::JT9, IARURegions::ALL}, - {474200, Modes::FST4, IARURegions::ALL}, - {474200, Modes::WSPR, IARURegions::ALL}, - {474200, Modes::FST4W, IARURegions::ALL}, + {474200, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {474200, Modes::FST4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {474200, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {474200, Modes::FST4W, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, - {1836600, Modes::WSPR, IARURegions::ALL}, - {1836800, Modes::FST4W, IARURegions::ALL}, - {1838000, Modes::JT65, IARURegions::ALL}, // squeezed allocations - {1839000, Modes::JT9, IARURegions::ALL}, - {1839000, Modes::FST4, IARURegions::ALL}, - {1840000, Modes::FT8, IARURegions::ALL}, + {1836600, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {1836800, Modes::FST4W, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {1838000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // squeezed allocations + {1839000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {1839000, Modes::FST4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {1840000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // Band plans (all USB dial unless stated otherwise) // @@ -90,12 +99,12 @@ namespace // 3580 PSK31 // 3600 LSB EMCOMM // - {3570000, Modes::JT65, IARURegions::ALL}, // JA compatible - {3572000, Modes::JT9, IARURegions::ALL}, - {3573000, Modes::FT8, IARURegions::ALL}, // above as below JT65 is out of DM allocation - {3568600, Modes::WSPR, IARURegions::ALL}, // needs guard marker and lock out - {3575000, Modes::FT4, IARURegions::ALL}, // provisional - {3568000, Modes::FT4, IARURegions::R3}, // provisional + {3570000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // JA compatible + {3572000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {3573000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // above as below JT65 is out of DM allocation + {3568600, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // needs guard marker and lock out + {3575000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // provisional + {3568000, Modes::FT4, IARURegions::R3, "","", QDateTime(), QDateTime(), false}, // provisional // Band plans (all USB dial unless stated otherwise) // @@ -128,11 +137,11 @@ namespace // 7090 LSB QRP CoA // 7110 LSB EMCOMM // - {7038600, Modes::WSPR, IARURegions::ALL}, - {7074000, Modes::FT8, IARURegions::ALL}, - {7076000, Modes::JT65, IARURegions::ALL}, - {7078000, Modes::JT9, IARURegions::ALL}, - {7047500, Modes::FT4, IARURegions::ALL}, // provisional - moved + {7038600, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {7074000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {7076000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {7078000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {7047500, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // provisional - moved // up 500Hz to clear // W1AW code practice QRG @@ -162,11 +171,11 @@ namespace // 10142.25 OLIVIA, Contestia, etc. // 10143.25 OLIVIA, Contestia, etc. (main QRG) // - {10136000, Modes::FT8, IARURegions::ALL}, - {10138000, Modes::JT65, IARURegions::ALL}, - {10138700, Modes::WSPR, IARURegions::ALL}, - {10140000, Modes::JT9, IARURegions::ALL}, - {10140000, Modes::FT4, IARURegions::ALL}, // provisional + {10136000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {10138000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {10138700, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {10140000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {10140000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // provisional // Band plans (all USB dial unless stated otherwise) // @@ -205,11 +214,11 @@ namespace // 14105.5 OLIVIA 1000 // 14106.5 OLIVIA 1000 (main QRG) // - {14095600, Modes::WSPR, IARURegions::ALL}, - {14074000, Modes::FT8, IARURegions::ALL}, - {14076000, Modes::JT65, IARURegions::ALL}, - {14078000, Modes::JT9, IARURegions::ALL}, - {14080000, Modes::FT4, IARURegions::ALL}, // provisional + {14095600, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {14074000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {14076000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {14078000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {14080000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // provisional // Band plans (all USB dial unless stated otherwise) // @@ -238,148 +247,179 @@ namespace // 18104.4 OLIVIA, Contestia, etc. // 18110 NCDXF beacons // - {18100000, Modes::FT8, IARURegions::ALL}, - {18102000, Modes::JT65, IARURegions::ALL}, - {18104000, Modes::JT9, IARURegions::ALL}, - {18104000, Modes::FT4, IARURegions::ALL}, // provisional - {18104600, Modes::WSPR, IARURegions::ALL}, + {18100000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {18102000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {18104000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {18104000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // provisional + {18104600, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, - {21074000, Modes::FT8, IARURegions::ALL}, - {21076000, Modes::JT65, IARURegions::ALL}, - {21078000, Modes::JT9, IARURegions::ALL}, - {21094600, Modes::WSPR, IARURegions::ALL}, - {21140000, Modes::FT4, IARURegions::ALL}, + {21074000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {21076000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {21078000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {21094600, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {21140000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, - {24915000, Modes::FT8, IARURegions::ALL}, - {24917000, Modes::JT65, IARURegions::ALL}, - {24919000, Modes::JT9, IARURegions::ALL}, - {24919000, Modes::FT4, IARURegions::ALL}, // provisional - {24924600, Modes::WSPR, IARURegions::ALL}, + {24915000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {24917000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {24919000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {24919000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // provisional + {24924600, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, - {28074000, Modes::FT8, IARURegions::ALL}, - {28076000, Modes::JT65, IARURegions::ALL}, - {28078000, Modes::JT9, IARURegions::ALL}, - {28124600, Modes::WSPR, IARURegions::ALL}, - {28180000, Modes::FT4, IARURegions::ALL}, + {28074000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {28076000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {28078000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {28124600, Modes::WSPR, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {28180000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, - {50200000, Modes::Echo, IARURegions::ALL}, - {50211000, Modes::Q65, IARURegions::ALL}, - {50275000, Modes::Q65, IARURegions::ALL}, - {50276000, Modes::JT65, IARURegions::R2}, - {50276000, Modes::JT65, IARURegions::R3}, - {50380000, Modes::MSK144, IARURegions::R1}, - {50260000, Modes::MSK144, IARURegions::R2}, - {50260000, Modes::MSK144, IARURegions::R3}, - {50293000, Modes::WSPR, IARURegions::R2}, - {50293000, Modes::WSPR, IARURegions::R3}, - {50310000, Modes::JT65, IARURegions::ALL}, - {50312000, Modes::JT9, IARURegions::ALL}, - {50313000, Modes::FT8, IARURegions::ALL}, - {50318000, Modes::FT4, IARURegions::ALL}, // provisional - {50323000, Modes::FT8, IARURegions::ALL}, + {50200000, Modes::Echo, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {50211000, Modes::Q65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {50275000, Modes::Q65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {50276000, Modes::JT65, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {50276000, Modes::JT65, IARURegions::R3, "","", QDateTime(), QDateTime(), false}, + {50380000, Modes::MSK144, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, + {50260000, Modes::MSK144, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {50260000, Modes::MSK144, IARURegions::R3, "","", QDateTime(), QDateTime(), false}, + {50293000, Modes::WSPR, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {50293000, Modes::WSPR, IARURegions::R3, "","", QDateTime(), QDateTime(), false}, + {50310000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {50312000, Modes::JT9, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {50313000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {50318000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, // provisional + {50323000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, - {70102000, Modes::JT65, IARURegions::R1}, - {70104000, Modes::JT9, IARURegions::R1}, - {70091000, Modes::WSPR, IARURegions::R1}, - {70154000, Modes::FT8, IARURegions::R1}, - {70230000, Modes::MSK144, IARURegions::R1}, + {70102000, Modes::JT65, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, + {70104000, Modes::JT9, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, + {70091000, Modes::WSPR, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, + {70154000, Modes::FT8, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, + {70230000, Modes::MSK144, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, - {144116000, Modes::Q65, IARURegions::ALL}, - {144120000, Modes::JT65, IARURegions::ALL}, - {144120000, Modes::Echo, IARURegions::ALL}, - {144170000, Modes::FT4, IARURegions::ALL}, - {144174000, Modes::FT8, IARURegions::ALL}, - {144360000, Modes::MSK144, IARURegions::R1}, - {144150000, Modes::MSK144, IARURegions::R2}, - {144489000, Modes::WSPR, IARURegions::ALL}, + {144116000, Modes::Q65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {144120000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {144120000, Modes::Echo, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {144170000, Modes::FT4, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {144174000, Modes::FT8, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {144360000, Modes::MSK144, IARURegions::R1, "","", QDateTime(), QDateTime(), false}, + {144150000, Modes::MSK144, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {144489000, Modes::WSPR, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {222065000, Modes::Echo, IARURegions::R2}, - {222065000, Modes::JT65, IARURegions::R2}, - {222065000, Modes::Q65, IARURegions::R2}, + {222065000, Modes::Echo, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {222065000, Modes::JT65, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {222065000, Modes::Q65, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, - {432065000, Modes::Echo, IARURegions::ALL}, - {432065000, Modes::JT65, IARURegions::ALL}, - {432300000, Modes::WSPR, IARURegions::ALL}, - {432360000, Modes::MSK144, IARURegions::ALL}, - {432065000, Modes::Q65, IARURegions::ALL}, + {432065000, Modes::Echo, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {432065000, Modes::JT65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {432300000, Modes::WSPR, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {432360000, Modes::MSK144, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {432065000, Modes::Q65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {902065000, Modes::JT65, IARURegions::R2}, - {902065000, Modes::Q65, IARURegions::R2}, + {902065000, Modes::JT65, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, + {902065000, Modes::Q65, IARURegions::R2, "","", QDateTime(), QDateTime(), false}, - {1296065000, Modes::Echo, IARURegions::ALL}, - {1296065000, Modes::JT65, IARURegions::ALL}, - {1296500000, Modes::WSPR, IARURegions::ALL}, - {1296065000, Modes::Q65, IARURegions::ALL}, + {1296065000, Modes::Echo, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {1296065000, Modes::JT65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {1296500000, Modes::WSPR, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {1296065000, Modes::Q65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {2301000000, Modes::Echo, IARURegions::ALL}, - {2301065000, Modes::JT4, IARURegions::ALL}, - {2301065000, Modes::JT65, IARURegions::ALL}, - {2301065000, Modes::Q65, IARURegions::ALL}, + {2301000000, Modes::Echo, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {2301065000, Modes::JT4, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {2301065000, Modes::JT65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {2301065000, Modes::Q65, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, - {2304065000, Modes::Echo, IARURegions::ALL}, - {2304065000, Modes::JT4, IARURegions::ALL}, - {2304065000, Modes::JT65, IARURegions::ALL}, - {2304065000, Modes::Q65, IARURegions::ALL}, + {2304065000, Modes::Echo, IARURegions::ALL, "","", QDateTime(), QDateTime(), false}, + {2304065000, Modes::JT4, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {2304065000, Modes::JT65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {2304065000, Modes::Q65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {2320065000, Modes::Echo, IARURegions::ALL}, - {2320065000, Modes::JT4, IARURegions::ALL}, - {2320065000, Modes::JT65, IARURegions::ALL}, - {2320065000, Modes::Q65, IARURegions::ALL}, + {2320065000, Modes::Echo, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {2320065000, Modes::JT4, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {2320065000, Modes::JT65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {2320065000, Modes::Q65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {3400065000, Modes::Echo, IARURegions::ALL}, - {3400065000, Modes::JT4, IARURegions::ALL}, - {3400065000, Modes::JT65, IARURegions::ALL}, - {3400065000, Modes::Q65, IARURegions::ALL}, + {3400065000, Modes::Echo, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {3400065000, Modes::JT4, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {3400065000, Modes::JT65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {3400065000, Modes::Q65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {5760065000, Modes::Echo, IARURegions::ALL}, - {5760065000, Modes::JT4, IARURegions::ALL}, - {5760065000, Modes::JT65, IARURegions::ALL}, - {5760200000, Modes::Q65, IARURegions::ALL}, + {5760065000, Modes::Echo, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {5760065000, Modes::JT4, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {5760065000, Modes::JT65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {5760200000, Modes::Q65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {10368100000, Modes::Echo, IARURegions::ALL}, - {10368200000, Modes::JT4, IARURegions::ALL}, - {10368200000, Modes::Q65, IARURegions::ALL}, + {10368100000, Modes::Echo, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {10368200000, Modes::JT4, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {10368200000, Modes::Q65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, - {24048100000, Modes::Echo, IARURegions::ALL}, - {24048200000, Modes::JT4, IARURegions::ALL}, - {24048200000, Modes::Q65, IARURegions::ALL}, + {24048100000, Modes::Echo, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {24048200000, Modes::JT4, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, + {24048200000, Modes::Q65, IARURegions::ALL,"","", QDateTime(), QDateTime(), false}, }; } #if !defined (QT_NO_DEBUG_STREAM) -QDebug operator << (QDebug debug, FrequencyList_v2::Item const& item) +QDebug operator << (QDebug debug, FrequencyList_v2_101::Item const& item) { QDebugStateSaver saver {debug}; return debug.nospace () << item.toString (); } #endif +bool FrequencyList_v2_101::Item::isSane() const +{ + return frequency_ > 0.0 && (!start_time_.isValid() || !end_time_.isValid() || start_time_ < end_time_) + && (region_ == IARURegions::ALL || region_ == IARURegions::R1 || region_ == IARURegions::R2 || region_ == IARURegions::R3); +} -QString FrequencyList_v2::Item::toString () const +QString FrequencyList_v2_101::Item::toString () const { QString string; QTextStream qts {&string}; qts << "FrequencyItem(" << Radio::frequency_MHz_string (frequency_) << ", " << IARURegions::name (region_) << ", " - << Modes::name (mode_) << ')'; + << Modes::name (mode_) << ", " + << start_time_.toString(Qt::ISODate) << ", " + << end_time_.toString(Qt::ISODate) << ", " + << description_ << ", " + << source_ << "," + << preferred_ << ')'; return string; } -QDataStream& operator << (QDataStream& os, FrequencyList_v2::Item const& item) +QJsonObject FrequencyList_v2_101::Item::toJson() const { + return {{"frequency", Radio::frequency_MHz_string (frequency_) }, + {"mode", Modes::name (mode_) }, + {"region", IARURegions::name (region_)}, + {"description", description_}, + {"source", source_}, + {"start_time", start_time_.toString(Qt::ISODate) }, + {"end_time", end_time_.toString(Qt::ISODate) }, + {"preferred", preferred_}}; +} + +QDataStream& operator << (QDataStream& os, FrequencyList_v2_101::Item const& item) { return os << item.frequency_ << item.mode_ - << item.region_; + << item.region_ + << item.start_time_ + << item.end_time_ + << item.description_ + << item.source_ + << item.preferred_; } -QDataStream& operator >> (QDataStream& is, FrequencyList_v2::Item& item) +QDataStream& operator >> (QDataStream& is, FrequencyList_v2_101::Item& item) { return is >> item.frequency_ >> item.mode_ - >> item.region_; + >> item.region_ + >> item.start_time_ + >> item.end_time_ + >> item.description_ + >> item.source_ + >> item.preferred_; } -class FrequencyList_v2::impl final +class FrequencyList_v2_101::impl final : public QAbstractTableModel { public: @@ -388,6 +428,7 @@ public: , bands_ {bands} , region_filter_ {IARURegions::ALL} , mode_filter_ {Modes::ALL} + , filter_on_time_ {false} { } @@ -407,6 +448,8 @@ public: QStringList mimeTypes () const override; QMimeData * mimeData (QModelIndexList const&) const override; + void unprefer_all_but(Item & item, int const row, QVector ); + static int constexpr num_cols {SENTINAL}; static auto constexpr mime_type = "application/wsjt.Frequencies"; @@ -414,9 +457,11 @@ public: FrequencyItems frequency_list_; Region region_filter_; Mode mode_filter_; + bool filter_on_time_; + }; -FrequencyList_v2::FrequencyList_v2 (Bands const * bands, QObject * parent) +FrequencyList_v2_101::FrequencyList_v2_101 (Bands const * bands, QObject * parent) : QSortFilterProxyModel {parent} , m_ {bands, parent} { @@ -424,21 +469,21 @@ FrequencyList_v2::FrequencyList_v2 (Bands const * bands, QObject * parent) setSortRole (SortRole); } -FrequencyList_v2::~FrequencyList_v2 () +FrequencyList_v2_101::~FrequencyList_v2_101 () { } -auto FrequencyList_v2::frequency_list (FrequencyItems frequency_list) -> FrequencyItems +auto FrequencyList_v2_101::frequency_list (FrequencyItems frequency_list) -> FrequencyItems { return m_->frequency_list (frequency_list); } -auto FrequencyList_v2::frequency_list () const -> FrequencyItems const& +auto FrequencyList_v2_101::frequency_list () const -> FrequencyItems const& { return m_->frequency_list_; } -auto FrequencyList_v2::frequency_list (QModelIndexList const& model_index_list) const -> FrequencyItems +auto FrequencyList_v2_101::frequency_list (QModelIndexList const& model_index_list) const -> FrequencyItems { FrequencyItems list; Q_FOREACH (auto const& index, model_index_list) @@ -448,12 +493,13 @@ auto FrequencyList_v2::frequency_list (QModelIndexList const& model_index_list) return list; } -void FrequencyList_v2::frequency_list_merge (FrequencyItems const& items) +void FrequencyList_v2_101::frequency_list_merge (FrequencyItems const& items) { m_->add (items); } -int FrequencyList_v2::best_working_frequency (Frequency f) const + +int FrequencyList_v2_101::best_working_frequency (Frequency f) const { int result {-1}; auto const& target_band = m_->bands_->find (f); @@ -468,6 +514,11 @@ int FrequencyList_v2::best_working_frequency (Frequency f) const auto const& band = m_->bands_->find (candidate_frequency); if (band == target_band) { + // take the preferred one + if (m_->frequency_list_[source_row].preferred_) + { + return row; + } // take closest band match Radio::FrequencyDelta new_delta = f - candidate_frequency; if (std::abs (new_delta) < std::abs (delta)) @@ -481,7 +532,7 @@ int FrequencyList_v2::best_working_frequency (Frequency f) const return result; } -int FrequencyList_v2::best_working_frequency (QString const& target_band) const +int FrequencyList_v2_101::best_working_frequency (QString const& target_band) const { int result {-1}; if (!target_band.isEmpty ()) @@ -493,24 +544,26 @@ int FrequencyList_v2::best_working_frequency (QString const& target_band) const auto const& band = m_->bands_->find (m_->frequency_list_[source_row].frequency_); if (band == target_band) { - return row; + if (m_->frequency_list_[source_row].preferred_) + return row; // return the preferred one immediately + result = row; } } } return result; } -void FrequencyList_v2::reset_to_defaults () +void FrequencyList_v2_101::reset_to_defaults () { m_->frequency_list (default_frequency_list); } -QModelIndex FrequencyList_v2::add (Item f) +QModelIndex FrequencyList_v2_101::add (Item f) { return mapFromSource (m_->add (f)); } -bool FrequencyList_v2::remove (Item f) +bool FrequencyList_v2_101::remove (Item f) { auto row = m_->frequency_list_.indexOf (f); @@ -522,13 +575,13 @@ bool FrequencyList_v2::remove (Item f) return m_->removeRow (row); } -bool FrequencyList_v2::removeDisjointRows (QModelIndexList rows) +bool FrequencyList_v2_101::removeDisjointRows (QModelIndexList rows) { bool result {true}; // We must work with source model indexes because we don't want row // removes to invalidate model indexes we haven't yet processed. We - // achieve that by processing them in decending row order. + // achieve that by processing them in descending row order. for (int r = 0; r < rows.size (); ++r) { rows[r] = mapToSource (rows[r]); @@ -549,14 +602,20 @@ bool FrequencyList_v2::removeDisjointRows (QModelIndexList rows) return result; } -void FrequencyList_v2::filter (Region region, Mode mode) +void FrequencyList_v2_101::filter (Region region, Mode mode, bool filter_on_time) { m_->region_filter_ = region; m_->mode_filter_ = mode; + m_->filter_on_time_ = filter_on_time; invalidateFilter (); } -bool FrequencyList_v2::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const +void FrequencyList_v2_101::filter_refresh () +{ + invalidateFilter (); +} + +bool FrequencyList_v2_101::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const { bool result {true}; auto const& item = m_->frequency_list_[source_row]; @@ -570,11 +629,16 @@ bool FrequencyList_v2::filterAcceptsRow (int source_row, QModelIndex const& /* p result = (Modes::ALL == item.mode_ && m_->mode_filter_ != Modes::FreqCal) || m_->mode_filter_ == item.mode_; } + if (result && m_->filter_on_time_) + { + result = (!item.start_time_.isValid() || item.start_time_ <= QDateTime::currentDateTimeUtc ()) && + (!item.end_time_.isValid() || item.end_time_ >= QDateTime::currentDateTimeUtc ()); + } return result; } -auto FrequencyList_v2::impl::frequency_list (FrequencyItems frequency_list) -> FrequencyItems +auto FrequencyList_v2_101::impl::frequency_list (FrequencyItems frequency_list) -> FrequencyItems { beginResetModel (); std::swap (frequency_list_, frequency_list); @@ -583,7 +647,7 @@ auto FrequencyList_v2::impl::frequency_list (FrequencyItems frequency_list) -> F } // add a frequency returning the new model index -QModelIndex FrequencyList_v2::impl::add (Item f) +QModelIndex FrequencyList_v2_101::impl::add (Item f) { // Any Frequency that isn't in the list may be added if (!frequency_list_.contains (f)) @@ -594,12 +658,15 @@ QModelIndex FrequencyList_v2::impl::add (Item f) frequency_list_.append (f); endInsertRows (); + // if we added one that had a preferred frequency, unprefer everything else + unprefer_all_but(f, row, {Qt::DisplayRole, Qt::CheckStateRole}); + return index (row, 0); } return QModelIndex {}; } -void FrequencyList_v2::impl::add (FrequencyItems items) +void FrequencyList_v2_101::impl::add (FrequencyItems items) { // Any Frequency that isn't in the list may be added for (auto p = items.begin (); p != items.end ();) @@ -624,17 +691,17 @@ void FrequencyList_v2::impl::add (FrequencyItems items) } } -int FrequencyList_v2::impl::rowCount (QModelIndex const& parent) const +int FrequencyList_v2_101::impl::rowCount (QModelIndex const& parent) const { return parent.isValid () ? 0 : frequency_list_.size (); } -int FrequencyList_v2::impl::columnCount (QModelIndex const& parent) const +int FrequencyList_v2_101::impl::columnCount (QModelIndex const& parent) const { return parent.isValid () ? 0 : num_cols; } -Qt::ItemFlags FrequencyList_v2::impl::flags (QModelIndex const& index) const +Qt::ItemFlags FrequencyList_v2_101::impl::flags (QModelIndex const& index) const { auto result = QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; auto row = index.row (); @@ -647,11 +714,16 @@ Qt::ItemFlags FrequencyList_v2::impl::flags (QModelIndex const& index) const { result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; } + + if (preferred_column == column) + { + result |= Qt::ItemIsUserCheckable; + } } return result; } -QVariant FrequencyList_v2::impl::data (QModelIndex const& index, int role) const +QVariant FrequencyList_v2_101::impl::data (QModelIndex const& index, int role) const { QVariant item; @@ -746,8 +818,14 @@ QVariant FrequencyList_v2::impl::data (QModelIndex const& index, int role) const case Qt::DisplayRole: { auto const& band = bands_->find (frequency_item.frequency_); - item = Radio::pretty_frequency_MHz_string (frequency_item.frequency_) - + " MHz (" + (band.isEmpty () ? "OOB" : band) + ')'; + QString desc_text; + desc_text = frequency_item.description_.isEmpty() ? "" : " \u2502 " + frequency_item.description_; + item = (frequency_item.preferred_ ? "\u2055 " : "") + + Radio::pretty_frequency_MHz_string(frequency_item.frequency_) + + " MHz (" + (band.isEmpty() ? "OOB" : band) + ")" + + (((frequency_item.start_time_.isValid() && !frequency_item.start_time_.isNull()) || + (frequency_item.end_time_.isValid() && !frequency_item.end_time_.isNull())) ? " \u2016 " : "") + + desc_text; } break; @@ -760,71 +838,328 @@ QVariant FrequencyList_v2::impl::data (QModelIndex const& index, int role) const item = Qt::AlignRight + Qt::AlignVCenter; break; } + break; + + case description_column: + switch (role) + { + case SortRole: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = frequency_item.description_; + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr("Description"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignLeft + Qt::AlignVCenter; + break; + } + break; + + case source_column: + switch (role) + { + case SortRole: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = frequency_item.source_; + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Source"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignLeft + Qt::AlignVCenter; + break; + } + break; + + case start_time_column: + switch (role) + { + case SortRole: + item = frequency_item.start_time_; + break; + + case Qt::EditRole: + if (frequency_item.start_time_.isNull () || !frequency_item.start_time_.isValid ()) + { + item = QDateTime::currentDateTimeUtc ().toString (Qt::ISODate); + } + else + { + item = frequency_item.start_time_.toString(Qt::ISODate); + } + break; + + case Qt::DisplayRole: + case Qt::AccessibleTextRole: + item = frequency_item.start_time_.toString(Qt::ISODate); + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Start Time"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignLeft + Qt::AlignVCenter; + break; + } + break; + + case end_time_column: + switch (role) + { + case SortRole: + item = frequency_item.end_time_; + break; + + case Qt::EditRole: + if (frequency_item.end_time_.isNull () || !frequency_item.end_time_.isValid ()) + { + item = QDateTime::currentDateTimeUtc ().toString (Qt::ISODate); + } + else + { + item = frequency_item.end_time_.toString(Qt::ISODate); + } + break; + + case Qt::DisplayRole: + case Qt::AccessibleTextRole: + item = frequency_item.end_time_.toString(Qt::ISODate); + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("End Time"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignLeft + Qt::AlignVCenter; + break; + } + break; + + case preferred_column: + switch (role) + { + case SortRole: + item = frequency_item.preferred_; + break; + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + //item = frequency_item.preferred_ ? QString("True") : QString("False"); + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Pref"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignHCenter + Qt::AlignVCenter; + break; + + case Qt::CheckStateRole: + item = frequency_item.preferred_ ? Qt::Checked : Qt::Unchecked; + break; + } break; } } return item; } -bool FrequencyList_v2::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) +void FrequencyList_v2_101::impl::unprefer_all_but(Item &item, int const item_row, QVector roles) +{ + // un-prefer all of the other frequencies in this band + auto const band = bands_->find (item.frequency_); + if (band.isEmpty ()) return; // out of any band + + roles << Qt::CheckStateRole; + roles << Qt::DisplayRole; + + for (int row = 0; row < rowCount (); ++row) + { + if (row == item_row) continue; + + Item &i = frequency_list_[row]; + auto const &iter_band = bands_->find(i.frequency_); + + if (!iter_band.isEmpty() && band == iter_band && (i.region_ == item.region_) && (i.mode_ == item.mode_)) + { + i.preferred_ = false; + Q_EMIT dataChanged(index(row,preferred_column), index(row,preferred_column), roles); + } + } +} + +bool FrequencyList_v2_101::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) { bool changed {false}; - auto const& row = model_index.row (); + auto& item = frequency_list_[row]; + + QVector roles; + roles << role; + + if (model_index.isValid () + && Qt::CheckStateRole == role + && row < frequency_list_.size () + && model_index.column () == preferred_column) + { + bool b_val = ((Qt::CheckState)value.toInt() == Qt::Checked); + if (b_val != item.preferred_) + { + item.preferred_ = b_val; + if (item.preferred_) + { + unprefer_all_but (item, row, roles); // un-prefer all of the other frequencies in this band + } + Q_EMIT dataChanged(index(row,description_column), index(row,preferred_column), roles); + changed = true; + } + } + if (model_index.isValid () && Qt::EditRole == role && row < frequency_list_.size ()) { - QVector roles; - roles << role; - - auto& item = frequency_list_[row]; - switch (model_index.column ()) + switch (model_index.column()) { - case region_column: - { - 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: - { - auto mode = Modes::value (value.toString ()); - if (mode != item.mode_) - { - item.mode_ = mode; - Q_EMIT dataChanged (model_index, model_index, roles); - changed = true; - } - } - break; - - case frequency_column: - if (value.canConvert ()) + case region_column: { - Radio::Frequency frequency {qvariant_cast (value)}; - if (frequency != item.frequency_) + auto region = IARURegions::value(value.toString()); + if (region != item.region_) { - item.frequency_ = frequency; - // mark derived column (1) changed as well - Q_EMIT dataChanged (index (model_index.row (), 1), model_index, roles); + item.region_ = region; + Q_EMIT dataChanged(model_index, model_index, roles); changed = true; } } break; + + case mode_column: + { + auto mode = Modes::value(value.toString()); + if (mode != item.mode_) + { + item.mode_ = mode; + Q_EMIT dataChanged(model_index, model_index, roles); + changed = true; + } + } + break; + + case frequency_column: + { + if (value.canConvert()) + { + Radio::Frequency frequency{qvariant_cast(value)}; + if (frequency != item.frequency_) + { + item.frequency_ = frequency; + // mark derived column (1) changed as well + Q_EMIT dataChanged(index(model_index.row(), 1), model_index, roles); + changed = true; + } + } + } + break; + + case description_column: + { + if (value.toString() != item.description_) + { + item.description_ = value.toString(); + Q_EMIT dataChanged(model_index, model_index, roles); + changed = true; + } + } + break; + + case source_column: + { + if (value.toString() != item.source_) + { + item.source_ = value.toString(); + Q_EMIT dataChanged(model_index, model_index, roles); + changed = true; + } + } + break; + + case start_time_column: + { + QDateTime start_time = QDateTime::fromString(value.toString(), Qt::ISODate); + LOG_INFO(QString{"start_time = %1 - isEmpty %2"}.arg(value.toString()).arg(value.toString().isEmpty())); + if (value.toString().isEmpty()) + { // empty string is valid + start_time = QDateTime(); + } + if (start_time.isValid() || start_time.isNull()) + { + item.start_time_ = start_time; + if (item.end_time_.isValid() && !item.start_time_.isNull() && item.end_time_ < item.start_time_) + { + item.end_time_ = item.start_time_; + } + Q_EMIT dataChanged(model_index, index(model_index.row(), end_time_column), roles); + changed = true; + } + } + break; + + case end_time_column: + { + QDateTime end_time = QDateTime::fromString(value.toString(), Qt::ISODate); + if (value.toString().isEmpty()) + { // empty string is valid + end_time = QDateTime(); + } + if (end_time.isValid() || end_time.isNull()) + { + item.end_time_ = end_time; + if (item.start_time_.isValid() && !item.end_time_.isNull() && end_time <= item.start_time_) + { + item.start_time_ = end_time; + } + Q_EMIT dataChanged(index(model_index.row(), start_time_column), model_index, roles); + changed = true; + } + } + break; + + case preferred_column: + { + bool b_value = value.toBool(); + if (b_value != item.preferred_) + { + item.preferred_ = b_value; + Q_EMIT dataChanged(index(model_index.row(), start_time_column), model_index, roles); + changed = true; + } + } + break; + } } return changed; } -QVariant FrequencyList_v2::impl::headerData (int section, Qt::Orientation orientation, int role) const +QVariant FrequencyList_v2_101::impl::headerData (int section, Qt::Orientation orientation, int role) const { QVariant header; if (Qt::DisplayRole == role @@ -833,10 +1168,15 @@ QVariant FrequencyList_v2::impl::headerData (int section, Qt::Orientation orient { switch (section) { - case region_column: header = tr ("IARU Region"); break; - case mode_column: header = tr ("Mode"); break; - case frequency_column: header = tr ("Frequency"); break; - case frequency_mhz_column: header = tr ("Frequency (MHz)"); break; + case region_column: header = tr ("IARU Region"); break; + case mode_column: header = tr ("Mode"); break; + case frequency_column: header = tr ("Frequency"); break; + case frequency_mhz_column: header = tr ("Frequency (MHz)"); break; + case source_column: header = tr ("Source"); break; + case start_time_column: header = tr ("Start Date/Time"); break; + case end_time_column: header = tr ("End Date/Time"); break; + case preferred_column: header = tr ("Pref"); break; + case description_column: header = tr ("Description"); break; } } else @@ -846,7 +1186,7 @@ QVariant FrequencyList_v2::impl::headerData (int section, Qt::Orientation orient return header; } -bool FrequencyList_v2::impl::removeRows (int row, int count, QModelIndex const& parent) +bool FrequencyList_v2_101::impl::removeRows (int row, int count, QModelIndex const& parent) { if (0 < count && (row + count) <= rowCount (parent)) { @@ -861,14 +1201,14 @@ bool FrequencyList_v2::impl::removeRows (int row, int count, QModelIndex const& return false; } -bool FrequencyList_v2::impl::insertRows (int row, int count, QModelIndex const& parent) +bool FrequencyList_v2_101::impl::insertRows (int row, int count, QModelIndex const& parent) { if (0 < count) { beginInsertRows (parent, row, row + count - 1); for (auto r = 0; r < count; ++r) { - frequency_list_.insert (row, Item {0, Mode::ALL, IARURegions::ALL}); + frequency_list_.insert (row, Item {0, Mode::ALL, IARURegions::ALL, QString(), QString(), QDateTime(), QDateTime(), false}); } endInsertRows (); return true; @@ -876,14 +1216,14 @@ bool FrequencyList_v2::impl::insertRows (int row, int count, QModelIndex const& return false; } -QStringList FrequencyList_v2::impl::mimeTypes () const +QStringList FrequencyList_v2_101::impl::mimeTypes () const { QStringList types; types << mime_type; return types; } -QMimeData * FrequencyList_v2::impl::mimeData (QModelIndexList const& items) const +QMimeData * FrequencyList_v2_101::impl::mimeData (QModelIndexList const& items) const { QMimeData * mime_data = new QMimeData {}; QByteArray encoded_data; @@ -901,43 +1241,43 @@ QMimeData * FrequencyList_v2::impl::mimeData (QModelIndexList const& items) cons return mime_data; } -auto FrequencyList_v2::const_iterator::operator * () const -> Item const& +auto FrequencyList_v2_101::const_iterator::operator * () const -> Item const& { return parent_->frequency_list ().at(parent_->mapToSource (parent_->index (row_, 0)).row ()); } -auto FrequencyList_v2::const_iterator::operator -> () const -> Item const * +auto FrequencyList_v2_101::const_iterator::operator -> () const -> Item const * { return &parent_->frequency_list ().at(parent_->mapToSource (parent_->index (row_, 0)).row ()); } -bool FrequencyList_v2::const_iterator::operator != (const_iterator const& rhs) const +bool FrequencyList_v2_101::const_iterator::operator != (const_iterator const& rhs) const { return parent_ != rhs.parent_ || row_ != rhs.row_; } -bool FrequencyList_v2::const_iterator::operator == (const_iterator const& rhs) const +bool FrequencyList_v2_101::const_iterator::operator == (const_iterator const& rhs) const { return parent_ == rhs.parent_ && row_ == rhs.row_; } -auto FrequencyList_v2::const_iterator::operator ++ () -> const_iterator& +auto FrequencyList_v2_101::const_iterator::operator ++ () -> const_iterator& { ++row_; return *this; } -auto FrequencyList_v2::begin () const -> const_iterator +auto FrequencyList_v2_101::begin () const -> const_iterator { return const_iterator (this, 0); } -auto FrequencyList_v2::end () const -> const_iterator +auto FrequencyList_v2_101::end () const -> const_iterator { return const_iterator (this, rowCount ()); } -auto FrequencyList_v2::find (Frequency f) const -> const_iterator +auto FrequencyList_v2_101::find (Frequency f) const -> const_iterator { int row {0}; for (; row < rowCount (); ++row) @@ -950,7 +1290,7 @@ auto FrequencyList_v2::find (Frequency f) const -> const_iterator return const_iterator (this, row); } -auto FrequencyList_v2::filtered_bands () const -> BandSet +auto FrequencyList_v2_101::filtered_bands () const -> BandSet { BandSet result; for (auto const& item : *this) @@ -960,7 +1300,7 @@ auto FrequencyList_v2::filtered_bands () const -> BandSet return result; } -auto FrequencyList_v2::all_bands (Region region, Mode mode) const -> BandSet +auto FrequencyList_v2_101::all_bands (Region region, Mode mode) const -> BandSet { BandSet result; for (auto const& item : m_->frequency_list_) @@ -977,6 +1317,93 @@ auto FrequencyList_v2::all_bands (Region region, Mode mode) const -> BandSet return result; } +FrequencyList_v2_101::FrequencyItems FrequencyList_v2_101::from_json_file(QFile *input_file) +{ + FrequencyList_v2_101::FrequencyItems list; + QJsonDocument doc = QJsonDocument::fromJson(input_file->readAll()); + if (doc.isNull()) + { + throw ReadFileException {tr ("Failed to parse JSON file")}; + } + QJsonObject obj = doc.object(); + if (obj.isEmpty()) + { + throw ReadFileException{tr("Information Missing")}; + } + QJsonArray arr = obj["frequencies"].toArray(); + if (arr.isEmpty()) + { + throw ReadFileException{tr ("No Frequencies were found")}; + } + int valid_entry_count = 0; + int skipped_entry_count = 0; + for (auto const &item: arr) + { + QString mode_s, region_s; + QJsonObject obj = item.toObject(); + FrequencyList_v2_101::Item freq; + region_s = obj["region"].toString(); + mode_s = obj["mode"].toString(); + + freq.frequency_ = obj["frequency"].toString().toDouble() * 1e6; + freq.region_ = IARURegions::value(region_s); + freq.mode_ = Modes::value(mode_s); + freq.description_ = obj["description"].toString(); + freq.source_ = obj["source"].toString(); + freq.start_time_ = QDateTime::fromString(obj["start_time"].toString(), Qt::ISODate); + freq.end_time_ = QDateTime::fromString(obj["end_time"].toString(), Qt::ISODate); + freq.preferred_ = obj["preferred"].toBool(); + + if ((freq.mode_ != Modes::ALL || QString::compare("ALL", mode_s)) && + (freq.region_ != IARURegions::ALL || QString::compare("ALL", region_s, Qt::CaseInsensitive)) && + freq.isSane()) + { + list.push_back(freq); + valid_entry_count++; + } else + skipped_entry_count++; + } + //MessageBox::information_message(this, tr("Loaded Frequencies from %1").arg(file_name), + // tr("Entries Valid/Skipped %1").arg(QString::number(valid_entry_count) + "/" + + // QString::number(skipped_entry_count))); + return list; +} +// write JSON format to a file +void FrequencyList_v2_101::to_json_file(QFile *output_file, QString magic_s, QString version_s, + FrequencyItems const &frequency_items) +{ + QJsonObject jobject{ + {"wsjtx_file", "qrg"}, + {"wsjtx_version", QCoreApplication::applicationVersion()+" "+revision()}, + {"generated_at", QDateTime::currentDateTimeUtc ().toString (Qt::ISODate)}, + {"wsjtx_filetype", magic_s}, + {"qrg_version", version_s}, + {"frequency_count", frequency_items.count()}}; + + QJsonArray array; + for (auto &item: frequency_items) + array.append(item.toJson()); + jobject["frequencies"] = array; + + QJsonDocument d = QJsonDocument(jobject); + output_file->write(d.toJson()); +} + +// previous version 100 of the FrequencyList_v2 class +QDataStream& operator >> (QDataStream& is, FrequencyList_v2::Item& item) +{ + return is >> item.frequency_ + >> item.mode_ + >> item.region_; +} + +QDataStream& operator << (QDataStream& os, FrequencyList_v2::Item const& item) +{ + return os << item.frequency_ + << item.mode_ + << item.region_; +} + // // Obsolete version of FrequencyList no longer used but needed to // allow loading and saving of old settings contents without damage diff --git a/models/FrequencyList.hpp b/models/FrequencyList.hpp index a3b9c117a..04b51a863 100644 --- a/models/FrequencyList.hpp +++ b/models/FrequencyList.hpp @@ -5,6 +5,11 @@ #include #include +#include +#include +#include +#include +#include #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; using BandSet = QSet; - 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; + +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 diff --git a/models/StationList.cpp b/models/StationList.cpp index ff8d153f0..2b5012597 100644 --- a/models/StationList.cpp +++ b/models/StationList.cpp @@ -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 () diff --git a/translations/wsjtx_ca.ts b/translations/wsjtx_ca.ts index 287a45a87..db7c4fe94 100644 --- a/translations/wsjtx_ca.ts +++ b/translations/wsjtx_ca.ts @@ -1477,7 +1477,7 @@ Error: %2 - %3 - FrequencyList_v2 + FrequencyList_v2_100 diff --git a/translations/wsjtx_es.ts b/translations/wsjtx_es.ts index 3a750b2cf..e2cc8caf7 100644 --- a/translations/wsjtx_es.ts +++ b/translations/wsjtx_es.ts @@ -1630,7 +1630,7 @@ Error: %2 - %3 - FrequencyList_v2 + FrequencyList_v2_100 diff --git a/translations/wsjtx_zh_HK.ts b/translations/wsjtx_zh_HK.ts index fc16afbdc..86f599a31 100644 --- a/translations/wsjtx_zh_HK.ts +++ b/translations/wsjtx_zh_HK.ts @@ -1475,7 +1475,7 @@ Error: %2 - %3 - FrequencyList_v2 + FrequencyList_v2_100 diff --git a/translations/wsjtx_zh_TW.ts b/translations/wsjtx_zh_TW.ts index 15c9131de..a4b23d7d3 100644 --- a/translations/wsjtx_zh_TW.ts +++ b/translations/wsjtx_zh_TW.ts @@ -1475,7 +1475,7 @@ Error: %2 - %3 - FrequencyList_v2 + FrequencyList_v2_100 diff --git a/validators/LiveFrequencyValidator.cpp b/validators/LiveFrequencyValidator.cpp index 873224920..70c992a9d 100644 --- a/validators/LiveFrequencyValidator.cpp +++ b/validators/LiveFrequencyValidator.cpp @@ -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 { diff --git a/validators/LiveFrequencyValidator.hpp b/validators/LiveFrequencyValidator.hpp index 823f8f745..4224d89a4 100644 --- a/validators/LiveFrequencyValidator.hpp +++ b/validators/LiveFrequencyValidator.hpp @@ -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_; }; diff --git a/widgets/BandComboBox.cpp b/widgets/BandComboBox.cpp index 0dc8eba61..7dfb77e08 100644 --- a/widgets/BandComboBox.cpp +++ b/widgets/BandComboBox.cpp @@ -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 diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index c9928cb99..dc91b9953 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -769,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 @@ -1021,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); @@ -1065,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 ()) @@ -7208,7 +7218,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) { @@ -7453,7 +7463,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 ()) { @@ -7481,7 +7491,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 ()) { @@ -7496,7 +7506,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) { diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 80fbce9e5..a2558fe81 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -477,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; @@ -824,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 *);