From e575005291b3ac779dd37b8e510a5464609a88a3 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Sun, 19 Jun 2022 11:04:49 +0200 Subject: [PATCH 01/28] Fix a compatibility issue. --- revision_utils.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/revision_utils.cpp b/revision_utils.cpp index 6b6ac1c82..d78e09fc9 100644 --- a/revision_utils.cpp +++ b/revision_utils.cpp @@ -80,6 +80,5 @@ QString version (bool include_patch) QString program_title (QString const& revision) { QString id {QCoreApplication::applicationName () + " v" + QCoreApplication::applicationVersion ()}; -// return id + " " + revision + " by K1JT, G4WJS, K9AN, and IV3NWV"; - return id + " " + revision; + return id + " " + revision + " by K1JT et al."; } From 219c04f5a4cb68364c16a2705c8d6d056bfe2aa9 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Sun, 19 Jun 2022 16:37:56 +0200 Subject: [PATCH 02/28] Optimize mode button layout for 4K screens. --- widgets/mainwindow.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index b52ac578a..c68dc971a 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -750,7 +750,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, // ensure a balanced layout of the mode buttons qreal pointSize = m_config.text_font().pointSizeF(); - if (pointSize < 12) { + if (pointSize < 11) { ui->houndButton->setMaximumWidth(40); ui->ft8Button->setMaximumWidth(40); ui->ft4Button->setMaximumWidth(40); @@ -758,12 +758,12 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->q65Button->setMaximumWidth(40); ui->jt65Button->setMaximumWidth(40); } else { - ui->houndButton->setMinimumWidth(0); - ui->ft8Button->setMinimumWidth(0); - ui->ft4Button->setMinimumWidth(0); - ui->msk144Button->setMinimumWidth(0); - ui->q65Button->setMinimumWidth(0); - ui->jt65Button->setMinimumWidth(0); + ui->houndButton->setMinimumWidth(50); + ui->ft8Button->setMinimumWidth(50); + ui->ft4Button->setMinimumWidth(50); + ui->msk144Button->setMinimumWidth(50); + ui->q65Button->setMinimumWidth(50); + ui->jt65Button->setMinimumWidth(50); } // hook up save WAV file exit handling From 345e53907426480b2122263f8d63a08b08088408 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 21 Jun 2022 14:27:06 -0400 Subject: [PATCH 03/28] Use "(Call_1 or CQ)" in Table 2, Section 12.1 of User Guide. --- doc/user_guide/en/decoder_notes.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_guide/en/decoder_notes.adoc b/doc/user_guide/en/decoder_notes.adoc index cbdf89fab..4bcedd490 100644 --- a/doc/user_guide/en/decoder_notes.adoc +++ b/doc/user_guide/en/decoder_notes.adoc @@ -38,7 +38,7 @@ uses information from the previous Rx sequence. |a4|MyCall DxCall RRR |a5|MyCall DxCall 73 |a6|MyCall DxCall RR73 -|a7|Call_1 Call_2     ? +|a7|(Call_1 or CQ) Call_2     ? |=== If a codeword is found that is judged to have high (but not From 0ef914fb5cccb2b70ba6c6301719e1972d409a0f Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 22 Jun 2022 14:34:50 -0400 Subject: [PATCH 04/28] Let Echo-mode "Measure" function use the computed fspread for DX grid. --- lib/astro0.f90 | 6 ++++-- lib/avecho.f90 | 10 ++++++---- widgets/mainwindow.cpp | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/astro0.f90 b/lib/astro0.f90 index 0ffe4d611..e59b7effc 100644 --- a/lib/astro0.f90 +++ b/lib/astro0.f90 @@ -11,7 +11,7 @@ subroutine astro0(nyear,month,nday,uth8,freq8,mygrid,hisgrid, & real*8 uth8,techo8,freq8 real*8 xl,b common/librcom/xl(2),b(2) - common/echocom2/echo_spread + common/echocom2/fspread_self,fspread_dx data uth8z/0.d0/ save @@ -43,9 +43,11 @@ subroutine astro0(nyear,month,nday,uth8,freq8,mygrid,hisgrid, & dbdt2=DEGS*(b2a-b2) rate1=2.0*sqrt(dldt1**2 + dbdt1**2) width1=0.5*6741*fghz*rate1 - echo_spread=width1 !Save echo_spread for avecho() rate2=sqrt((dldt1+dldt2)**2 + (dbdt1+dbdt2)**2) width2=0.5*6741*fghz*rate2 + if(hisgrid(1:4).eq.' ') width2=width1 !No hisgrid, use self width + fspread_self=width1 !Save for avecho() + fspread_dx=width2 !Save for avecho() AzSun8=AzSun ElSun8=ElSun diff --git a/lib/avecho.f90 b/lib/avecho.f90 index aa56e66d9..04b80df65 100644 --- a/lib/avecho.f90 +++ b/lib/avecho.f90 @@ -1,4 +1,5 @@ -subroutine avecho(id2,ndop,nfrit,nqual,f1,xlevel,snrdb,db_err,dfreq,width) +subroutine avecho(id2,ndop,nfrit,nauto,nqual,f1,xlevel,snrdb,db_err, & + dfreq,width) integer TXLENGTH parameter (TXLENGTH=27648) !27*1024 @@ -17,18 +18,19 @@ subroutine avecho(id2,ndop,nfrit,nqual,f1,xlevel,snrdb,db_err,dfreq,width) complex c(0:NH) equivalence (x,c),(ipk,ipkv) common/echocom/nclearave,nsum,blue(NZ),red(NZ) - common/echocom2/echo_spread + common/echocom2/fspread_self,fspread_dx save dop0,sa,sb - fspread=echo_spread !### Use the predicted Doppler spread ### + fspread=fspread_dx !### Use the predicted Doppler spread ### + if(nauto.eq.1) fspread=fspread_self inquire(file='fspread.txt',exist=ex) if(ex) then open(39,file='fspread.txt',status='old') read(39,*) fspread close(39) endif + fspread=min(max(0.1,fspread),700.0) width=fspread - dop=ndop sq=0. do i=1,TXLENGTH diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index c68dc971a..67bf1e9ba 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -153,7 +153,7 @@ extern "C" { int savec2_(char const * fname, int* TR_seconds, double* dial_freq, fortran_charlen_t); - void avecho_( short id2[], int* dop, int* nfrit, int* nqual, float* f1, + void avecho_( short id2[], int* dop, int* nfrit, int* nauto, int* nqual, float* f1, float* level, float* sigdb, float* snr, float* dfreq, float* width); @@ -1576,6 +1576,8 @@ void MainWindow::dataSink(qint64 frames) if(m_mode=="Echo") { float dBerr=0.0; int nfrit=0; + int nauto=0; + if(m_auto) nauto=1; int nqual=0; float f1=1500.0; float xlevel=0.0; @@ -1584,7 +1586,7 @@ void MainWindow::dataSink(qint64 frames) float width=0.0; echocom_.nclearave=m_nclearave; int nDop=0; - avecho_(dec_data.d2,&nDop,&nfrit,&nqual,&f1,&xlevel,&sigdb, + avecho_(dec_data.d2,&nDop,&nfrit,&nauto,&nqual,&f1,&xlevel,&sigdb, &dBerr,&dfreq,&width); QString t; t = t.asprintf("%3d %7.1f %7.1f %7.1f %7.1f %7.1f %3d",echocom_.nsum,xlevel,sigdb, @@ -7090,7 +7092,7 @@ void MainWindow::WSPR_config(bool b) ui->rh_decodes_widget->setVisible(!b); ui->controls_stack_widget->setCurrentIndex (b && m_mode != "Echo" ? 1 : 0); ui->QSO_controls_widget->setVisible (!b); - ui->DX_controls_widget->setVisible (!b); + ui->DX_controls_widget->setVisible (true); ui->WSPR_controls_widget->setVisible (b); ui->lh_decodes_title_label->setVisible(!b and ui->cbMenus->isChecked()); ui->logQSOButton->setVisible(!b); From 951d17b20c6effa88c620ebdb690f69523940c5d Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 23 Jun 2022 09:20:52 -0400 Subject: [PATCH 05/28] Correct the if statement controlling display of DX station fields. --- widgets/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 67bf1e9ba..97717a7da 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -7092,7 +7092,7 @@ void MainWindow::WSPR_config(bool b) ui->rh_decodes_widget->setVisible(!b); ui->controls_stack_widget->setCurrentIndex (b && m_mode != "Echo" ? 1 : 0); ui->QSO_controls_widget->setVisible (!b); - ui->DX_controls_widget->setVisible (true); + ui->DX_controls_widget->setVisible (!b or (m_mode=="Echo")); ui->WSPR_controls_widget->setVisible (b); ui->lh_decodes_title_label->setVisible(!b and ui->cbMenus->isChecked()); ui->logQSOButton->setVisible(!b); From 3caaf785bdc7af62490e78717c6b7dc7843abd0c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 23 Jun 2022 09:51:30 -0400 Subject: [PATCH 06/28] Change version number to 2.6.0-rc2. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 658820145..ffe482eb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ message (STATUS "******************************************************") include (set_build_type) # RC 0 or omitted is a development build, GA is a General Availability release build -set_build_type (RC 1) +set_build_type (RC 2) set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}") # From bc635f0cd7457dd3704813f150b3c80e1e9c4e6f Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 1 Jul 2022 11:56:22 -0400 Subject: [PATCH 07/28] Make OK button the default on the LogQSO dialog window. --- widgets/logqso.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/widgets/logqso.cpp b/widgets/logqso.cpp index f49274494..e87a88520 100644 --- a/widgets/logqso.cpp +++ b/widgets/logqso.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "logbook/logbook.h" #include "MessageBox.hpp" @@ -109,6 +110,15 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd) { if(!isHidden()) return; + + QPushButton* okBtn = ui->buttonBox->button(QDialogButtonBox::Ok); + okBtn->setAutoDefault(true); + okBtn->setDefault(true); + okBtn->setFocus(); + QPushButton* caBtn = ui->buttonBox->button(QDialogButtonBox::Cancel); + caBtn->setAutoDefault(false); + caBtn->setDefault(false); + ui->call->setText (hisCall); ui->grid->setText (hisGrid); ui->name->clear (); From 9adb1c8256d98e7cf861f79954ba8d772d91c168 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 1 Jul 2022 12:04:22 -0400 Subject: [PATCH 08/28] Minor edits to display of Keyboard Shortcuts. --- widgets/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 97717a7da..7d103f92c 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3021,10 +3021,10 @@ void MainWindow::on_actionKeyboard_shortcuts_triggered() Alt+H Halt Tx Ctrl+L Lookup callsign in database, generate standard messages Alt+M Monitor - Alt+N Enable Tx + Alt+N Toggle "Enable Tx" Ctrl+O Open a .wav file Alt+O Change operator - Alt+Q Log QSO + Alt+Q Open "Log QSO" window Ctrl+R Set Tx4 message to RRR (not in FT4) Alt+R Set Tx4 message to RR73 Alt+S Stop monitoring From c97c53db8913dac9ede3fcd04087588eb425e358 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Mon, 4 Jul 2022 19:53:03 +0200 Subject: [PATCH 09/28] Fix VFOB not getting set on some rigs (e.g. IC7610 & IC7100). --- Transceiver/HamlibTransceiver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Transceiver/HamlibTransceiver.cpp b/Transceiver/HamlibTransceiver.cpp index a0670c0f2..eb69bbae8 100644 --- a/Transceiver/HamlibTransceiver.cpp +++ b/Transceiver/HamlibTransceiver.cpp @@ -911,6 +911,7 @@ void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore) // to frequency such as the TS-2000 auto mode setting CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode)); m_->error_check (rig_set_mode (m_->rig_.data (), target_vfo, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode")); + rig_set_mode (m_->rig_.data (), RIG_VFO_B, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting VFOB mode"); } update_mode (m); } From 599cf1b7d6d2ca1bd484e4b69a28d312a82fce51 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Tue, 5 Jul 2022 10:55:00 +0200 Subject: [PATCH 10/28] Remember settings for T/R period and Submode by mode. --- widgets/mainwindow.cpp | 59 ++++++++++++++++++++++++++++++++---------- widgets/mainwindow.h | 3 +++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 7d103f92c..482d9c50f 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -294,6 +294,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_secID {0}, m_idleMinutes {0}, m_nSubMode {0}, + m_nSubMode_Q65 {0}, + m_nSubMode_JT65 {0}, + m_nSubMode_JT4 {0}, m_nclearave {1}, m_nWSPRdecodes {0}, m_k0 {9999999}, @@ -1171,7 +1174,7 @@ void MainWindow::writeSettings() m_settings->setValue("FST4W_FTol",ui->sbFST4W_FTol->value()); m_settings->setValue("FST4_FLow",ui->sbF_Low->value()); m_settings->setValue("FST4_FHigh",ui->sbF_High->value()); - m_settings->setValue("SubMode",ui->sbSubmode->value()); +// m_settings->setValue("SubMode",ui->sbSubmode->value()); m_settings->setValue("DTtol",m_DTtol); m_settings->setValue("Ftol", ui->sbFtol->value ()); m_settings->setValue("MinSync",m_minSync); @@ -1193,7 +1196,7 @@ void MainWindow::writeSettings() m_settings->setValue("UploadSpots",m_uploadWSPRSpots); m_settings->setValue("NoOwnCall",ui->cbNoOwnCall->isChecked()); m_settings->setValue ("BandHopping", ui->band_hopping_group_box->isChecked ()); - m_settings->setValue ("TRPeriod", ui->sbTR->value ()); +// m_settings->setValue ("TRPeriod", ui->sbTR->value ()); m_settings->setValue ("MaxDrift", ui->sbMaxDrift->value()); m_settings->setValue ("TRPeriod_FST4W", ui->sbTR_FST4W->value ()); m_settings->setValue("FastMode",m_bFastMode); @@ -1277,8 +1280,14 @@ void MainWindow::readSettings() ui->sbFST4W_RxFreq->setValue(m_settings->value("FST4W_RxFreq",1500).toInt()); ui->sbF_Low->setValue(m_settings->value("FST4_FLow",600).toInt()); ui->sbF_High->setValue(m_settings->value("FST4_FHigh",1400).toInt()); - m_nSubMode=m_settings->value("SubMode",0).toInt(); - ui->sbSubmode->setValue(m_nSubMode); +// m_nSubMode=m_settings->value("SubMode",0).toInt(); + if (m_mode=="Q65") m_nSubMode=m_settings->value("SubMode_Q65",0).toInt(); + if (m_mode=="JT65") m_nSubMode=m_settings->value("SubMode_JT65",0).toInt(); + if (m_mode=="JT4") m_nSubMode=m_settings->value("SubMode_JT4",0).toInt(); +// ui->sbSubmode->setValue(m_nSubMode); + if (m_mode=="Q65") ui->sbSubmode->setValue(m_nSubMode_Q65); + if (m_mode=="JT65") ui->sbSubmode->setValue(m_nSubMode_JT65); + if (m_mode=="JT4") ui->sbSubmode->setValue(m_nSubMode_JT4); ui->sbFtol->setValue (m_settings->value("Ftol", 50).toInt()); ui->sbFST4W_FTol->setValue(m_settings->value("FST4W_FTol",100).toInt()); m_minSync=m_settings->value("MinSync",0).toInt(); @@ -1289,7 +1298,10 @@ void MainWindow::readSettings() m_bSWL=m_settings->value("SWL",false).toBool(); m_bFast9=m_settings->value("Fast9",false).toBool(); m_bFastMode=m_settings->value("FastMode",false).toBool(); - ui->sbTR->setValue (m_settings->value ("TRPeriod", 15).toInt()); +// ui->sbTR->setValue (m_settings->value ("TRPeriod", 15).toInt()); + if (m_mode=="Q65") ui->sbTR->setValue (m_settings->value ("TRPeriod_Q65", 30).toInt()); + if (m_mode=="MSK144") ui->sbTR->setValue (m_settings->value ("TRPeriod_MSK144", 15).toInt()); + if (m_mode=="FST4") ui->sbTR->setValue (m_settings->value ("TRPeriod_FST4", 60).toInt()); ui->sbMaxDrift->setValue (m_settings->value ("MaxDrift",0).toInt()); ui->sbTR_FST4W->setValue (m_settings->value ("TRPeriod_FST4W", 15).toInt()); m_lastMonitoredFrequency = m_settings->value ("DialFreq", @@ -6502,7 +6514,8 @@ void MainWindow::on_actionFST4_triggered() switch_mode (Modes::FST4); m_wideGraph->setMode(m_mode); ui->sbTR->values ({15, 30, 60, 120, 300, 900, 1800}); - on_sbTR_valueChanged (ui->sbTR->value()); + ui->sbTR->setValue (m_settings->value ("TRPeriod_FST4", 60).toInt()); // remember sbTR settings by mode + QTimer::singleShot (50, [=] {on_sbTR_valueChanged (ui->sbTR->value());}); statusChanged(); m_bOK_to_chk=true; chk_FST4_freq_range(); @@ -6722,7 +6735,9 @@ void MainWindow::on_actionJT4_triggered() ui->lh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); ui->rh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); if(bVHF) { - ui->sbSubmode->setValue(m_nSubMode); +// ui->sbSubmode->setValue(m_nSubMode); + m_nSubMode=m_settings->value("SubMode_JT4",0).toInt(); + QTimer::singleShot (50, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_JT4",0).toInt());}); } else { ui->sbSubmode->setValue(0); } @@ -6823,8 +6838,10 @@ void MainWindow::on_actionJT65_triggered() m_bFast9=false; ui->sbSubmode->setMaximum(2); if(bVHF) { - ui->sbSubmode->setValue(m_nSubMode); - ui->lh_decodes_title_label->setText(tr ("Single-Period Decodes")); +// ui->sbSubmode->setValue(m_nSubMode); + m_nSubMode=m_settings->value("SubMode_JT65",0).toInt(); + QTimer::singleShot (50, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_JT65",0).toInt());}); + ui->lh_decodes_title_label->setText(tr ("Single-Period Decodes")); ui->rh_decodes_title_label->setText(tr ("Average Decodes")); } else { ui->sbSubmode->setValue(0); @@ -6859,8 +6876,11 @@ void MainWindow::on_actionQ65_triggered() Q_EMIT FFTSize(m_FFTSize); m_hsymStop=49; ui->sbTR->values ({15, 30, 60, 120, 300}); - on_sbTR_valueChanged (ui->sbTR->value()); - ui->sbSubmode->setValue(m_nSubMode); + ui->sbTR->setValue (m_settings->value ("TRPeriod_Q65", 30).toInt()); // remember sbTR settings by mode + QTimer::singleShot (50, [=] {on_sbTR_valueChanged (ui->sbTR->value());}); +// ui->sbSubmode->setValue(m_nSubMode); + m_nSubMode=m_settings->value("SubMode_Q65",0).toInt(); + QTimer::singleShot (50, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_Q65",0).toInt());}); QString fname {QDir::toNativeSeparators(m_config.temp_dir().absoluteFilePath ("red.dat"))}; m_wideGraph->setRedFile(fname); m_wideGraph->setMode(m_mode); @@ -6930,7 +6950,8 @@ void MainWindow::on_actionMSK144_triggered() m_bFastMode=true; m_bFast9=false; ui->sbTR->values ({5, 10, 15, 30}); - on_sbTR_valueChanged (ui->sbTR->value()); + ui->sbTR->setValue (m_settings->value ("TRPeriod_MSK144", 15).toInt()); // remember sbTR settings by mode + QTimer::singleShot (50, [=] {on_sbTR_valueChanged (ui->sbTR->value());}); m_wideGraph->hide(); m_fastGraph->showNormal(); ui->TxFreqSpinBox->setValue(1500); @@ -8048,7 +8069,16 @@ void MainWindow::on_sbTR_valueChanged(int value) m_wideGraph->setPeriod (value, m_nsps); progressBar.setMaximum (value); } - if(m_mode=="FST4") chk_FST4_freq_range(); + if (m_mode=="Q65") { + QTimer::singleShot (200, [=] {m_settings->setValue ("TRPeriod_Q65", ui->sbTR->value ());}); + } + if (m_mode=="MSK144") { + QTimer::singleShot (200, [=] {m_settings->setValue ("TRPeriod_MSK144", ui->sbTR->value ());}); + } + if (m_mode=="FST4") { + chk_FST4_freq_range(); + QTimer::singleShot (200, [=] {m_settings->setValue ("TRPeriod_FST4", ui->sbTR->value ());}); + } // if(m_transmitting) on_stopTxButton_clicked(); //### Is this needed or desirable? ### on_sbSubmode_valueChanged(ui->sbSubmode->value()); statusUpdate (); @@ -8104,6 +8134,9 @@ void MainWindow::on_sbSubmode_valueChanged(int n) if(m_bFast9) ui->TxFreqSpinBox->setValue(700); } if(m_transmitting and m_bFast9 and m_nSubMode>=4) transmit (99.0); + if (m_mode=="Q65") {QTimer::singleShot (200, [=] {m_settings->setValue("SubMode_Q65",ui->sbSubmode->value());});} + if (m_mode=="JT65") {QTimer::singleShot (200, [=] {m_settings->setValue("SubMode_JT65",ui->sbSubmode->value());});} + if (m_mode=="JT4") {QTimer::singleShot (200, [=] {m_settings->setValue("SubMode_JT4",ui->sbSubmode->value());});} statusUpdate (); } diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 9784cc621..01c142e88 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -461,6 +461,9 @@ private: qint32 m_secID; qint32 m_idleMinutes; qint32 m_nSubMode; + qint32 m_nSubMode_Q65; + qint32 m_nSubMode_JT65; + qint32 m_nSubMode_JT4; qint32 m_nclearave; qint32 m_minSync; qint32 m_dBm; From 8b767b4c75217eb6007c09c594bda823c1e22e1a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 5 Jul 2022 14:01:22 -0400 Subject: [PATCH 11/28] Satisfy the fussy compiler on macOS. --- lib/grid2deg.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/grid2deg.f90 b/lib/grid2deg.f90 index 843fc8480..a7ec1c89c 100644 --- a/lib/grid2deg.f90 +++ b/lib/grid2deg.f90 @@ -3,7 +3,8 @@ subroutine grid2deg(grid0,dlong,dlat) ! Converts Maidenhead grid locator to degrees of West longitude ! and North latitude. - character*6 grid0,grid + character*(*) grid0 + character*6 grid character*1 g1,g2,g3,g4,g5,g6 grid=grid0 From f84ba8a0d0e0f7122cb51e6bdeac98938014cd21 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Thu, 7 Jul 2022 18:11:29 +0200 Subject: [PATCH 12/28] Make submode switching more robust, and fix a long-standing bug where the Tx audio frequency spin box remained red when coming from some Q65 submodes. --- widgets/mainwindow.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 482d9c50f..858fe00b8 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6480,7 +6480,7 @@ void MainWindow::displayWidgets(qint64 n) void MainWindow::on_actionFST4_triggered() { - m_mode="FST4"; + QTimer::singleShot (50, [=] {on_sbSubmode_valueChanged(ui->sbSubmode->value());}); m_mode="FST4"; ui->actionFST4->setChecked(true); m_bFast9=false; @@ -6553,6 +6553,7 @@ void MainWindow::on_actionFST4W_triggered() void MainWindow::on_actionFT4_triggered() { + QTimer::singleShot (50, [=] {on_sbSubmode_valueChanged(ui->sbSubmode->value());}); m_mode="FT4"; m_TRperiod=7.5; bool bVHF=m_config.enable_VHF_features(); @@ -6596,6 +6597,7 @@ void MainWindow::on_actionFT4_triggered() void MainWindow::on_actionFT8_triggered() { + QTimer::singleShot (50, [=] {on_sbSubmode_valueChanged(ui->sbSubmode->value());}); m_mode="FT8"; bool bVHF=m_config.enable_VHF_features(); m_bFast9=false; @@ -6736,8 +6738,9 @@ void MainWindow::on_actionJT4_triggered() ui->rh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); if(bVHF) { // ui->sbSubmode->setValue(m_nSubMode); - m_nSubMode=m_settings->value("SubMode_JT4",0).toInt(); - QTimer::singleShot (50, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_JT4",0).toInt());}); + QTimer::singleShot (50, [=] {m_nSubMode=m_settings->value("SubMode_JT4",0).toInt();}); + QTimer::singleShot (75, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_JT4",0).toInt());}); + QTimer::singleShot (100, [=] {on_sbSubmode_valueChanged(m_nSubMode);}); } else { ui->sbSubmode->setValue(0); } @@ -6753,6 +6756,7 @@ void MainWindow::on_actionJT4_triggered() void MainWindow::on_actionJT9_triggered() { + QTimer::singleShot (50, [=] {on_sbSubmode_valueChanged(ui->sbSubmode->value());}); m_mode="JT9"; bool bVHF=m_config.enable_VHF_features(); m_bFast9=ui->cbFast9->isChecked(); @@ -6839,8 +6843,9 @@ void MainWindow::on_actionJT65_triggered() ui->sbSubmode->setMaximum(2); if(bVHF) { // ui->sbSubmode->setValue(m_nSubMode); - m_nSubMode=m_settings->value("SubMode_JT65",0).toInt(); - QTimer::singleShot (50, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_JT65",0).toInt());}); + QTimer::singleShot (50, [=] {m_nSubMode=m_settings->value("SubMode_JT65",0).toInt();}); + QTimer::singleShot (75, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_JT65",0).toInt());}); + QTimer::singleShot (100, [=] {on_sbSubmode_valueChanged(m_nSubMode);}); ui->lh_decodes_title_label->setText(tr ("Single-Period Decodes")); ui->rh_decodes_title_label->setText(tr ("Average Decodes")); } else { @@ -6879,8 +6884,9 @@ void MainWindow::on_actionQ65_triggered() ui->sbTR->setValue (m_settings->value ("TRPeriod_Q65", 30).toInt()); // remember sbTR settings by mode QTimer::singleShot (50, [=] {on_sbTR_valueChanged (ui->sbTR->value());}); // ui->sbSubmode->setValue(m_nSubMode); - m_nSubMode=m_settings->value("SubMode_Q65",0).toInt(); - QTimer::singleShot (50, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_Q65",0).toInt());}); + QTimer::singleShot (50, [=] {m_nSubMode=m_settings->value("SubMode_Q65",0).toInt();}); + QTimer::singleShot (75, [=] {ui->sbSubmode->setValue(m_settings->value("SubMode_Q65",0).toInt());}); + QTimer::singleShot (100, [=] {on_sbSubmode_valueChanged(m_nSubMode);}); QString fname {QDir::toNativeSeparators(m_config.temp_dir().absoluteFilePath ("red.dat"))}; m_wideGraph->setRedFile(fname); m_wideGraph->setMode(m_mode); @@ -6951,7 +6957,10 @@ void MainWindow::on_actionMSK144_triggered() m_bFast9=false; ui->sbTR->values ({5, 10, 15, 30}); ui->sbTR->setValue (m_settings->value ("TRPeriod_MSK144", 15).toInt()); // remember sbTR settings by mode - QTimer::singleShot (50, [=] {on_sbTR_valueChanged (ui->sbTR->value());}); + QTimer::singleShot (50, [=] { + on_sbTR_valueChanged (ui->sbTR->value()); + on_sbSubmode_valueChanged(ui->sbSubmode->value()); + }); m_wideGraph->hide(); m_fastGraph->showNormal(); ui->TxFreqSpinBox->setValue(1500); @@ -8134,6 +8143,7 @@ void MainWindow::on_sbSubmode_valueChanged(int n) if(m_bFast9) ui->TxFreqSpinBox->setValue(700); } if(m_transmitting and m_bFast9 and m_nSubMode>=4) transmit (99.0); + if (m_mode !="Q65") ui->TxFreqSpinBox->setStyleSheet(""); if (m_mode=="Q65") {QTimer::singleShot (200, [=] {m_settings->setValue("SubMode_Q65",ui->sbSubmode->value());});} if (m_mode=="JT65") {QTimer::singleShot (200, [=] {m_settings->setValue("SubMode_JT65",ui->sbSubmode->value());});} if (m_mode=="JT4") {QTimer::singleShot (200, [=] {m_settings->setValue("SubMode_JT4",ui->sbSubmode->value());});} From da282209f1356ec498c89d4e4dc832d4f439ad71 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Fri, 8 Jul 2022 11:56:02 +0200 Subject: [PATCH 13/28] Remember Tx and Rx audio frequencies when coming back from any mode which sets AF to 1500 Hz (MSK144, FST4W, Echo, WSPR, FreqCal). --- widgets/mainwindow.cpp | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 858fe00b8..2be90e3c1 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6480,7 +6480,11 @@ void MainWindow::displayWidgets(qint64 n) void MainWindow::on_actionFST4_triggered() { - QTimer::singleShot (50, [=] {on_sbSubmode_valueChanged(ui->sbSubmode->value());}); + QTimer::singleShot (50, [=] { + ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq_old",1500).toInt()); + ui->RxFreqSpinBox->setValue(m_settings->value("RxFreq_old",1500).toInt()); + on_sbSubmode_valueChanged(ui->sbSubmode->value()); + }); m_mode="FST4"; ui->actionFST4->setChecked(true); m_bFast9=false; @@ -6553,7 +6557,11 @@ void MainWindow::on_actionFST4W_triggered() void MainWindow::on_actionFT4_triggered() { - QTimer::singleShot (50, [=] {on_sbSubmode_valueChanged(ui->sbSubmode->value());}); + QTimer::singleShot (50, [=] { + ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq_old",1500).toInt()); + ui->RxFreqSpinBox->setValue(m_settings->value("RxFreq_old",1500).toInt()); + on_sbSubmode_valueChanged(ui->sbSubmode->value()); + }); m_mode="FT4"; m_TRperiod=7.5; bool bVHF=m_config.enable_VHF_features(); @@ -6597,7 +6605,11 @@ void MainWindow::on_actionFT4_triggered() void MainWindow::on_actionFT8_triggered() { - QTimer::singleShot (50, [=] {on_sbSubmode_valueChanged(ui->sbSubmode->value());}); + QTimer::singleShot (50, [=] { + ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq_old",1500).toInt()); + ui->RxFreqSpinBox->setValue(m_settings->value("RxFreq_old",1500).toInt()); + on_sbSubmode_valueChanged(ui->sbSubmode->value()); + }); m_mode="FT8"; bool bVHF=m_config.enable_VHF_features(); m_bFast9=false; @@ -6711,6 +6723,10 @@ void MainWindow::on_actionFT8_triggered() void MainWindow::on_actionJT4_triggered() { + QTimer::singleShot (50, [=] { + ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq_old",1500).toInt()); + ui->RxFreqSpinBox->setValue(m_settings->value("RxFreq_old",1500).toInt()); + }); m_mode="JT4"; bool bVHF=m_config.enable_VHF_features(); WSPR_config(false); @@ -6816,6 +6832,10 @@ void MainWindow::on_actionJT9_triggered() void MainWindow::on_actionJT65_triggered() { + QTimer::singleShot (50, [=] { + ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq_old",1500).toInt()); + ui->RxFreqSpinBox->setValue(m_settings->value("RxFreq_old",1500).toInt()); + }); on_actionJT9_triggered(); m_mode="JT65"; bool bVHF=m_config.enable_VHF_features(); @@ -6869,6 +6889,10 @@ void MainWindow::on_actionJT65_triggered() void MainWindow::on_actionQ65_triggered() { + QTimer::singleShot (50, [=] { + ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq_old",1500).toInt()); + ui->RxFreqSpinBox->setValue(m_settings->value("RxFreq_old",1500).toInt()); + }); m_mode="Q65"; ui->actionQ65->setChecked(true); switch_mode(Modes::Q65); @@ -7180,7 +7204,9 @@ void MainWindow::on_TxFreqSpinBox_valueChanged(int n) ui->TxFreqSpinBox->setStyleSheet(""); } } - + if (m_mode != "MSK144" && m_mode != "FST4W" && m_mode != "WSPR" && m_mode != "Echo" && m_mode != "FreqCal") { + QTimer::singleShot (200, [=] {m_settings->setValue("TxFreq_old",ui->TxFreqSpinBox->value());}); + } statusUpdate (); } @@ -7190,6 +7216,9 @@ void MainWindow::on_RxFreqSpinBox_valueChanged(int n) if (m_mode == "FreqCal") { setRig (); } + if (m_mode != "MSK144" && m_mode != "FST4W" && m_mode != "WSPR" && m_mode != "Echo" && m_mode != "FreqCal") { + QTimer::singleShot (200, [=] {m_settings->setValue("RxFreq_old",ui->RxFreqSpinBox->value());}); + } statusUpdate (); } From 566d01aa2309941c016947249ac7160340d0f4e9 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Fri, 8 Jul 2022 14:37:43 +0200 Subject: [PATCH 14/28] Some possible text modules for the rc2 release notes. --- Release_Notes.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Release_Notes.txt b/Release_Notes.txt index e1a80df51..2285b2eb7 100644 --- a/Release_Notes.txt +++ b/Release_Notes.txt @@ -11,6 +11,36 @@ Copyright 2001 - 2022 by Joe Taylor, K1JT, and the WSJT Development Team + Release: WSJT-X 2.6.0-rc2 + August 01, 2022 + ---------------------- + +WSJT-X 2.6.0 Release Candidate 2 brings a number of useful improvements, +and some bug fixes. + +In program WSJT-X: + + - Echo-mode now lets the "Measure" function use the computed fspread + for DX grid + + - Fix VFOB not getting set on some rigs (e.g. IC7610 & IC7100) + + - The settings for T/R period and Submode are now remembered by band. + This is especially helpful for VHF / EME activities, and on HF for + FST4. You can now switch directly e.g. between MSK144-15, Q65-60A, + JT65-C, FST4-120 or whatever, and wsjt-x_improved remembers all that. + + - Also your last TX and RX audio frequencies are now remembered when + coming back from any mode which sets AF to 1500 Hz (MSK144, FST4W, + Echo, WSPR, FreqCal). + Note: when you start this version for the very first time, it will + set the RX and Tx audio frequencies for the non-restricted modes + (FT4, FT8, Q65, JT65, FST4) to 1500 Hz. Once you have changed the RX + and Tx audio frequencies in any of the non-restricted modes at least + one time, such values are saved and remembered. + + + Release: WSJT-X 2.6.0-rc1 June 16, 2022 ---------------------- @@ -85,6 +115,7 @@ In program MAP65 (Windows only): - Suppress a bounds error caused by too-wide setting of display bandwidth + Release: WSJT-X 2.5.4 Dec 28, 2021 ---------------------- From 4822b943508f49f5093fc276ee463d043feb8c9a Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Sat, 9 Jul 2022 12:38:26 +0200 Subject: [PATCH 15/28] Fix a problem with backward compatibility, part 1. --- models/FrequencyList.cpp | 994 --------------------------------------- 1 file changed, 994 deletions(-) delete mode 100644 models/FrequencyList.cpp diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp deleted file mode 100644 index cac85ea5a..000000000 --- a/models/FrequencyList.cpp +++ /dev/null @@ -1,994 +0,0 @@ -#include "FrequencyList.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Radio.hpp" -#include "Bands.hpp" -#include "pimpl_impl.hpp" - -#include "moc_FrequencyList.cpp" - -namespace -{ - FrequencyList_v2::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 - - {660000, Modes::FreqCal, IARURegions::R2}, - {880000, Modes::FreqCal, IARURegions::R2}, - {1210000, Modes::FreqCal, IARURegions::R2}, - - {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}, - - {136000, Modes::WSPR, IARURegions::ALL}, - {136000, Modes::FST4, IARURegions::ALL}, - {136000, Modes::FST4W, IARURegions::ALL}, - {136000, Modes::JT9, IARURegions::ALL}, - - {474200, Modes::JT9, IARURegions::ALL}, - {474200, Modes::FST4, IARURegions::ALL}, - {474200, Modes::WSPR, IARURegions::ALL}, - {474200, Modes::FST4W, IARURegions::ALL}, - - {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}, - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 3570 - 3580 DM NB(<200Hz) - // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS - // - // 3577.75 OLIVIA, Contestia, etc. - // 3580 PSK31 - // 3583.25 OLIVIA, Contestia, etc. - // - // R2: 3570 - 3580 DM NB(<200Hz) - // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS - // - // 3577.75 OLIVIA, Contestia, etc. - // 3580 PSK31 - // 3583.25 OLIVIA, Contestia, etc. - // 3590 RTTY DX - // 3596 W1AW DM QST - // - // R3: 3535 - 3580 DM NB(<2000Hz) - // - // 3520 - 3575 DM NB(<2000Hz) JA 3535 - 3575 shared with all modes - // - // 3522 OLIVIA, Contestia, etc. - // 3535 JA LSB EMCOMM - // 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 - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS - // 7050 - 7060 DM WB(<2700Hz) with 7050 - 7053 ACDS - // - // 7040 PSK31 - // 7043.25 OLIVIA, Contestia, etc. (main QRG) - // 7070 PSK31 - // 7073.25 OLIVIA, Contestia, etc. (main QRG) - // 7090 LSB QRP CoA - // - // R2: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS - // 7050 - 7053 DM WB(<2700Hz) ACDS shared with all modes - // - // 7040 RTTY DX - // 7043.25 OLIVIA, Contestia, etc. (main QRG) - // 7070 PSK31 (also LSB EMCOMM) - // 7073.25 OLIVIA, Contestia, etc. (main QRG) - // 7080 - 7125 RTTY/Data - // 7090 LSB QRP CoA - // - // R3: 7030 - 7060 DM NB(<2000Hz) with 7040 - 7060 NB DX all shared with phone - // - // 7030 - 7100 DM WB(<3000Hz) JA 7045 - 7100 shared with all modes - // - // 7026.25 OLIVIA, Contestia, etc. (main QRG) - // 7035 PSK31 - // 7050 JA LSB EMCOMM - // 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 - // up 500Hz to clear - // W1AW code practice QRG - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 10130 - 10150 DM NB(<500Hz) with 10120 - 10140 shared with phone in southern Africa - // - // 10139.25 OLIVIA, Contestia, etc. - // 10142 PSK31 - // 10142.25 OLIVIA, Contestia, etc. - // 10143.25 OLIVIA, Contestia, etc. (main QRG) - // - // R2: 10130 - 10140 DM NB(<500Hz) shared with ACDS - // 10140 - 10150 DM WB(<2700Hz) - // - // 10130 - 10140 RTTY - // 10139.25 OLIVIA, Contestia, etc. - // 10140 - 10150 Packet - // 10142 PSK31 - // 10142.25 OLIVIA, Contestia, etc. - // 10143.25 OLIVIA, Contestia, etc. (main QRG) - // - // R3: 10130 - 10150 DM NB(<2000Hz) - // - // 10139.25 OLIVIA, Contestia, etc. - // 10142 PSK31 - // 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 - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS - // 14101 - 14112 DM NB(<2700Hz) ACDS - // - // 14070 PSK31 - // 14074.4 OLIVIA, Contestia, etc. - // 14075.4 OLIVIA, Contestia, etc. (main QRG) - // 14078.4 OLIVIA, Contestia, etc. - // 14100 NCDXF beacons - // 14105.5 OLIVIA 1000 - // 14106.5 OLIVIA 1000 (main QRG) - // - // R2: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS - // 14101 - 14112 DM NB(<2700Hz) ACDS - // - // 14070 - 14095 RTTY - // 14070 PSK31 - // 14074.4 OLIVIA, Contestia, etc. - // 14075.4 OLIVIA, Contestia, etc. (main QRG) - // 14078.4 OLIVIA, Contestia, etc. - // 14095 - 14099.5 Packet - // 14100 NCDXF beacons - // 14100.5 - 14112 Packet - // 14105.5 OLIVIA 1000 - // 14106.5 OLIVIA 1000 (main QRG) - // - // R3: 14070 - 14112 DM NB(<2000Hz) with ±500Hz IBP guard band at 14100 - // - // 14070 PSK31 - // 14074.4 OLIVIA, Contestia, etc. - // 14075.4 OLIVIA, Contestia, etc. (main QRG) - // 14078.4 OLIVIA, Contestia, etc. - // 14100 NCDXF beacons - // 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 - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS - // 18111 - 18120 DM NB(<2700Hz) ACDS - // - // 18100 PSK31 - // 18103.4 OLIVIA, Contestia, etc. (main QRG) - // 18104.4 OLIVIA, Contestia, etc. - // 18110 NCDXF beacons - // - // R2: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS - // 18111 - 18120 DM NB(<2700Hz) ACDS - // - // 18100 - 18105 RTTY - // 18100 PSK31 - // 18103.4 OLIVIA, Contestia, etc. (main QRG) - // 18104.4 OLIVIA, Contestia, etc. - // 18105 - 18110 Packet - // 18110 NCDXF beacons - // - // R3: 18095 - 18120 DM NB(<2000Hz) with ±500Hz IBP guard band at 18110 - // - // 18100 PSK31 - // 18103.4 OLIVIA, Contestia, etc. (main QRG) - // 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}, - - {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}, - - {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}, - - {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}, - - {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}, - - {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}, - - {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}, - - {222065000, Modes::Echo, IARURegions::R2}, - {222065000, Modes::JT65, IARURegions::R2}, - {222065000, Modes::Q65, IARURegions::R2}, - - {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}, - - {902065000, Modes::JT65, IARURegions::R2}, - {902065000, Modes::Q65, IARURegions::R2}, - - {1296065000, Modes::Echo, IARURegions::ALL}, - {1296065000, Modes::JT65, IARURegions::ALL}, - {1296500000, Modes::WSPR, IARURegions::ALL}, - {1296065000, Modes::Q65, IARURegions::ALL}, - - {2301000000, Modes::Echo, IARURegions::ALL}, - {2301065000, Modes::JT4, IARURegions::ALL}, - {2301065000, Modes::JT65, IARURegions::ALL}, - {2301065000, Modes::Q65, IARURegions::ALL}, - - {2304065000, Modes::Echo, IARURegions::ALL}, - {2304065000, Modes::JT4, IARURegions::ALL}, - {2304065000, Modes::JT65, IARURegions::ALL}, - {2304065000, Modes::Q65, IARURegions::ALL}, - - {2320065000, Modes::Echo, IARURegions::ALL}, - {2320065000, Modes::JT4, IARURegions::ALL}, - {2320065000, Modes::JT65, IARURegions::ALL}, - {2320065000, Modes::Q65, IARURegions::ALL}, - - {3400065000, Modes::Echo, IARURegions::ALL}, - {3400065000, Modes::JT4, IARURegions::ALL}, - {3400065000, Modes::JT65, IARURegions::ALL}, - {3400065000, Modes::Q65, IARURegions::ALL}, - - {5760065000, Modes::Echo, IARURegions::ALL}, - {5760065000, Modes::JT4, IARURegions::ALL}, - {5760065000, Modes::JT65, IARURegions::ALL}, - {5760200000, Modes::Q65, IARURegions::ALL}, - - {10368100000, Modes::Echo, IARURegions::ALL}, - {10368200000, Modes::JT4, IARURegions::ALL}, - {10368200000, Modes::Q65, IARURegions::ALL}, - - {24048100000, Modes::Echo, IARURegions::ALL}, - {24048200000, Modes::JT4, IARURegions::ALL}, - {24048200000, Modes::Q65, IARURegions::ALL}, - }; -} - -#if !defined (QT_NO_DEBUG_STREAM) -QDebug operator << (QDebug debug, FrequencyList_v2::Item const& item) -{ - QDebugStateSaver saver {debug}; - return debug.nospace () << item.toString (); -} -#endif - -QString FrequencyList_v2::Item::toString () const -{ - QString string; - QTextStream qts {&string}; - qts << "FrequencyItem(" - << Radio::frequency_MHz_string (frequency_) << ", " - << IARURegions::name (region_) << ", " - << Modes::name (mode_) << ')'; - return string; -} - -QDataStream& operator << (QDataStream& os, FrequencyList_v2::Item const& item) -{ - return os << item.frequency_ - << item.mode_ - << item.region_; -} - -QDataStream& operator >> (QDataStream& is, FrequencyList_v2::Item& item) -{ - return is >> item.frequency_ - >> item.mode_ - >> item.region_; -} - -class FrequencyList_v2::impl final - : public QAbstractTableModel -{ -public: - impl (Bands const * bands, QObject * parent) - : QAbstractTableModel {parent} - , bands_ {bands} - , region_filter_ {IARURegions::ALL} - , mode_filter_ {Modes::ALL} - { - } - - FrequencyItems frequency_list (FrequencyItems); - QModelIndex add (Item); - void add (FrequencyItems); - - // Implement the QAbstractTableModel interface - int rowCount (QModelIndex const& parent = QModelIndex {}) const override; - int columnCount (QModelIndex const& parent = QModelIndex {}) const override; - Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; - QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; - bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override; - QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; - bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; - bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; - QStringList mimeTypes () const override; - QMimeData * mimeData (QModelIndexList const&) const override; - - static int constexpr num_cols {SENTINAL}; - static auto constexpr mime_type = "application/wsjt.Frequencies"; - - Bands const * bands_; - FrequencyItems frequency_list_; - Region region_filter_; - Mode mode_filter_; -}; - -FrequencyList_v2::FrequencyList_v2 (Bands const * bands, QObject * parent) - : QSortFilterProxyModel {parent} - , m_ {bands, parent} -{ - setSourceModel (&*m_); - setSortRole (SortRole); -} - -FrequencyList_v2::~FrequencyList_v2 () -{ -} - -auto FrequencyList_v2::frequency_list (FrequencyItems frequency_list) -> FrequencyItems -{ - return m_->frequency_list (frequency_list); -} - -auto FrequencyList_v2::frequency_list () const -> FrequencyItems const& -{ - return m_->frequency_list_; -} - -auto FrequencyList_v2::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_v2::frequency_list_merge (FrequencyItems const& items) -{ - m_->add (items); -} - -int FrequencyList_v2::best_working_frequency (Frequency f) const -{ - int result {-1}; - auto const& target_band = m_->bands_->find (f); - if (!target_band.isEmpty ()) - { - Radio::FrequencyDelta delta {std::numeric_limits::max ()}; - // find a frequency in the same band that is allowed - for (int row = 0; row < rowCount (); ++row) - { - auto const& source_row = mapToSource (index (row, 0)).row (); - auto const& candidate_frequency = m_->frequency_list_[source_row].frequency_; - auto const& band = m_->bands_->find (candidate_frequency); - if (band == target_band) - { - // take closest band match - Radio::FrequencyDelta new_delta = f - candidate_frequency; - if (std::abs (new_delta) < std::abs (delta)) - { - delta = new_delta; - result = row; - } - } - } - } - return result; -} - -int FrequencyList_v2::best_working_frequency (QString const& target_band) const -{ - int result {-1}; - if (!target_band.isEmpty ()) - { - // find a frequency in the same band that is allowed - for (int row = 0; row < rowCount (); ++row) - { - auto const& source_row = mapToSource (index (row, 0)).row (); - auto const& band = m_->bands_->find (m_->frequency_list_[source_row].frequency_); - if (band == target_band) - { - return row; - } - } - } - return result; -} - -void FrequencyList_v2::reset_to_defaults () -{ - m_->frequency_list (default_frequency_list); -} - -QModelIndex FrequencyList_v2::add (Item f) -{ - return mapFromSource (m_->add (f)); -} - -bool FrequencyList_v2::remove (Item f) -{ - auto row = m_->frequency_list_.indexOf (f); - - if (0 > row) - { - return false; - } - - return m_->removeRow (row); -} - -bool FrequencyList_v2::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. - for (int r = 0; r < rows.size (); ++r) - { - rows[r] = mapToSource (rows[r]); - } - - // reverse sort by row - std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) - { - return rhs.row () < lhs.row (); // reverse row ordering - }); - Q_FOREACH (auto index, rows) - { - if (result && !m_->removeRow (index.row ())) - { - result = false; - } - } - return result; -} - -void FrequencyList_v2::filter (Region region, Mode mode) -{ - m_->region_filter_ = region; - m_->mode_filter_ = mode; - invalidateFilter (); -} - -bool FrequencyList_v2::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const -{ - bool result {true}; - auto const& item = m_->frequency_list_[source_row]; - if (m_->region_filter_ != IARURegions::ALL) - { - result = IARURegions::ALL == item.region_ || m_->region_filter_ == item.region_; - } - 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_; - } - return result; -} - - -auto FrequencyList_v2::impl::frequency_list (FrequencyItems frequency_list) -> FrequencyItems -{ - beginResetModel (); - std::swap (frequency_list_, frequency_list); - endResetModel (); - return frequency_list; -} - -// add a frequency returning the new model index -QModelIndex FrequencyList_v2::impl::add (Item f) -{ - // Any Frequency that isn't in the list may be added - if (!frequency_list_.contains (f)) - { - auto row = frequency_list_.size (); - - beginInsertRows (QModelIndex {}, row, row); - frequency_list_.append (f); - endInsertRows (); - - return index (row, 0); - } - return QModelIndex {}; -} - -void FrequencyList_v2::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_v2::impl::rowCount (QModelIndex const& parent) const -{ - return parent.isValid () ? 0 : frequency_list_.size (); -} - -int FrequencyList_v2::impl::columnCount (QModelIndex const& parent) const -{ - return parent.isValid () ? 0 : num_cols; -} - -Qt::ItemFlags FrequencyList_v2::impl::flags (QModelIndex const& index) const -{ - auto result = QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; - auto row = index.row (); - auto column = index.column (); - if (index.isValid () - && row < frequency_list_.size () - && column < num_cols) - { - if (frequency_mhz_column != column) - { - result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; - } - } - return result; -} - -QVariant FrequencyList_v2::impl::data (QModelIndex const& index, int role) const -{ - QVariant item; - - auto const& row = index.row (); - auto const& column = index.column (); - - if (index.isValid () - && row < frequency_list_.size () - && column < num_cols) - { - auto const& frequency_item = frequency_list_.at (row); - 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: - switch (role) - { - case SortRole: - case Qt::DisplayRole: - case Qt::EditRole: - case Qt::AccessibleTextRole: - item = Modes::name (frequency_item.mode_); - break; - - case Qt::ToolTipRole: - case Qt::AccessibleDescriptionRole: - item = tr ("Mode"); - break; - - case Qt::TextAlignmentRole: - item = Qt::AlignHCenter + Qt::AlignVCenter; - break; - } - break; - - case frequency_column: - switch (role) - { - case SortRole: - case Qt::EditRole: - case Qt::AccessibleTextRole: - item = frequency_item.frequency_; - break; - - 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) + ')'; - } - break; - - case Qt::ToolTipRole: - case Qt::AccessibleDescriptionRole: - item = tr ("Frequency"); - break; - - case Qt::TextAlignmentRole: - item = Qt::AlignRight + Qt::AlignVCenter; - break; - } - break; - - case frequency_mhz_column: - switch (role) - { - case Qt::EditRole: - case Qt::AccessibleTextRole: - item = Radio::frequency_MHz_string (frequency_item.frequency_); - break; - - 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) + ')'; - } - break; - - case Qt::ToolTipRole: - case Qt::AccessibleDescriptionRole: - item = tr ("Frequency (MHz)"); - break; - - case Qt::TextAlignmentRole: - item = Qt::AlignRight + Qt::AlignVCenter; - break; - } - break; - } - } - return item; -} - -bool FrequencyList_v2::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) -{ - bool changed {false}; - - auto const& row = model_index.row (); - if (model_index.isValid () - && Qt::EditRole == role - && row < frequency_list_.size ()) - { - QVector roles; - roles << role; - - auto& item = frequency_list_[row]; - 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 ()) - { - 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; - } - } - - return changed; -} - -QVariant FrequencyList_v2::impl::headerData (int section, Qt::Orientation orientation, int role) const -{ - QVariant header; - if (Qt::DisplayRole == role - && Qt::Horizontal == orientation - && section < num_cols) - { - 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; - } - } - else - { - header = QAbstractTableModel::headerData (section, orientation, role); - } - return header; -} - -bool FrequencyList_v2::impl::removeRows (int row, int count, QModelIndex const& parent) -{ - if (0 < count && (row + count) <= rowCount (parent)) - { - beginRemoveRows (parent, row, row + count - 1); - for (auto r = 0; r < count; ++r) - { - frequency_list_.removeAt (row); - } - endRemoveRows (); - return true; - } - return false; -} - -bool FrequencyList_v2::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}); - } - endInsertRows (); - return true; - } - return false; -} - -QStringList FrequencyList_v2::impl::mimeTypes () const -{ - QStringList types; - types << mime_type; - return types; -} - -QMimeData * FrequencyList_v2::impl::mimeData (QModelIndexList const& items) const -{ - QMimeData * mime_data = new QMimeData {}; - QByteArray encoded_data; - QDataStream stream {&encoded_data, QIODevice::WriteOnly}; - - Q_FOREACH (auto const& item, items) - { - if (item.isValid () && frequency_column == item.column ()) - { - stream << frequency_list_.at (item.row ()); - } - } - - mime_data->setData (mime_type, encoded_data); - return mime_data; -} - -auto FrequencyList_v2::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 * -{ - return &parent_->frequency_list ().at(parent_->mapToSource (parent_->index (row_, 0)).row ()); -} - -bool FrequencyList_v2::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 -{ - return parent_ == rhs.parent_ && row_ == rhs.row_; -} - -auto FrequencyList_v2::const_iterator::operator ++ () -> const_iterator& -{ - ++row_; - return *this; -} - -auto FrequencyList_v2::begin () const -> const_iterator -{ - return const_iterator (this, 0); -} - -auto FrequencyList_v2::end () const -> const_iterator -{ - return const_iterator (this, rowCount ()); -} - -auto FrequencyList_v2::find (Frequency f) const -> const_iterator -{ - int row {0}; - for (; row < rowCount (); ++row) - { - if (m_->frequency_list_[mapToSource (index (row, 0)).row ()].frequency_ == f) - { - break; - } - } - return const_iterator (this, row); -} - -auto FrequencyList_v2::filtered_bands () const -> BandSet -{ - BandSet result; - for (auto const& item : *this) - { - result << m_->bands_->find (item.frequency_); - } - return result; -} - -auto FrequencyList_v2::all_bands (Region region, Mode mode) const -> BandSet -{ - BandSet result; - for (auto const& item : m_->frequency_list_) - { - // Match frequencies that are for all regions, for the specified - // region (which can also be "all"), and where the mode matches - // the specified mode (which can also be "all"). - if ((region == IARURegions::ALL || item.region_ == IARURegions::ALL || item.region_ == region) - && (mode == Modes::ALL || item.mode_ == Modes::ALL || item.mode_ == mode)) - { - result << m_->bands_->find (item.frequency_); - } - } - return result; -} - -// -// Obsolete version of FrequencyList no longer used but needed to -// allow loading and saving of old settings contents without damage -// -QDataStream& operator << (QDataStream& os, FrequencyList::Item const& item) -{ - return os << item.frequency_ - << item.mode_; -} - -QDataStream& operator >> (QDataStream& is, FrequencyList::Item& item) -{ - return is >> item.frequency_ - >> item.mode_; -} From 4545195a3214f875028e9015a9015159f6fa54cd Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Sat, 9 Jul 2022 12:39:12 +0200 Subject: [PATCH 16/28] Fix a problem with backward compatibility, part 2. --- models/FrequencyList.cpp | 994 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 994 insertions(+) create mode 100644 models/FrequencyList.cpp diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp new file mode 100644 index 000000000..cac85ea5a --- /dev/null +++ b/models/FrequencyList.cpp @@ -0,0 +1,994 @@ +#include "FrequencyList.hpp" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Radio.hpp" +#include "Bands.hpp" +#include "pimpl_impl.hpp" + +#include "moc_FrequencyList.cpp" + +namespace +{ + FrequencyList_v2::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 + + {660000, Modes::FreqCal, IARURegions::R2}, + {880000, Modes::FreqCal, IARURegions::R2}, + {1210000, Modes::FreqCal, IARURegions::R2}, + + {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}, + + {136000, Modes::WSPR, IARURegions::ALL}, + {136000, Modes::FST4, IARURegions::ALL}, + {136000, Modes::FST4W, IARURegions::ALL}, + {136000, Modes::JT9, IARURegions::ALL}, + + {474200, Modes::JT9, IARURegions::ALL}, + {474200, Modes::FST4, IARURegions::ALL}, + {474200, Modes::WSPR, IARURegions::ALL}, + {474200, Modes::FST4W, IARURegions::ALL}, + + {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}, + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 3570 - 3580 DM NB(<200Hz) + // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS + // + // 3577.75 OLIVIA, Contestia, etc. + // 3580 PSK31 + // 3583.25 OLIVIA, Contestia, etc. + // + // R2: 3570 - 3580 DM NB(<200Hz) + // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS + // + // 3577.75 OLIVIA, Contestia, etc. + // 3580 PSK31 + // 3583.25 OLIVIA, Contestia, etc. + // 3590 RTTY DX + // 3596 W1AW DM QST + // + // R3: 3535 - 3580 DM NB(<2000Hz) + // + // 3520 - 3575 DM NB(<2000Hz) JA 3535 - 3575 shared with all modes + // + // 3522 OLIVIA, Contestia, etc. + // 3535 JA LSB EMCOMM + // 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 + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS + // 7050 - 7060 DM WB(<2700Hz) with 7050 - 7053 ACDS + // + // 7040 PSK31 + // 7043.25 OLIVIA, Contestia, etc. (main QRG) + // 7070 PSK31 + // 7073.25 OLIVIA, Contestia, etc. (main QRG) + // 7090 LSB QRP CoA + // + // R2: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS + // 7050 - 7053 DM WB(<2700Hz) ACDS shared with all modes + // + // 7040 RTTY DX + // 7043.25 OLIVIA, Contestia, etc. (main QRG) + // 7070 PSK31 (also LSB EMCOMM) + // 7073.25 OLIVIA, Contestia, etc. (main QRG) + // 7080 - 7125 RTTY/Data + // 7090 LSB QRP CoA + // + // R3: 7030 - 7060 DM NB(<2000Hz) with 7040 - 7060 NB DX all shared with phone + // + // 7030 - 7100 DM WB(<3000Hz) JA 7045 - 7100 shared with all modes + // + // 7026.25 OLIVIA, Contestia, etc. (main QRG) + // 7035 PSK31 + // 7050 JA LSB EMCOMM + // 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 + // up 500Hz to clear + // W1AW code practice QRG + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 10130 - 10150 DM NB(<500Hz) with 10120 - 10140 shared with phone in southern Africa + // + // 10139.25 OLIVIA, Contestia, etc. + // 10142 PSK31 + // 10142.25 OLIVIA, Contestia, etc. + // 10143.25 OLIVIA, Contestia, etc. (main QRG) + // + // R2: 10130 - 10140 DM NB(<500Hz) shared with ACDS + // 10140 - 10150 DM WB(<2700Hz) + // + // 10130 - 10140 RTTY + // 10139.25 OLIVIA, Contestia, etc. + // 10140 - 10150 Packet + // 10142 PSK31 + // 10142.25 OLIVIA, Contestia, etc. + // 10143.25 OLIVIA, Contestia, etc. (main QRG) + // + // R3: 10130 - 10150 DM NB(<2000Hz) + // + // 10139.25 OLIVIA, Contestia, etc. + // 10142 PSK31 + // 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 + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS + // 14101 - 14112 DM NB(<2700Hz) ACDS + // + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14100 NCDXF beacons + // 14105.5 OLIVIA 1000 + // 14106.5 OLIVIA 1000 (main QRG) + // + // R2: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS + // 14101 - 14112 DM NB(<2700Hz) ACDS + // + // 14070 - 14095 RTTY + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14095 - 14099.5 Packet + // 14100 NCDXF beacons + // 14100.5 - 14112 Packet + // 14105.5 OLIVIA 1000 + // 14106.5 OLIVIA 1000 (main QRG) + // + // R3: 14070 - 14112 DM NB(<2000Hz) with ±500Hz IBP guard band at 14100 + // + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14100 NCDXF beacons + // 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 + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS + // 18111 - 18120 DM NB(<2700Hz) ACDS + // + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 18104.4 OLIVIA, Contestia, etc. + // 18110 NCDXF beacons + // + // R2: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS + // 18111 - 18120 DM NB(<2700Hz) ACDS + // + // 18100 - 18105 RTTY + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 18104.4 OLIVIA, Contestia, etc. + // 18105 - 18110 Packet + // 18110 NCDXF beacons + // + // R3: 18095 - 18120 DM NB(<2000Hz) with ±500Hz IBP guard band at 18110 + // + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 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}, + + {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}, + + {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}, + + {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}, + + {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}, + + {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}, + + {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}, + + {222065000, Modes::Echo, IARURegions::R2}, + {222065000, Modes::JT65, IARURegions::R2}, + {222065000, Modes::Q65, IARURegions::R2}, + + {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}, + + {902065000, Modes::JT65, IARURegions::R2}, + {902065000, Modes::Q65, IARURegions::R2}, + + {1296065000, Modes::Echo, IARURegions::ALL}, + {1296065000, Modes::JT65, IARURegions::ALL}, + {1296500000, Modes::WSPR, IARURegions::ALL}, + {1296065000, Modes::Q65, IARURegions::ALL}, + + {2301000000, Modes::Echo, IARURegions::ALL}, + {2301065000, Modes::JT4, IARURegions::ALL}, + {2301065000, Modes::JT65, IARURegions::ALL}, + {2301065000, Modes::Q65, IARURegions::ALL}, + + {2304065000, Modes::Echo, IARURegions::ALL}, + {2304065000, Modes::JT4, IARURegions::ALL}, + {2304065000, Modes::JT65, IARURegions::ALL}, + {2304065000, Modes::Q65, IARURegions::ALL}, + + {2320065000, Modes::Echo, IARURegions::ALL}, + {2320065000, Modes::JT4, IARURegions::ALL}, + {2320065000, Modes::JT65, IARURegions::ALL}, + {2320065000, Modes::Q65, IARURegions::ALL}, + + {3400065000, Modes::Echo, IARURegions::ALL}, + {3400065000, Modes::JT4, IARURegions::ALL}, + {3400065000, Modes::JT65, IARURegions::ALL}, + {3400065000, Modes::Q65, IARURegions::ALL}, + + {5760065000, Modes::Echo, IARURegions::ALL}, + {5760065000, Modes::JT4, IARURegions::ALL}, + {5760065000, Modes::JT65, IARURegions::ALL}, + {5760200000, Modes::Q65, IARURegions::ALL}, + + {10368100000, Modes::Echo, IARURegions::ALL}, + {10368200000, Modes::JT4, IARURegions::ALL}, + {10368200000, Modes::Q65, IARURegions::ALL}, + + {24048100000, Modes::Echo, IARURegions::ALL}, + {24048200000, Modes::JT4, IARURegions::ALL}, + {24048200000, Modes::Q65, IARURegions::ALL}, + }; +} + +#if !defined (QT_NO_DEBUG_STREAM) +QDebug operator << (QDebug debug, FrequencyList_v2::Item const& item) +{ + QDebugStateSaver saver {debug}; + return debug.nospace () << item.toString (); +} +#endif + +QString FrequencyList_v2::Item::toString () const +{ + QString string; + QTextStream qts {&string}; + qts << "FrequencyItem(" + << Radio::frequency_MHz_string (frequency_) << ", " + << IARURegions::name (region_) << ", " + << Modes::name (mode_) << ')'; + return string; +} + +QDataStream& operator << (QDataStream& os, FrequencyList_v2::Item const& item) +{ + return os << item.frequency_ + << item.mode_ + << item.region_; +} + +QDataStream& operator >> (QDataStream& is, FrequencyList_v2::Item& item) +{ + return is >> item.frequency_ + >> item.mode_ + >> item.region_; +} + +class FrequencyList_v2::impl final + : public QAbstractTableModel +{ +public: + impl (Bands const * bands, QObject * parent) + : QAbstractTableModel {parent} + , bands_ {bands} + , region_filter_ {IARURegions::ALL} + , mode_filter_ {Modes::ALL} + { + } + + FrequencyItems frequency_list (FrequencyItems); + QModelIndex add (Item); + void add (FrequencyItems); + + // Implement the QAbstractTableModel interface + int rowCount (QModelIndex const& parent = QModelIndex {}) const override; + int columnCount (QModelIndex const& parent = QModelIndex {}) const override; + Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; + QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; + bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override; + QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; + bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; + bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; + QStringList mimeTypes () const override; + QMimeData * mimeData (QModelIndexList const&) const override; + + static int constexpr num_cols {SENTINAL}; + static auto constexpr mime_type = "application/wsjt.Frequencies"; + + Bands const * bands_; + FrequencyItems frequency_list_; + Region region_filter_; + Mode mode_filter_; +}; + +FrequencyList_v2::FrequencyList_v2 (Bands const * bands, QObject * parent) + : QSortFilterProxyModel {parent} + , m_ {bands, parent} +{ + setSourceModel (&*m_); + setSortRole (SortRole); +} + +FrequencyList_v2::~FrequencyList_v2 () +{ +} + +auto FrequencyList_v2::frequency_list (FrequencyItems frequency_list) -> FrequencyItems +{ + return m_->frequency_list (frequency_list); +} + +auto FrequencyList_v2::frequency_list () const -> FrequencyItems const& +{ + return m_->frequency_list_; +} + +auto FrequencyList_v2::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_v2::frequency_list_merge (FrequencyItems const& items) +{ + m_->add (items); +} + +int FrequencyList_v2::best_working_frequency (Frequency f) const +{ + int result {-1}; + auto const& target_band = m_->bands_->find (f); + if (!target_band.isEmpty ()) + { + Radio::FrequencyDelta delta {std::numeric_limits::max ()}; + // find a frequency in the same band that is allowed + for (int row = 0; row < rowCount (); ++row) + { + auto const& source_row = mapToSource (index (row, 0)).row (); + auto const& candidate_frequency = m_->frequency_list_[source_row].frequency_; + auto const& band = m_->bands_->find (candidate_frequency); + if (band == target_band) + { + // take closest band match + Radio::FrequencyDelta new_delta = f - candidate_frequency; + if (std::abs (new_delta) < std::abs (delta)) + { + delta = new_delta; + result = row; + } + } + } + } + return result; +} + +int FrequencyList_v2::best_working_frequency (QString const& target_band) const +{ + int result {-1}; + if (!target_band.isEmpty ()) + { + // find a frequency in the same band that is allowed + for (int row = 0; row < rowCount (); ++row) + { + auto const& source_row = mapToSource (index (row, 0)).row (); + auto const& band = m_->bands_->find (m_->frequency_list_[source_row].frequency_); + if (band == target_band) + { + return row; + } + } + } + return result; +} + +void FrequencyList_v2::reset_to_defaults () +{ + m_->frequency_list (default_frequency_list); +} + +QModelIndex FrequencyList_v2::add (Item f) +{ + return mapFromSource (m_->add (f)); +} + +bool FrequencyList_v2::remove (Item f) +{ + auto row = m_->frequency_list_.indexOf (f); + + if (0 > row) + { + return false; + } + + return m_->removeRow (row); +} + +bool FrequencyList_v2::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. + for (int r = 0; r < rows.size (); ++r) + { + rows[r] = mapToSource (rows[r]); + } + + // reverse sort by row + std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) + { + return rhs.row () < lhs.row (); // reverse row ordering + }); + Q_FOREACH (auto index, rows) + { + if (result && !m_->removeRow (index.row ())) + { + result = false; + } + } + return result; +} + +void FrequencyList_v2::filter (Region region, Mode mode) +{ + m_->region_filter_ = region; + m_->mode_filter_ = mode; + invalidateFilter (); +} + +bool FrequencyList_v2::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const +{ + bool result {true}; + auto const& item = m_->frequency_list_[source_row]; + if (m_->region_filter_ != IARURegions::ALL) + { + result = IARURegions::ALL == item.region_ || m_->region_filter_ == item.region_; + } + 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_; + } + return result; +} + + +auto FrequencyList_v2::impl::frequency_list (FrequencyItems frequency_list) -> FrequencyItems +{ + beginResetModel (); + std::swap (frequency_list_, frequency_list); + endResetModel (); + return frequency_list; +} + +// add a frequency returning the new model index +QModelIndex FrequencyList_v2::impl::add (Item f) +{ + // Any Frequency that isn't in the list may be added + if (!frequency_list_.contains (f)) + { + auto row = frequency_list_.size (); + + beginInsertRows (QModelIndex {}, row, row); + frequency_list_.append (f); + endInsertRows (); + + return index (row, 0); + } + return QModelIndex {}; +} + +void FrequencyList_v2::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_v2::impl::rowCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : frequency_list_.size (); +} + +int FrequencyList_v2::impl::columnCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : num_cols; +} + +Qt::ItemFlags FrequencyList_v2::impl::flags (QModelIndex const& index) const +{ + auto result = QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; + auto row = index.row (); + auto column = index.column (); + if (index.isValid () + && row < frequency_list_.size () + && column < num_cols) + { + if (frequency_mhz_column != column) + { + result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; + } + } + return result; +} + +QVariant FrequencyList_v2::impl::data (QModelIndex const& index, int role) const +{ + QVariant item; + + auto const& row = index.row (); + auto const& column = index.column (); + + if (index.isValid () + && row < frequency_list_.size () + && column < num_cols) + { + auto const& frequency_item = frequency_list_.at (row); + 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: + switch (role) + { + case SortRole: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = Modes::name (frequency_item.mode_); + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Mode"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignHCenter + Qt::AlignVCenter; + break; + } + break; + + case frequency_column: + switch (role) + { + case SortRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = frequency_item.frequency_; + break; + + 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) + ')'; + } + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Frequency"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignRight + Qt::AlignVCenter; + break; + } + break; + + case frequency_mhz_column: + switch (role) + { + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = Radio::frequency_MHz_string (frequency_item.frequency_); + break; + + 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) + ')'; + } + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Frequency (MHz)"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignRight + Qt::AlignVCenter; + break; + } + break; + } + } + return item; +} + +bool FrequencyList_v2::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) +{ + bool changed {false}; + + auto const& row = model_index.row (); + if (model_index.isValid () + && Qt::EditRole == role + && row < frequency_list_.size ()) + { + QVector roles; + roles << role; + + auto& item = frequency_list_[row]; + 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 ()) + { + 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; + } + } + + return changed; +} + +QVariant FrequencyList_v2::impl::headerData (int section, Qt::Orientation orientation, int role) const +{ + QVariant header; + if (Qt::DisplayRole == role + && Qt::Horizontal == orientation + && section < num_cols) + { + 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; + } + } + else + { + header = QAbstractTableModel::headerData (section, orientation, role); + } + return header; +} + +bool FrequencyList_v2::impl::removeRows (int row, int count, QModelIndex const& parent) +{ + if (0 < count && (row + count) <= rowCount (parent)) + { + beginRemoveRows (parent, row, row + count - 1); + for (auto r = 0; r < count; ++r) + { + frequency_list_.removeAt (row); + } + endRemoveRows (); + return true; + } + return false; +} + +bool FrequencyList_v2::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}); + } + endInsertRows (); + return true; + } + return false; +} + +QStringList FrequencyList_v2::impl::mimeTypes () const +{ + QStringList types; + types << mime_type; + return types; +} + +QMimeData * FrequencyList_v2::impl::mimeData (QModelIndexList const& items) const +{ + QMimeData * mime_data = new QMimeData {}; + QByteArray encoded_data; + QDataStream stream {&encoded_data, QIODevice::WriteOnly}; + + Q_FOREACH (auto const& item, items) + { + if (item.isValid () && frequency_column == item.column ()) + { + stream << frequency_list_.at (item.row ()); + } + } + + mime_data->setData (mime_type, encoded_data); + return mime_data; +} + +auto FrequencyList_v2::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 * +{ + return &parent_->frequency_list ().at(parent_->mapToSource (parent_->index (row_, 0)).row ()); +} + +bool FrequencyList_v2::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 +{ + return parent_ == rhs.parent_ && row_ == rhs.row_; +} + +auto FrequencyList_v2::const_iterator::operator ++ () -> const_iterator& +{ + ++row_; + return *this; +} + +auto FrequencyList_v2::begin () const -> const_iterator +{ + return const_iterator (this, 0); +} + +auto FrequencyList_v2::end () const -> const_iterator +{ + return const_iterator (this, rowCount ()); +} + +auto FrequencyList_v2::find (Frequency f) const -> const_iterator +{ + int row {0}; + for (; row < rowCount (); ++row) + { + if (m_->frequency_list_[mapToSource (index (row, 0)).row ()].frequency_ == f) + { + break; + } + } + return const_iterator (this, row); +} + +auto FrequencyList_v2::filtered_bands () const -> BandSet +{ + BandSet result; + for (auto const& item : *this) + { + result << m_->bands_->find (item.frequency_); + } + return result; +} + +auto FrequencyList_v2::all_bands (Region region, Mode mode) const -> BandSet +{ + BandSet result; + for (auto const& item : m_->frequency_list_) + { + // Match frequencies that are for all regions, for the specified + // region (which can also be "all"), and where the mode matches + // the specified mode (which can also be "all"). + if ((region == IARURegions::ALL || item.region_ == IARURegions::ALL || item.region_ == region) + && (mode == Modes::ALL || item.mode_ == Modes::ALL || item.mode_ == mode)) + { + result << m_->bands_->find (item.frequency_); + } + } + return result; +} + +// +// Obsolete version of FrequencyList no longer used but needed to +// allow loading and saving of old settings contents without damage +// +QDataStream& operator << (QDataStream& os, FrequencyList::Item const& item) +{ + return os << item.frequency_ + << item.mode_; +} + +QDataStream& operator >> (QDataStream& is, FrequencyList::Item& item) +{ + return is >> item.frequency_ + >> item.mode_; +} From dd384d076522cd614e3c26902bba6d533e07ebbf Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Sat, 9 Jul 2022 12:43:39 +0200 Subject: [PATCH 17/28] Revert "Fix a problem with backward compatibility, part 2." This reverts commit 4545195a3214f875028e9015a9015159f6fa54cd. --- models/FrequencyList.cpp | 994 --------------------------------------- 1 file changed, 994 deletions(-) delete mode 100644 models/FrequencyList.cpp diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp deleted file mode 100644 index cac85ea5a..000000000 --- a/models/FrequencyList.cpp +++ /dev/null @@ -1,994 +0,0 @@ -#include "FrequencyList.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Radio.hpp" -#include "Bands.hpp" -#include "pimpl_impl.hpp" - -#include "moc_FrequencyList.cpp" - -namespace -{ - FrequencyList_v2::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 - - {660000, Modes::FreqCal, IARURegions::R2}, - {880000, Modes::FreqCal, IARURegions::R2}, - {1210000, Modes::FreqCal, IARURegions::R2}, - - {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}, - - {136000, Modes::WSPR, IARURegions::ALL}, - {136000, Modes::FST4, IARURegions::ALL}, - {136000, Modes::FST4W, IARURegions::ALL}, - {136000, Modes::JT9, IARURegions::ALL}, - - {474200, Modes::JT9, IARURegions::ALL}, - {474200, Modes::FST4, IARURegions::ALL}, - {474200, Modes::WSPR, IARURegions::ALL}, - {474200, Modes::FST4W, IARURegions::ALL}, - - {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}, - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 3570 - 3580 DM NB(<200Hz) - // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS - // - // 3577.75 OLIVIA, Contestia, etc. - // 3580 PSK31 - // 3583.25 OLIVIA, Contestia, etc. - // - // R2: 3570 - 3580 DM NB(<200Hz) - // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS - // - // 3577.75 OLIVIA, Contestia, etc. - // 3580 PSK31 - // 3583.25 OLIVIA, Contestia, etc. - // 3590 RTTY DX - // 3596 W1AW DM QST - // - // R3: 3535 - 3580 DM NB(<2000Hz) - // - // 3520 - 3575 DM NB(<2000Hz) JA 3535 - 3575 shared with all modes - // - // 3522 OLIVIA, Contestia, etc. - // 3535 JA LSB EMCOMM - // 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 - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS - // 7050 - 7060 DM WB(<2700Hz) with 7050 - 7053 ACDS - // - // 7040 PSK31 - // 7043.25 OLIVIA, Contestia, etc. (main QRG) - // 7070 PSK31 - // 7073.25 OLIVIA, Contestia, etc. (main QRG) - // 7090 LSB QRP CoA - // - // R2: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS - // 7050 - 7053 DM WB(<2700Hz) ACDS shared with all modes - // - // 7040 RTTY DX - // 7043.25 OLIVIA, Contestia, etc. (main QRG) - // 7070 PSK31 (also LSB EMCOMM) - // 7073.25 OLIVIA, Contestia, etc. (main QRG) - // 7080 - 7125 RTTY/Data - // 7090 LSB QRP CoA - // - // R3: 7030 - 7060 DM NB(<2000Hz) with 7040 - 7060 NB DX all shared with phone - // - // 7030 - 7100 DM WB(<3000Hz) JA 7045 - 7100 shared with all modes - // - // 7026.25 OLIVIA, Contestia, etc. (main QRG) - // 7035 PSK31 - // 7050 JA LSB EMCOMM - // 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 - // up 500Hz to clear - // W1AW code practice QRG - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 10130 - 10150 DM NB(<500Hz) with 10120 - 10140 shared with phone in southern Africa - // - // 10139.25 OLIVIA, Contestia, etc. - // 10142 PSK31 - // 10142.25 OLIVIA, Contestia, etc. - // 10143.25 OLIVIA, Contestia, etc. (main QRG) - // - // R2: 10130 - 10140 DM NB(<500Hz) shared with ACDS - // 10140 - 10150 DM WB(<2700Hz) - // - // 10130 - 10140 RTTY - // 10139.25 OLIVIA, Contestia, etc. - // 10140 - 10150 Packet - // 10142 PSK31 - // 10142.25 OLIVIA, Contestia, etc. - // 10143.25 OLIVIA, Contestia, etc. (main QRG) - // - // R3: 10130 - 10150 DM NB(<2000Hz) - // - // 10139.25 OLIVIA, Contestia, etc. - // 10142 PSK31 - // 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 - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS - // 14101 - 14112 DM NB(<2700Hz) ACDS - // - // 14070 PSK31 - // 14074.4 OLIVIA, Contestia, etc. - // 14075.4 OLIVIA, Contestia, etc. (main QRG) - // 14078.4 OLIVIA, Contestia, etc. - // 14100 NCDXF beacons - // 14105.5 OLIVIA 1000 - // 14106.5 OLIVIA 1000 (main QRG) - // - // R2: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS - // 14101 - 14112 DM NB(<2700Hz) ACDS - // - // 14070 - 14095 RTTY - // 14070 PSK31 - // 14074.4 OLIVIA, Contestia, etc. - // 14075.4 OLIVIA, Contestia, etc. (main QRG) - // 14078.4 OLIVIA, Contestia, etc. - // 14095 - 14099.5 Packet - // 14100 NCDXF beacons - // 14100.5 - 14112 Packet - // 14105.5 OLIVIA 1000 - // 14106.5 OLIVIA 1000 (main QRG) - // - // R3: 14070 - 14112 DM NB(<2000Hz) with ±500Hz IBP guard band at 14100 - // - // 14070 PSK31 - // 14074.4 OLIVIA, Contestia, etc. - // 14075.4 OLIVIA, Contestia, etc. (main QRG) - // 14078.4 OLIVIA, Contestia, etc. - // 14100 NCDXF beacons - // 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 - - // Band plans (all USB dial unless stated otherwise) - // - // R1: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS - // 18111 - 18120 DM NB(<2700Hz) ACDS - // - // 18100 PSK31 - // 18103.4 OLIVIA, Contestia, etc. (main QRG) - // 18104.4 OLIVIA, Contestia, etc. - // 18110 NCDXF beacons - // - // R2: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS - // 18111 - 18120 DM NB(<2700Hz) ACDS - // - // 18100 - 18105 RTTY - // 18100 PSK31 - // 18103.4 OLIVIA, Contestia, etc. (main QRG) - // 18104.4 OLIVIA, Contestia, etc. - // 18105 - 18110 Packet - // 18110 NCDXF beacons - // - // R3: 18095 - 18120 DM NB(<2000Hz) with ±500Hz IBP guard band at 18110 - // - // 18100 PSK31 - // 18103.4 OLIVIA, Contestia, etc. (main QRG) - // 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}, - - {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}, - - {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}, - - {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}, - - {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}, - - {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}, - - {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}, - - {222065000, Modes::Echo, IARURegions::R2}, - {222065000, Modes::JT65, IARURegions::R2}, - {222065000, Modes::Q65, IARURegions::R2}, - - {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}, - - {902065000, Modes::JT65, IARURegions::R2}, - {902065000, Modes::Q65, IARURegions::R2}, - - {1296065000, Modes::Echo, IARURegions::ALL}, - {1296065000, Modes::JT65, IARURegions::ALL}, - {1296500000, Modes::WSPR, IARURegions::ALL}, - {1296065000, Modes::Q65, IARURegions::ALL}, - - {2301000000, Modes::Echo, IARURegions::ALL}, - {2301065000, Modes::JT4, IARURegions::ALL}, - {2301065000, Modes::JT65, IARURegions::ALL}, - {2301065000, Modes::Q65, IARURegions::ALL}, - - {2304065000, Modes::Echo, IARURegions::ALL}, - {2304065000, Modes::JT4, IARURegions::ALL}, - {2304065000, Modes::JT65, IARURegions::ALL}, - {2304065000, Modes::Q65, IARURegions::ALL}, - - {2320065000, Modes::Echo, IARURegions::ALL}, - {2320065000, Modes::JT4, IARURegions::ALL}, - {2320065000, Modes::JT65, IARURegions::ALL}, - {2320065000, Modes::Q65, IARURegions::ALL}, - - {3400065000, Modes::Echo, IARURegions::ALL}, - {3400065000, Modes::JT4, IARURegions::ALL}, - {3400065000, Modes::JT65, IARURegions::ALL}, - {3400065000, Modes::Q65, IARURegions::ALL}, - - {5760065000, Modes::Echo, IARURegions::ALL}, - {5760065000, Modes::JT4, IARURegions::ALL}, - {5760065000, Modes::JT65, IARURegions::ALL}, - {5760200000, Modes::Q65, IARURegions::ALL}, - - {10368100000, Modes::Echo, IARURegions::ALL}, - {10368200000, Modes::JT4, IARURegions::ALL}, - {10368200000, Modes::Q65, IARURegions::ALL}, - - {24048100000, Modes::Echo, IARURegions::ALL}, - {24048200000, Modes::JT4, IARURegions::ALL}, - {24048200000, Modes::Q65, IARURegions::ALL}, - }; -} - -#if !defined (QT_NO_DEBUG_STREAM) -QDebug operator << (QDebug debug, FrequencyList_v2::Item const& item) -{ - QDebugStateSaver saver {debug}; - return debug.nospace () << item.toString (); -} -#endif - -QString FrequencyList_v2::Item::toString () const -{ - QString string; - QTextStream qts {&string}; - qts << "FrequencyItem(" - << Radio::frequency_MHz_string (frequency_) << ", " - << IARURegions::name (region_) << ", " - << Modes::name (mode_) << ')'; - return string; -} - -QDataStream& operator << (QDataStream& os, FrequencyList_v2::Item const& item) -{ - return os << item.frequency_ - << item.mode_ - << item.region_; -} - -QDataStream& operator >> (QDataStream& is, FrequencyList_v2::Item& item) -{ - return is >> item.frequency_ - >> item.mode_ - >> item.region_; -} - -class FrequencyList_v2::impl final - : public QAbstractTableModel -{ -public: - impl (Bands const * bands, QObject * parent) - : QAbstractTableModel {parent} - , bands_ {bands} - , region_filter_ {IARURegions::ALL} - , mode_filter_ {Modes::ALL} - { - } - - FrequencyItems frequency_list (FrequencyItems); - QModelIndex add (Item); - void add (FrequencyItems); - - // Implement the QAbstractTableModel interface - int rowCount (QModelIndex const& parent = QModelIndex {}) const override; - int columnCount (QModelIndex const& parent = QModelIndex {}) const override; - Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; - QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; - bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override; - QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; - bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; - bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; - QStringList mimeTypes () const override; - QMimeData * mimeData (QModelIndexList const&) const override; - - static int constexpr num_cols {SENTINAL}; - static auto constexpr mime_type = "application/wsjt.Frequencies"; - - Bands const * bands_; - FrequencyItems frequency_list_; - Region region_filter_; - Mode mode_filter_; -}; - -FrequencyList_v2::FrequencyList_v2 (Bands const * bands, QObject * parent) - : QSortFilterProxyModel {parent} - , m_ {bands, parent} -{ - setSourceModel (&*m_); - setSortRole (SortRole); -} - -FrequencyList_v2::~FrequencyList_v2 () -{ -} - -auto FrequencyList_v2::frequency_list (FrequencyItems frequency_list) -> FrequencyItems -{ - return m_->frequency_list (frequency_list); -} - -auto FrequencyList_v2::frequency_list () const -> FrequencyItems const& -{ - return m_->frequency_list_; -} - -auto FrequencyList_v2::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_v2::frequency_list_merge (FrequencyItems const& items) -{ - m_->add (items); -} - -int FrequencyList_v2::best_working_frequency (Frequency f) const -{ - int result {-1}; - auto const& target_band = m_->bands_->find (f); - if (!target_band.isEmpty ()) - { - Radio::FrequencyDelta delta {std::numeric_limits::max ()}; - // find a frequency in the same band that is allowed - for (int row = 0; row < rowCount (); ++row) - { - auto const& source_row = mapToSource (index (row, 0)).row (); - auto const& candidate_frequency = m_->frequency_list_[source_row].frequency_; - auto const& band = m_->bands_->find (candidate_frequency); - if (band == target_band) - { - // take closest band match - Radio::FrequencyDelta new_delta = f - candidate_frequency; - if (std::abs (new_delta) < std::abs (delta)) - { - delta = new_delta; - result = row; - } - } - } - } - return result; -} - -int FrequencyList_v2::best_working_frequency (QString const& target_band) const -{ - int result {-1}; - if (!target_band.isEmpty ()) - { - // find a frequency in the same band that is allowed - for (int row = 0; row < rowCount (); ++row) - { - auto const& source_row = mapToSource (index (row, 0)).row (); - auto const& band = m_->bands_->find (m_->frequency_list_[source_row].frequency_); - if (band == target_band) - { - return row; - } - } - } - return result; -} - -void FrequencyList_v2::reset_to_defaults () -{ - m_->frequency_list (default_frequency_list); -} - -QModelIndex FrequencyList_v2::add (Item f) -{ - return mapFromSource (m_->add (f)); -} - -bool FrequencyList_v2::remove (Item f) -{ - auto row = m_->frequency_list_.indexOf (f); - - if (0 > row) - { - return false; - } - - return m_->removeRow (row); -} - -bool FrequencyList_v2::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. - for (int r = 0; r < rows.size (); ++r) - { - rows[r] = mapToSource (rows[r]); - } - - // reverse sort by row - std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) - { - return rhs.row () < lhs.row (); // reverse row ordering - }); - Q_FOREACH (auto index, rows) - { - if (result && !m_->removeRow (index.row ())) - { - result = false; - } - } - return result; -} - -void FrequencyList_v2::filter (Region region, Mode mode) -{ - m_->region_filter_ = region; - m_->mode_filter_ = mode; - invalidateFilter (); -} - -bool FrequencyList_v2::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const -{ - bool result {true}; - auto const& item = m_->frequency_list_[source_row]; - if (m_->region_filter_ != IARURegions::ALL) - { - result = IARURegions::ALL == item.region_ || m_->region_filter_ == item.region_; - } - 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_; - } - return result; -} - - -auto FrequencyList_v2::impl::frequency_list (FrequencyItems frequency_list) -> FrequencyItems -{ - beginResetModel (); - std::swap (frequency_list_, frequency_list); - endResetModel (); - return frequency_list; -} - -// add a frequency returning the new model index -QModelIndex FrequencyList_v2::impl::add (Item f) -{ - // Any Frequency that isn't in the list may be added - if (!frequency_list_.contains (f)) - { - auto row = frequency_list_.size (); - - beginInsertRows (QModelIndex {}, row, row); - frequency_list_.append (f); - endInsertRows (); - - return index (row, 0); - } - return QModelIndex {}; -} - -void FrequencyList_v2::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_v2::impl::rowCount (QModelIndex const& parent) const -{ - return parent.isValid () ? 0 : frequency_list_.size (); -} - -int FrequencyList_v2::impl::columnCount (QModelIndex const& parent) const -{ - return parent.isValid () ? 0 : num_cols; -} - -Qt::ItemFlags FrequencyList_v2::impl::flags (QModelIndex const& index) const -{ - auto result = QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; - auto row = index.row (); - auto column = index.column (); - if (index.isValid () - && row < frequency_list_.size () - && column < num_cols) - { - if (frequency_mhz_column != column) - { - result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; - } - } - return result; -} - -QVariant FrequencyList_v2::impl::data (QModelIndex const& index, int role) const -{ - QVariant item; - - auto const& row = index.row (); - auto const& column = index.column (); - - if (index.isValid () - && row < frequency_list_.size () - && column < num_cols) - { - auto const& frequency_item = frequency_list_.at (row); - 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: - switch (role) - { - case SortRole: - case Qt::DisplayRole: - case Qt::EditRole: - case Qt::AccessibleTextRole: - item = Modes::name (frequency_item.mode_); - break; - - case Qt::ToolTipRole: - case Qt::AccessibleDescriptionRole: - item = tr ("Mode"); - break; - - case Qt::TextAlignmentRole: - item = Qt::AlignHCenter + Qt::AlignVCenter; - break; - } - break; - - case frequency_column: - switch (role) - { - case SortRole: - case Qt::EditRole: - case Qt::AccessibleTextRole: - item = frequency_item.frequency_; - break; - - 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) + ')'; - } - break; - - case Qt::ToolTipRole: - case Qt::AccessibleDescriptionRole: - item = tr ("Frequency"); - break; - - case Qt::TextAlignmentRole: - item = Qt::AlignRight + Qt::AlignVCenter; - break; - } - break; - - case frequency_mhz_column: - switch (role) - { - case Qt::EditRole: - case Qt::AccessibleTextRole: - item = Radio::frequency_MHz_string (frequency_item.frequency_); - break; - - 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) + ')'; - } - break; - - case Qt::ToolTipRole: - case Qt::AccessibleDescriptionRole: - item = tr ("Frequency (MHz)"); - break; - - case Qt::TextAlignmentRole: - item = Qt::AlignRight + Qt::AlignVCenter; - break; - } - break; - } - } - return item; -} - -bool FrequencyList_v2::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) -{ - bool changed {false}; - - auto const& row = model_index.row (); - if (model_index.isValid () - && Qt::EditRole == role - && row < frequency_list_.size ()) - { - QVector roles; - roles << role; - - auto& item = frequency_list_[row]; - 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 ()) - { - 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; - } - } - - return changed; -} - -QVariant FrequencyList_v2::impl::headerData (int section, Qt::Orientation orientation, int role) const -{ - QVariant header; - if (Qt::DisplayRole == role - && Qt::Horizontal == orientation - && section < num_cols) - { - 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; - } - } - else - { - header = QAbstractTableModel::headerData (section, orientation, role); - } - return header; -} - -bool FrequencyList_v2::impl::removeRows (int row, int count, QModelIndex const& parent) -{ - if (0 < count && (row + count) <= rowCount (parent)) - { - beginRemoveRows (parent, row, row + count - 1); - for (auto r = 0; r < count; ++r) - { - frequency_list_.removeAt (row); - } - endRemoveRows (); - return true; - } - return false; -} - -bool FrequencyList_v2::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}); - } - endInsertRows (); - return true; - } - return false; -} - -QStringList FrequencyList_v2::impl::mimeTypes () const -{ - QStringList types; - types << mime_type; - return types; -} - -QMimeData * FrequencyList_v2::impl::mimeData (QModelIndexList const& items) const -{ - QMimeData * mime_data = new QMimeData {}; - QByteArray encoded_data; - QDataStream stream {&encoded_data, QIODevice::WriteOnly}; - - Q_FOREACH (auto const& item, items) - { - if (item.isValid () && frequency_column == item.column ()) - { - stream << frequency_list_.at (item.row ()); - } - } - - mime_data->setData (mime_type, encoded_data); - return mime_data; -} - -auto FrequencyList_v2::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 * -{ - return &parent_->frequency_list ().at(parent_->mapToSource (parent_->index (row_, 0)).row ()); -} - -bool FrequencyList_v2::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 -{ - return parent_ == rhs.parent_ && row_ == rhs.row_; -} - -auto FrequencyList_v2::const_iterator::operator ++ () -> const_iterator& -{ - ++row_; - return *this; -} - -auto FrequencyList_v2::begin () const -> const_iterator -{ - return const_iterator (this, 0); -} - -auto FrequencyList_v2::end () const -> const_iterator -{ - return const_iterator (this, rowCount ()); -} - -auto FrequencyList_v2::find (Frequency f) const -> const_iterator -{ - int row {0}; - for (; row < rowCount (); ++row) - { - if (m_->frequency_list_[mapToSource (index (row, 0)).row ()].frequency_ == f) - { - break; - } - } - return const_iterator (this, row); -} - -auto FrequencyList_v2::filtered_bands () const -> BandSet -{ - BandSet result; - for (auto const& item : *this) - { - result << m_->bands_->find (item.frequency_); - } - return result; -} - -auto FrequencyList_v2::all_bands (Region region, Mode mode) const -> BandSet -{ - BandSet result; - for (auto const& item : m_->frequency_list_) - { - // Match frequencies that are for all regions, for the specified - // region (which can also be "all"), and where the mode matches - // the specified mode (which can also be "all"). - if ((region == IARURegions::ALL || item.region_ == IARURegions::ALL || item.region_ == region) - && (mode == Modes::ALL || item.mode_ == Modes::ALL || item.mode_ == mode)) - { - result << m_->bands_->find (item.frequency_); - } - } - return result; -} - -// -// Obsolete version of FrequencyList no longer used but needed to -// allow loading and saving of old settings contents without damage -// -QDataStream& operator << (QDataStream& os, FrequencyList::Item const& item) -{ - return os << item.frequency_ - << item.mode_; -} - -QDataStream& operator >> (QDataStream& is, FrequencyList::Item& item) -{ - return is >> item.frequency_ - >> item.mode_; -} From 9d90ede3def8766c128828da8907e3432c5f4ec4 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Sat, 9 Jul 2022 12:43:49 +0200 Subject: [PATCH 18/28] Revert "Fix a problem with backward compatibility, part 1." This reverts commit 4822b943508f49f5093fc276ee463d043feb8c9a. --- models/FrequencyList.cpp | 994 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 994 insertions(+) create mode 100644 models/FrequencyList.cpp diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp new file mode 100644 index 000000000..cac85ea5a --- /dev/null +++ b/models/FrequencyList.cpp @@ -0,0 +1,994 @@ +#include "FrequencyList.hpp" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Radio.hpp" +#include "Bands.hpp" +#include "pimpl_impl.hpp" + +#include "moc_FrequencyList.cpp" + +namespace +{ + FrequencyList_v2::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 + + {660000, Modes::FreqCal, IARURegions::R2}, + {880000, Modes::FreqCal, IARURegions::R2}, + {1210000, Modes::FreqCal, IARURegions::R2}, + + {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}, + + {136000, Modes::WSPR, IARURegions::ALL}, + {136000, Modes::FST4, IARURegions::ALL}, + {136000, Modes::FST4W, IARURegions::ALL}, + {136000, Modes::JT9, IARURegions::ALL}, + + {474200, Modes::JT9, IARURegions::ALL}, + {474200, Modes::FST4, IARURegions::ALL}, + {474200, Modes::WSPR, IARURegions::ALL}, + {474200, Modes::FST4W, IARURegions::ALL}, + + {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}, + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 3570 - 3580 DM NB(<200Hz) + // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS + // + // 3577.75 OLIVIA, Contestia, etc. + // 3580 PSK31 + // 3583.25 OLIVIA, Contestia, etc. + // + // R2: 3570 - 3580 DM NB(<200Hz) + // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS + // + // 3577.75 OLIVIA, Contestia, etc. + // 3580 PSK31 + // 3583.25 OLIVIA, Contestia, etc. + // 3590 RTTY DX + // 3596 W1AW DM QST + // + // R3: 3535 - 3580 DM NB(<2000Hz) + // + // 3520 - 3575 DM NB(<2000Hz) JA 3535 - 3575 shared with all modes + // + // 3522 OLIVIA, Contestia, etc. + // 3535 JA LSB EMCOMM + // 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 + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS + // 7050 - 7060 DM WB(<2700Hz) with 7050 - 7053 ACDS + // + // 7040 PSK31 + // 7043.25 OLIVIA, Contestia, etc. (main QRG) + // 7070 PSK31 + // 7073.25 OLIVIA, Contestia, etc. (main QRG) + // 7090 LSB QRP CoA + // + // R2: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS + // 7050 - 7053 DM WB(<2700Hz) ACDS shared with all modes + // + // 7040 RTTY DX + // 7043.25 OLIVIA, Contestia, etc. (main QRG) + // 7070 PSK31 (also LSB EMCOMM) + // 7073.25 OLIVIA, Contestia, etc. (main QRG) + // 7080 - 7125 RTTY/Data + // 7090 LSB QRP CoA + // + // R3: 7030 - 7060 DM NB(<2000Hz) with 7040 - 7060 NB DX all shared with phone + // + // 7030 - 7100 DM WB(<3000Hz) JA 7045 - 7100 shared with all modes + // + // 7026.25 OLIVIA, Contestia, etc. (main QRG) + // 7035 PSK31 + // 7050 JA LSB EMCOMM + // 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 + // up 500Hz to clear + // W1AW code practice QRG + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 10130 - 10150 DM NB(<500Hz) with 10120 - 10140 shared with phone in southern Africa + // + // 10139.25 OLIVIA, Contestia, etc. + // 10142 PSK31 + // 10142.25 OLIVIA, Contestia, etc. + // 10143.25 OLIVIA, Contestia, etc. (main QRG) + // + // R2: 10130 - 10140 DM NB(<500Hz) shared with ACDS + // 10140 - 10150 DM WB(<2700Hz) + // + // 10130 - 10140 RTTY + // 10139.25 OLIVIA, Contestia, etc. + // 10140 - 10150 Packet + // 10142 PSK31 + // 10142.25 OLIVIA, Contestia, etc. + // 10143.25 OLIVIA, Contestia, etc. (main QRG) + // + // R3: 10130 - 10150 DM NB(<2000Hz) + // + // 10139.25 OLIVIA, Contestia, etc. + // 10142 PSK31 + // 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 + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS + // 14101 - 14112 DM NB(<2700Hz) ACDS + // + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14100 NCDXF beacons + // 14105.5 OLIVIA 1000 + // 14106.5 OLIVIA 1000 (main QRG) + // + // R2: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS + // 14101 - 14112 DM NB(<2700Hz) ACDS + // + // 14070 - 14095 RTTY + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14095 - 14099.5 Packet + // 14100 NCDXF beacons + // 14100.5 - 14112 Packet + // 14105.5 OLIVIA 1000 + // 14106.5 OLIVIA 1000 (main QRG) + // + // R3: 14070 - 14112 DM NB(<2000Hz) with ±500Hz IBP guard band at 14100 + // + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14100 NCDXF beacons + // 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 + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS + // 18111 - 18120 DM NB(<2700Hz) ACDS + // + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 18104.4 OLIVIA, Contestia, etc. + // 18110 NCDXF beacons + // + // R2: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS + // 18111 - 18120 DM NB(<2700Hz) ACDS + // + // 18100 - 18105 RTTY + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 18104.4 OLIVIA, Contestia, etc. + // 18105 - 18110 Packet + // 18110 NCDXF beacons + // + // R3: 18095 - 18120 DM NB(<2000Hz) with ±500Hz IBP guard band at 18110 + // + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 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}, + + {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}, + + {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}, + + {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}, + + {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}, + + {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}, + + {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}, + + {222065000, Modes::Echo, IARURegions::R2}, + {222065000, Modes::JT65, IARURegions::R2}, + {222065000, Modes::Q65, IARURegions::R2}, + + {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}, + + {902065000, Modes::JT65, IARURegions::R2}, + {902065000, Modes::Q65, IARURegions::R2}, + + {1296065000, Modes::Echo, IARURegions::ALL}, + {1296065000, Modes::JT65, IARURegions::ALL}, + {1296500000, Modes::WSPR, IARURegions::ALL}, + {1296065000, Modes::Q65, IARURegions::ALL}, + + {2301000000, Modes::Echo, IARURegions::ALL}, + {2301065000, Modes::JT4, IARURegions::ALL}, + {2301065000, Modes::JT65, IARURegions::ALL}, + {2301065000, Modes::Q65, IARURegions::ALL}, + + {2304065000, Modes::Echo, IARURegions::ALL}, + {2304065000, Modes::JT4, IARURegions::ALL}, + {2304065000, Modes::JT65, IARURegions::ALL}, + {2304065000, Modes::Q65, IARURegions::ALL}, + + {2320065000, Modes::Echo, IARURegions::ALL}, + {2320065000, Modes::JT4, IARURegions::ALL}, + {2320065000, Modes::JT65, IARURegions::ALL}, + {2320065000, Modes::Q65, IARURegions::ALL}, + + {3400065000, Modes::Echo, IARURegions::ALL}, + {3400065000, Modes::JT4, IARURegions::ALL}, + {3400065000, Modes::JT65, IARURegions::ALL}, + {3400065000, Modes::Q65, IARURegions::ALL}, + + {5760065000, Modes::Echo, IARURegions::ALL}, + {5760065000, Modes::JT4, IARURegions::ALL}, + {5760065000, Modes::JT65, IARURegions::ALL}, + {5760200000, Modes::Q65, IARURegions::ALL}, + + {10368100000, Modes::Echo, IARURegions::ALL}, + {10368200000, Modes::JT4, IARURegions::ALL}, + {10368200000, Modes::Q65, IARURegions::ALL}, + + {24048100000, Modes::Echo, IARURegions::ALL}, + {24048200000, Modes::JT4, IARURegions::ALL}, + {24048200000, Modes::Q65, IARURegions::ALL}, + }; +} + +#if !defined (QT_NO_DEBUG_STREAM) +QDebug operator << (QDebug debug, FrequencyList_v2::Item const& item) +{ + QDebugStateSaver saver {debug}; + return debug.nospace () << item.toString (); +} +#endif + +QString FrequencyList_v2::Item::toString () const +{ + QString string; + QTextStream qts {&string}; + qts << "FrequencyItem(" + << Radio::frequency_MHz_string (frequency_) << ", " + << IARURegions::name (region_) << ", " + << Modes::name (mode_) << ')'; + return string; +} + +QDataStream& operator << (QDataStream& os, FrequencyList_v2::Item const& item) +{ + return os << item.frequency_ + << item.mode_ + << item.region_; +} + +QDataStream& operator >> (QDataStream& is, FrequencyList_v2::Item& item) +{ + return is >> item.frequency_ + >> item.mode_ + >> item.region_; +} + +class FrequencyList_v2::impl final + : public QAbstractTableModel +{ +public: + impl (Bands const * bands, QObject * parent) + : QAbstractTableModel {parent} + , bands_ {bands} + , region_filter_ {IARURegions::ALL} + , mode_filter_ {Modes::ALL} + { + } + + FrequencyItems frequency_list (FrequencyItems); + QModelIndex add (Item); + void add (FrequencyItems); + + // Implement the QAbstractTableModel interface + int rowCount (QModelIndex const& parent = QModelIndex {}) const override; + int columnCount (QModelIndex const& parent = QModelIndex {}) const override; + Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; + QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; + bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override; + QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; + bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; + bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; + QStringList mimeTypes () const override; + QMimeData * mimeData (QModelIndexList const&) const override; + + static int constexpr num_cols {SENTINAL}; + static auto constexpr mime_type = "application/wsjt.Frequencies"; + + Bands const * bands_; + FrequencyItems frequency_list_; + Region region_filter_; + Mode mode_filter_; +}; + +FrequencyList_v2::FrequencyList_v2 (Bands const * bands, QObject * parent) + : QSortFilterProxyModel {parent} + , m_ {bands, parent} +{ + setSourceModel (&*m_); + setSortRole (SortRole); +} + +FrequencyList_v2::~FrequencyList_v2 () +{ +} + +auto FrequencyList_v2::frequency_list (FrequencyItems frequency_list) -> FrequencyItems +{ + return m_->frequency_list (frequency_list); +} + +auto FrequencyList_v2::frequency_list () const -> FrequencyItems const& +{ + return m_->frequency_list_; +} + +auto FrequencyList_v2::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_v2::frequency_list_merge (FrequencyItems const& items) +{ + m_->add (items); +} + +int FrequencyList_v2::best_working_frequency (Frequency f) const +{ + int result {-1}; + auto const& target_band = m_->bands_->find (f); + if (!target_band.isEmpty ()) + { + Radio::FrequencyDelta delta {std::numeric_limits::max ()}; + // find a frequency in the same band that is allowed + for (int row = 0; row < rowCount (); ++row) + { + auto const& source_row = mapToSource (index (row, 0)).row (); + auto const& candidate_frequency = m_->frequency_list_[source_row].frequency_; + auto const& band = m_->bands_->find (candidate_frequency); + if (band == target_band) + { + // take closest band match + Radio::FrequencyDelta new_delta = f - candidate_frequency; + if (std::abs (new_delta) < std::abs (delta)) + { + delta = new_delta; + result = row; + } + } + } + } + return result; +} + +int FrequencyList_v2::best_working_frequency (QString const& target_band) const +{ + int result {-1}; + if (!target_band.isEmpty ()) + { + // find a frequency in the same band that is allowed + for (int row = 0; row < rowCount (); ++row) + { + auto const& source_row = mapToSource (index (row, 0)).row (); + auto const& band = m_->bands_->find (m_->frequency_list_[source_row].frequency_); + if (band == target_band) + { + return row; + } + } + } + return result; +} + +void FrequencyList_v2::reset_to_defaults () +{ + m_->frequency_list (default_frequency_list); +} + +QModelIndex FrequencyList_v2::add (Item f) +{ + return mapFromSource (m_->add (f)); +} + +bool FrequencyList_v2::remove (Item f) +{ + auto row = m_->frequency_list_.indexOf (f); + + if (0 > row) + { + return false; + } + + return m_->removeRow (row); +} + +bool FrequencyList_v2::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. + for (int r = 0; r < rows.size (); ++r) + { + rows[r] = mapToSource (rows[r]); + } + + // reverse sort by row + std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) + { + return rhs.row () < lhs.row (); // reverse row ordering + }); + Q_FOREACH (auto index, rows) + { + if (result && !m_->removeRow (index.row ())) + { + result = false; + } + } + return result; +} + +void FrequencyList_v2::filter (Region region, Mode mode) +{ + m_->region_filter_ = region; + m_->mode_filter_ = mode; + invalidateFilter (); +} + +bool FrequencyList_v2::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const +{ + bool result {true}; + auto const& item = m_->frequency_list_[source_row]; + if (m_->region_filter_ != IARURegions::ALL) + { + result = IARURegions::ALL == item.region_ || m_->region_filter_ == item.region_; + } + 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_; + } + return result; +} + + +auto FrequencyList_v2::impl::frequency_list (FrequencyItems frequency_list) -> FrequencyItems +{ + beginResetModel (); + std::swap (frequency_list_, frequency_list); + endResetModel (); + return frequency_list; +} + +// add a frequency returning the new model index +QModelIndex FrequencyList_v2::impl::add (Item f) +{ + // Any Frequency that isn't in the list may be added + if (!frequency_list_.contains (f)) + { + auto row = frequency_list_.size (); + + beginInsertRows (QModelIndex {}, row, row); + frequency_list_.append (f); + endInsertRows (); + + return index (row, 0); + } + return QModelIndex {}; +} + +void FrequencyList_v2::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_v2::impl::rowCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : frequency_list_.size (); +} + +int FrequencyList_v2::impl::columnCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : num_cols; +} + +Qt::ItemFlags FrequencyList_v2::impl::flags (QModelIndex const& index) const +{ + auto result = QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; + auto row = index.row (); + auto column = index.column (); + if (index.isValid () + && row < frequency_list_.size () + && column < num_cols) + { + if (frequency_mhz_column != column) + { + result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; + } + } + return result; +} + +QVariant FrequencyList_v2::impl::data (QModelIndex const& index, int role) const +{ + QVariant item; + + auto const& row = index.row (); + auto const& column = index.column (); + + if (index.isValid () + && row < frequency_list_.size () + && column < num_cols) + { + auto const& frequency_item = frequency_list_.at (row); + 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: + switch (role) + { + case SortRole: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = Modes::name (frequency_item.mode_); + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Mode"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignHCenter + Qt::AlignVCenter; + break; + } + break; + + case frequency_column: + switch (role) + { + case SortRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = frequency_item.frequency_; + break; + + 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) + ')'; + } + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Frequency"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignRight + Qt::AlignVCenter; + break; + } + break; + + case frequency_mhz_column: + switch (role) + { + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = Radio::frequency_MHz_string (frequency_item.frequency_); + break; + + 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) + ')'; + } + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Frequency (MHz)"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignRight + Qt::AlignVCenter; + break; + } + break; + } + } + return item; +} + +bool FrequencyList_v2::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) +{ + bool changed {false}; + + auto const& row = model_index.row (); + if (model_index.isValid () + && Qt::EditRole == role + && row < frequency_list_.size ()) + { + QVector roles; + roles << role; + + auto& item = frequency_list_[row]; + 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 ()) + { + 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; + } + } + + return changed; +} + +QVariant FrequencyList_v2::impl::headerData (int section, Qt::Orientation orientation, int role) const +{ + QVariant header; + if (Qt::DisplayRole == role + && Qt::Horizontal == orientation + && section < num_cols) + { + 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; + } + } + else + { + header = QAbstractTableModel::headerData (section, orientation, role); + } + return header; +} + +bool FrequencyList_v2::impl::removeRows (int row, int count, QModelIndex const& parent) +{ + if (0 < count && (row + count) <= rowCount (parent)) + { + beginRemoveRows (parent, row, row + count - 1); + for (auto r = 0; r < count; ++r) + { + frequency_list_.removeAt (row); + } + endRemoveRows (); + return true; + } + return false; +} + +bool FrequencyList_v2::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}); + } + endInsertRows (); + return true; + } + return false; +} + +QStringList FrequencyList_v2::impl::mimeTypes () const +{ + QStringList types; + types << mime_type; + return types; +} + +QMimeData * FrequencyList_v2::impl::mimeData (QModelIndexList const& items) const +{ + QMimeData * mime_data = new QMimeData {}; + QByteArray encoded_data; + QDataStream stream {&encoded_data, QIODevice::WriteOnly}; + + Q_FOREACH (auto const& item, items) + { + if (item.isValid () && frequency_column == item.column ()) + { + stream << frequency_list_.at (item.row ()); + } + } + + mime_data->setData (mime_type, encoded_data); + return mime_data; +} + +auto FrequencyList_v2::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 * +{ + return &parent_->frequency_list ().at(parent_->mapToSource (parent_->index (row_, 0)).row ()); +} + +bool FrequencyList_v2::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 +{ + return parent_ == rhs.parent_ && row_ == rhs.row_; +} + +auto FrequencyList_v2::const_iterator::operator ++ () -> const_iterator& +{ + ++row_; + return *this; +} + +auto FrequencyList_v2::begin () const -> const_iterator +{ + return const_iterator (this, 0); +} + +auto FrequencyList_v2::end () const -> const_iterator +{ + return const_iterator (this, rowCount ()); +} + +auto FrequencyList_v2::find (Frequency f) const -> const_iterator +{ + int row {0}; + for (; row < rowCount (); ++row) + { + if (m_->frequency_list_[mapToSource (index (row, 0)).row ()].frequency_ == f) + { + break; + } + } + return const_iterator (this, row); +} + +auto FrequencyList_v2::filtered_bands () const -> BandSet +{ + BandSet result; + for (auto const& item : *this) + { + result << m_->bands_->find (item.frequency_); + } + return result; +} + +auto FrequencyList_v2::all_bands (Region region, Mode mode) const -> BandSet +{ + BandSet result; + for (auto const& item : m_->frequency_list_) + { + // Match frequencies that are for all regions, for the specified + // region (which can also be "all"), and where the mode matches + // the specified mode (which can also be "all"). + if ((region == IARURegions::ALL || item.region_ == IARURegions::ALL || item.region_ == region) + && (mode == Modes::ALL || item.mode_ == Modes::ALL || item.mode_ == mode)) + { + result << m_->bands_->find (item.frequency_); + } + } + return result; +} + +// +// Obsolete version of FrequencyList no longer used but needed to +// allow loading and saving of old settings contents without damage +// +QDataStream& operator << (QDataStream& os, FrequencyList::Item const& item) +{ + return os << item.frequency_ + << item.mode_; +} + +QDataStream& operator >> (QDataStream& is, FrequencyList::Item& item) +{ + return is >> item.frequency_ + >> item.mode_; +} From 31696388b958f8f8c14ffab33a90c5b0088ac1c8 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Sat, 9 Jul 2022 12:45:46 +0200 Subject: [PATCH 19/28] Revert "Set the 4m FT8 default frequency for Region 1 to 70,154 MHz." This reverts commit 43cd871413a1b1985d43519786ef31aeab0b0f3d. --- models/FrequencyList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp index cac85ea5a..034af8951 100644 --- a/models/FrequencyList.cpp +++ b/models/FrequencyList.cpp @@ -278,10 +278,10 @@ namespace {50318000, Modes::FT4, IARURegions::ALL}, // provisional {50323000, Modes::FT8, IARURegions::ALL}, + {70100000, Modes::FT8, IARURegions::R1}, {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}, {144116000, Modes::Q65, IARURegions::ALL}, From d81a3d799c4e92ac023b2c53c92e587390b9af86 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Sat, 9 Jul 2022 12:48:26 +0200 Subject: [PATCH 20/28] Set the 4m FT8 default frequency for Region 1 to 70,154 MHz. --- models/FrequencyList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp index 034af8951..cac85ea5a 100644 --- a/models/FrequencyList.cpp +++ b/models/FrequencyList.cpp @@ -278,10 +278,10 @@ namespace {50318000, Modes::FT4, IARURegions::ALL}, // provisional {50323000, Modes::FT8, IARURegions::ALL}, - {70100000, Modes::FT8, IARURegions::R1}, {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}, {144116000, Modes::Q65, IARURegions::ALL}, From 68a534221bc24510eaaf3f48e704cf3ceb414cbb Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Mon, 11 Jul 2022 19:04:05 +0200 Subject: [PATCH 21/28] Fix a typo. --- Release_Notes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release_Notes.txt b/Release_Notes.txt index 2285b2eb7..e69257026 100644 --- a/Release_Notes.txt +++ b/Release_Notes.txt @@ -25,7 +25,7 @@ In program WSJT-X: - Fix VFOB not getting set on some rigs (e.g. IC7610 & IC7100) - - The settings for T/R period and Submode are now remembered by band. + - The settings for T/R period and Submode are now remembered by mode. This is especially helpful for VHF / EME activities, and on HF for FST4. You can now switch directly e.g. between MSK144-15, Q65-60A, JT65-C, FST4-120 or whatever, and wsjt-x_improved remembers all that. From c85ed8cc7d417f43d0e25870ea40f09d50cf020a Mon Sep 17 00:00:00 2001 From: Brian Moran Date: Mon, 11 Jul 2022 15:56:55 -0700 Subject: [PATCH 22/28] show contacts by ID, scroll to insertion when sorted by tha column up or down --- models/CabrilloLog.cpp | 3 ++ widgets/AbstractLogWindow.cpp | 53 ++++++++++++++++++++++------------- widgets/CabrilloLogWindow.cpp | 3 +- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index b0459e190..cb13c0ec3 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -88,6 +88,7 @@ CabrilloLog::impl::impl (CabrilloLog * self, Configuration const * configuration setEditStrategy (QSqlTableModel::OnFieldChange); setTable ("cabrillo_log_v2"); + setHeaderData (fieldIndex ("id"), Qt::Horizontal, tr ("Qso #")); setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(MHz)")); setHeaderData (fieldIndex ("mode"), Qt::Horizontal, tr ("Mode")); setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); @@ -234,8 +235,10 @@ bool CabrilloLog::add_QSO (Frequency frequency, QString const& mode, QDateTime c m_->adding_row_ = true; auto ok = m_->insertRecord (-1, record); transaction.submit (); + m_->adding_row_ = false; m_->setEditStrategy (QSqlTableModel::OnFieldChange); + return ok; } diff --git a/widgets/AbstractLogWindow.cpp b/widgets/AbstractLogWindow.cpp index b8e2d7e7a..020e34bad 100644 --- a/widgets/AbstractLogWindow.cpp +++ b/widgets/AbstractLogWindow.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "Configuration.hpp" #include "SettingsGroup.hpp" #include "MessageBox.hpp" @@ -88,29 +89,37 @@ void AbstractLogWindow::impl::delete_QSOs () } } + AbstractLogWindow::AbstractLogWindow (QString const& settings_key, QSettings * settings , Configuration const * configuration , QWidget * parent) : QWidget {parent} - , m_ {this, settings_key, settings, configuration} -{ - // this attempt to scroll to the last new record doesn't work, some - // sort of issue with model indexes and optimized DB fetches. For - // now sorting by the same column and direction as the underlying DB - // select and that DB select being in descending order so new rows - // at the end appear at view row 0 gets the job done + , m_ {this, settings_key, settings, configuration} { + // when we're viewing the log by contact ID (visually, up/down chevron in the column heading), + // when we add a contact, scroll the list to the top or bottom, depending on the sort order. + // If the table is sorted by some other criteria, don't change anything. - // // ensure view scrolls to latest new row - // connect (&m_->model_, &QAbstractItemModel::rowsInserted, this, [this] (QModelIndex const& parent, int first, int last) { - // // note col 0 is hidden so use col 1 - // // queued connection required otherwise row may not be available - // // in time - // auto index = m_->model_.index (last, 1, parent); - // if (m_->log_view_) - // { - // m_->log_view_->scrollTo (index); - // } - // }, Qt::QueuedConnection); + connect(&m_->model_, &QAbstractItemModel::rowsInserted, this, + [this](QModelIndex const &parent, int first, int last) { + (void) (parent); // UNUSED + (void) (first); // UNUSED + (void) (last); // UNUSED + QTimer::singleShot(0, [=] { + // if we're sorting by the contact #, then show the most-recently logged contact. + // Otherwise, leave the scroll alone + auto horizontal_header = m_->log_view_->horizontalHeader (); + if (horizontal_header->sortIndicatorSection() == 0) { + if (horizontal_header->sortIndicatorOrder() == Qt::AscendingOrder) { + // we're sorting 1->N, so go to bottom + m_->log_view_->scrollToBottom(); + } else { + m_->log_view_->scrollToTop(); + } + } + + }); + } + ); } AbstractLogWindow::~AbstractLogWindow () @@ -134,11 +143,14 @@ void AbstractLogWindow::set_log_view (QTableView * log_view) log_view->setVerticalScrollMode (QAbstractItemView::ScrollPerPixel); m_->model_.setSourceModel (log_view->model ()); log_view->setModel (&m_->model_); - log_view->setColumnHidden (0, true); + log_view->setColumnHidden (0, false); // show the ID column, which is also QSO # auto horizontal_header = log_view->horizontalHeader (); + horizontal_header->setResizeContentsPrecision (0); // visible region only horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); horizontal_header->setSectionsMovable (true); + horizontal_header->setSortIndicator(0,Qt::AscendingOrder); // sort by the contact id. show 1->N + auto vertical_header = log_view->horizontalHeader (); vertical_header->setResizeContentsPrecision (0); // visible region only vertical_header->setSectionResizeMode (QHeaderView::ResizeToContents); @@ -149,6 +161,9 @@ void AbstractLogWindow::set_log_view (QTableView * log_view) connect (delete_action, &QAction::triggered, [this] (bool /*checked*/) { m_->delete_QSOs (); }); + + // scroll to bottom, since we're showing 1-N + log_view->scrollToBottom(); } void AbstractLogWindow::set_log_view_font (QFont const& font) diff --git a/widgets/CabrilloLogWindow.cpp b/widgets/CabrilloLogWindow.cpp index 5c219fcd7..e31ed4700 100644 --- a/widgets/CabrilloLogWindow.cpp +++ b/widgets/CabrilloLogWindow.cpp @@ -70,7 +70,8 @@ CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const m_->ui_.log_table_view->setItemDelegateForColumn (3, new SQLiteDateTimeDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (4, new CallsignDelegate {this}); auto h_header = m_->ui_.log_table_view->horizontalHeader (); - h_header->moveSection (7, 1); // band to first column + m_->ui_.log_table_view->verticalHeader()->setVisible(false); // turn off line numbers for the table, use index + h_header->moveSection (7, 2); // band to 2nd column } CabrilloLogWindow::~CabrilloLogWindow () From cd0a0e6db404daa37b8b0616c1b56c3c9705c4f8 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 13 Jul 2022 14:57:24 -0400 Subject: [PATCH 23/28] Fix a typo. --- models/CabrilloLog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index cb13c0ec3..beab1eb4b 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -88,7 +88,7 @@ CabrilloLog::impl::impl (CabrilloLog * self, Configuration const * configuration setEditStrategy (QSqlTableModel::OnFieldChange); setTable ("cabrillo_log_v2"); - setHeaderData (fieldIndex ("id"), Qt::Horizontal, tr ("Qso #")); + setHeaderData (fieldIndex ("id"), Qt::Horizontal, tr ("QSO #")); setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(MHz)")); setHeaderData (fieldIndex ("mode"), Qt::Horizontal, tr ("Mode")); setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); From a1106aff4621361437f41e22241387c393145a81 Mon Sep 17 00:00:00 2001 From: Brian Moran Date: Wed, 13 Jul 2022 21:36:07 -0700 Subject: [PATCH 24/28] no qso #. When date sorted, move to top or bottom --- models/CabrilloLog.cpp | 1 - widgets/AbstractLogWindow.cpp | 10 +++++----- widgets/CabrilloLogWindow.cpp | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index cb13c0ec3..66c87ebfc 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -88,7 +88,6 @@ CabrilloLog::impl::impl (CabrilloLog * self, Configuration const * configuration setEditStrategy (QSqlTableModel::OnFieldChange); setTable ("cabrillo_log_v2"); - setHeaderData (fieldIndex ("id"), Qt::Horizontal, tr ("Qso #")); setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(MHz)")); setHeaderData (fieldIndex ("mode"), Qt::Horizontal, tr ("Mode")); setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); diff --git a/widgets/AbstractLogWindow.cpp b/widgets/AbstractLogWindow.cpp index 020e34bad..656eff7f1 100644 --- a/widgets/AbstractLogWindow.cpp +++ b/widgets/AbstractLogWindow.cpp @@ -105,12 +105,12 @@ AbstractLogWindow::AbstractLogWindow (QString const& settings_key, QSettings * s (void) (first); // UNUSED (void) (last); // UNUSED QTimer::singleShot(0, [=] { - // if we're sorting by the contact #, then show the most-recently logged contact. + // if we're sorting by the date, then show the most-recently logged contact. // Otherwise, leave the scroll alone auto horizontal_header = m_->log_view_->horizontalHeader (); - if (horizontal_header->sortIndicatorSection() == 0) { + if (horizontal_header->sortIndicatorSection() == 3) { // sorting on date? if (horizontal_header->sortIndicatorOrder() == Qt::AscendingOrder) { - // we're sorting 1->N, so go to bottom + // we're sorting oldes->newest, so go to bottom m_->log_view_->scrollToBottom(); } else { m_->log_view_->scrollToTop(); @@ -143,13 +143,13 @@ void AbstractLogWindow::set_log_view (QTableView * log_view) log_view->setVerticalScrollMode (QAbstractItemView::ScrollPerPixel); m_->model_.setSourceModel (log_view->model ()); log_view->setModel (&m_->model_); - log_view->setColumnHidden (0, false); // show the ID column, which is also QSO # + log_view->setColumnHidden (0, true); // hide the ID column auto horizontal_header = log_view->horizontalHeader (); horizontal_header->setResizeContentsPrecision (0); // visible region only horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); horizontal_header->setSectionsMovable (true); - horizontal_header->setSortIndicator(0,Qt::AscendingOrder); // sort by the contact id. show 1->N + horizontal_header->setSortIndicator(3, Qt::AscendingOrder); // sort by the contact datetime oldest->newest auto vertical_header = log_view->horizontalHeader (); vertical_header->setResizeContentsPrecision (0); // visible region only diff --git a/widgets/CabrilloLogWindow.cpp b/widgets/CabrilloLogWindow.cpp index e31ed4700..16a38ef3d 100644 --- a/widgets/CabrilloLogWindow.cpp +++ b/widgets/CabrilloLogWindow.cpp @@ -70,8 +70,8 @@ CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const m_->ui_.log_table_view->setItemDelegateForColumn (3, new SQLiteDateTimeDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (4, new CallsignDelegate {this}); auto h_header = m_->ui_.log_table_view->horizontalHeader (); - m_->ui_.log_table_view->verticalHeader()->setVisible(false); // turn off line numbers for the table, use index - h_header->moveSection (7, 2); // band to 2nd column + m_->ui_.log_table_view->verticalHeader()->setVisible(false); // turn off line numbers for the table view + h_header->moveSection (7, 1); // band to first column } CabrilloLogWindow::~CabrilloLogWindow () From e1fde92ea26e70c3800e1cf364c71b4e511dca7a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 14 Jul 2022 12:42:55 -0400 Subject: [PATCH 25/28] Try adding a lineEdit to display number of QSOs in the contest log. Not quite right, yet. --- models/CabrilloLog.cpp | 5 +++++ models/CabrilloLog.hpp | 1 + widgets/CabrilloLogWindow.cpp | 7 +++++++ widgets/CabrilloLogWindow.hpp | 1 + widgets/CabrilloLogWindow.ui | 16 ++++++++++++++++ widgets/mainwindow.cpp | 6 ++++++ 6 files changed, 36 insertions(+) diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index 66c87ebfc..b0f467f33 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -258,6 +258,11 @@ bool CabrilloLog::dupe (Frequency frequency, QString const& call) const return false; } +int CabrilloLog::n_qso() +{ + return m_->rowCount(); +} + void CabrilloLog::reset () { // synchronize model diff --git a/models/CabrilloLog.hpp b/models/CabrilloLog.hpp index 97d8f0d88..40c27380d 100644 --- a/models/CabrilloLog.hpp +++ b/models/CabrilloLog.hpp @@ -31,6 +31,7 @@ public: bool add_QSO (Frequency, QString const& mode, QDateTime const&, QString const& call , QString const& report_sent, QString const& report_received); bool dupe (Frequency, QString const& call) const; + int n_qso(); QSqlTableModel * model (); void reset (); diff --git a/widgets/CabrilloLogWindow.cpp b/widgets/CabrilloLogWindow.cpp index 16a38ef3d..3315181a0 100644 --- a/widgets/CabrilloLogWindow.cpp +++ b/widgets/CabrilloLogWindow.cpp @@ -89,3 +89,10 @@ void CabrilloLogWindow::log_model_changed (int row) m_->log_model_->select (); } } + +void CabrilloLogWindow::set_nQSO(int n) +{ + QString t; + t=t.asprintf("%d QSOs",n); + m_->ui_.nQSO_lineEdit->setText(t); +} diff --git a/widgets/CabrilloLogWindow.hpp b/widgets/CabrilloLogWindow.hpp index e2aa1627a..044986620 100644 --- a/widgets/CabrilloLogWindow.hpp +++ b/widgets/CabrilloLogWindow.hpp @@ -16,6 +16,7 @@ public: explicit CabrilloLogWindow (QSettings *, Configuration const *, QSqlTableModel * cabrillo_log_model , QWidget * parent = nullptr); ~CabrilloLogWindow (); + void set_nQSO(int n); private: void log_model_changed (int row) override; diff --git a/widgets/CabrilloLogWindow.ui b/widgets/CabrilloLogWindow.ui index 35b4d597d..1b44d0652 100644 --- a/widgets/CabrilloLogWindow.ui +++ b/widgets/CabrilloLogWindow.ui @@ -27,6 +27,22 @@ + + + + + 100 + 16777215 + + + + 0 QSOs + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 2be90e3c1..7e1609d90 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -1423,6 +1423,7 @@ void MainWindow::setDecodedTextFont (QFont const& font) } if (m_contestLogWindow) { m_contestLogWindow->set_log_view_font (font); + m_contestLogWindow->set_nQSO(m_logBook.contest_log()->n_qso()); } if(m_ActiveStationsWidget != NULL) { m_ActiveStationsWidget->changeFont(font); @@ -2778,6 +2779,7 @@ void MainWindow::on_contest_log_action_triggered() m_contestLogWindow->showNormal (); m_contestLogWindow->raise (); m_contestLogWindow->activateWindow (); + m_contestLogWindow->set_nQSO(m_logBook.contest_log()->n_qso()); } void MainWindow::on_actionColors_triggered() @@ -4676,6 +4678,7 @@ void MainWindow::guiUpdate() //Once per second (onesec) if(nsec != m_sec0) { // qDebug() << "AAA" << nsec; + m_contestLogWindow->set_nQSO(m_logBook.contest_log()->n_qso()); if(m_mode=="FST4") chk_FST4_freq_range(); m_currentBand=m_config.bands()->find(m_freqNominal); @@ -6374,6 +6377,9 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, m_xSent.clear (); m_xRcvd.clear (); + if(m_contestLogWindow) { + m_contestLogWindow->set_nQSO(m_logBook.contest_log()->n_qso()); + } } void MainWindow::updateRate() From e5bf51abf645b7fc5471855408445802f45baba9 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 15 Jul 2022 10:49:26 -0400 Subject: [PATCH 26/28] Update number of logged contest QSOs only if Contet Log has been made visible. --- widgets/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 7e1609d90..8d0aecf42 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -4678,7 +4678,7 @@ void MainWindow::guiUpdate() //Once per second (onesec) if(nsec != m_sec0) { // qDebug() << "AAA" << nsec; - m_contestLogWindow->set_nQSO(m_logBook.contest_log()->n_qso()); + if(m_contestLogWindow) m_contestLogWindow->set_nQSO(m_logBook.contest_log()->n_qso()); if(m_mode=="FST4") chk_FST4_freq_range(); m_currentBand=m_config.bands()->find(m_freqNominal); From a5f963233be55635196c9b76b0433746fd5f25a8 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Fri, 15 Jul 2022 18:18:49 +0200 Subject: [PATCH 27/28] Update release notes and NEWS for v2.6.0-rc2. --- NEWS | 33 +++++++++++++++++++++++++++++++++ Release_Notes.txt | 35 +++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index 580208cfc..ff8f8d39b 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,39 @@ Copyright 2001 - 2022 by Joe Taylor, K1JT, and the WSJT Development Team + Release: WSJT-X 2.6.0-rc2 + July 25, 2022 + ---------------------- + +WSJT-X 2.6.0 Release Candidate 2 brings a number of improvements as +well as some bug fixes. + +In program WSJT-X : + + - Echo-mode now lets the "Measure" function use the computed fspread + for DX grid + + - Fix VFOB not getting set on some rigs (e.g. IC7610 & IC7100) + + - Show contacts by ID in the contest log, scroll to insertion when + sorted by the column up or down + + - Remember the settings for T/R period and Submode by mode; you can now + switch directly e.g. between MSK144-15, Q65-60A, JT65-C, FST4-120 + + - Restore Tx & Rx offset when coming from a mode which sets AF to + 1500 Hz (MSK144, FST4W, Echo, WSPR, FreqCal) and switch back to + FT4, FT8, Q65, JT65, or FST4 + + - Set 4m FT8 default frequency for Region 1 to 70.154 MHz + + - Optimize mode button layout for 4K screens + + - Minor edits to display of Keyboard Shortcuts + + - Fix some bugs + + Release: WSJT-X 2.6.0-rc1 June 16, 2022 ---------------------- diff --git a/Release_Notes.txt b/Release_Notes.txt index e69257026..b5f492d64 100644 --- a/Release_Notes.txt +++ b/Release_Notes.txt @@ -12,33 +12,36 @@ Copyright 2001 - 2022 by Joe Taylor, K1JT, and the WSJT Development Team Release: WSJT-X 2.6.0-rc2 - August 01, 2022 + July 25, 2022 ---------------------- -WSJT-X 2.6.0 Release Candidate 2 brings a number of useful improvements, -and some bug fixes. +WSJT-X 2.6.0 Release Candidate 2 brings a number of improvements as +well as some bug fixes. -In program WSJT-X: +In program WSJT-X : - Echo-mode now lets the "Measure" function use the computed fspread for DX grid - Fix VFOB not getting set on some rigs (e.g. IC7610 & IC7100) - - The settings for T/R period and Submode are now remembered by mode. - This is especially helpful for VHF / EME activities, and on HF for - FST4. You can now switch directly e.g. between MSK144-15, Q65-60A, - JT65-C, FST4-120 or whatever, and wsjt-x_improved remembers all that. + - Show contacts by ID in the contest log, scroll to insertion when + sorted by the column up or down - - Also your last TX and RX audio frequencies are now remembered when - coming back from any mode which sets AF to 1500 Hz (MSK144, FST4W, - Echo, WSPR, FreqCal). - Note: when you start this version for the very first time, it will - set the RX and Tx audio frequencies for the non-restricted modes - (FT4, FT8, Q65, JT65, FST4) to 1500 Hz. Once you have changed the RX - and Tx audio frequencies in any of the non-restricted modes at least - one time, such values are saved and remembered. + - Remember the settings for T/R period and Submode by mode; you can now + switch directly e.g. between MSK144-15, Q65-60A, JT65-C, FST4-120 + - Restore Tx & Rx offset when coming from a mode which sets AF to + 1500 Hz (MSK144, FST4W, Echo, WSPR, FreqCal) and switch back to + FT4, FT8, Q65, JT65, or FST4 + + - Set 4m FT8 default frequency for Region 1 to 70.154 MHz + + - Optimize mode button layout for 4K screens + + - Minor edits to display of Keyboard Shortcuts + + - Fix some bugs Release: WSJT-X 2.6.0-rc1 From 5759f06d6da1530f6d4eaa2228b21946e57e2592 Mon Sep 17 00:00:00 2001 From: Uwe Risse Date: Fri, 15 Jul 2022 18:25:46 +0200 Subject: [PATCH 28/28] One more item for the rc2 release notes and NEWS. --- NEWS | 2 ++ Release_Notes.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index ff8f8d39b..3b95b3bce 100644 --- a/NEWS +++ b/NEWS @@ -41,6 +41,8 @@ In program WSJT-X : - Minor edits to display of Keyboard Shortcuts + - Make OK button the default on the LogQSO dialog window + - Fix some bugs diff --git a/Release_Notes.txt b/Release_Notes.txt index b5f492d64..bc9b414b2 100644 --- a/Release_Notes.txt +++ b/Release_Notes.txt @@ -41,6 +41,8 @@ In program WSJT-X : - Minor edits to display of Keyboard Shortcuts + - Make OK button the default on the LogQSO dialog window + - Fix some bugs