mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-30 12:30:23 -04:00 
			
		
		
		
	Add mode dependent working frequencies
Working frequencies are mode dependent and a reset to defaults button has been added. Also re-factored much of the model and item delegate code to simplify several of the model implementations. Introduced a single routine called from main to register the custom types with Qt. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5453 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
		
							parent
							
								
									0a2823b611
								
							
						
					
					
						commit
						a1a6d1bc06
					
				| @ -1,18 +1,5 @@ | ||||
| #include "AudioDevice.hpp" | ||||
| 
 | ||||
| #include <QMetaType> | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   struct init | ||||
|   { | ||||
|     init () | ||||
|     { | ||||
|       qRegisterMetaType<AudioDevice::Channel> ("AudioDevice::Channel"); | ||||
|     } | ||||
|   } static_initializer; | ||||
| } | ||||
| 
 | ||||
| bool AudioDevice::initialize (OpenMode mode, Channel channel) | ||||
| { | ||||
|   m_channel = channel; | ||||
|  | ||||
							
								
								
									
										389
									
								
								Bands.cpp
									
									
									
									
									
								
							
							
						
						
									
										389
									
								
								Bands.cpp
									
									
									
									
									
								
							| @ -1,196 +1,193 @@ | ||||
| #include "Bands.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| #include <QString> | ||||
| #include <QVariant> | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   // Local structure to hold a single ADIF band definition.
 | ||||
|   struct ADIF_band | ||||
|   { | ||||
|     char const * const name_; | ||||
|     Radio::Frequency lower_bound_; | ||||
|     Radio::Frequency upper_bound_; | ||||
|   }; | ||||
| 
 | ||||
|   // Table of ADIF band definitions as defined in the ADIF
 | ||||
|   // specification.
 | ||||
|   ADIF_band constexpr ADIF_bands[] = { | ||||
|     {"2190m", 	136000u, 	137000u}, | ||||
|     {"630m", 	472000u, 	479000u}, | ||||
|     {"560m", 	501000u, 	504000u}, | ||||
|     {"160m", 	1800000u, 	2000000u}, | ||||
|     {"80m", 	3500000u, 	4000000u}, | ||||
|     {"60m", 	5102000u, 	5406500u}, | ||||
|     {"40m", 	7000000u, 	7300000u}, | ||||
|     {"30m", 	10000000u, 	10150000u}, | ||||
|     {"20m", 	14000000u, 	14350000u}, | ||||
|     {"17m", 	18068000u, 	18168000u}, | ||||
|     {"15m", 	21000000u, 	21450000u}, | ||||
|     {"12m", 	24890000u, 	24990000u}, | ||||
|     {"10m", 	28000000u, 	29700000u}, | ||||
|     {"6m", 	50000000u, 	54000000u}, | ||||
|     {"4m", 	70000000u, 	71000000u}, | ||||
|     {"2m", 	144000000u, 	148000000u}, | ||||
|     {"1.25m", 	222000000u, 	225000000u}, | ||||
|     {"70cm", 	420000000u, 	450000000u}, | ||||
|     {"33cm", 	902000000u, 	928000000u}, | ||||
|     {"23cm", 	1240000000u, 	1300000000u}, | ||||
|     {"13cm", 	2300000000u, 	2450000000u}, | ||||
|     {"9cm", 	3300000000u, 	3500000000u}, | ||||
|     {"6cm", 	5650000000u, 	5925000000u}, | ||||
|     {"3cm", 	10000000000u,	10500000000u}, | ||||
|     {"1.25cm", 	24000000000u,	24250000000u}, | ||||
|     {"6mm", 	47000000000u,	47200000000u}, | ||||
|     {"4mm", 	75500000000u,	81000000000u}, | ||||
|     {"2.5mm", 	119980000000u,	120020000000u}, | ||||
|     {"2mm", 	142000000000u,	149000000000u}, | ||||
|     {"1mm", 	241000000000u,	250000000000u}, | ||||
|   }; | ||||
| 
 | ||||
|   auto constexpr out_of_band = "OOB"; | ||||
| 
 | ||||
|   int constexpr table_rows () | ||||
|   { | ||||
|     return sizeof (ADIF_bands) / sizeof (ADIF_bands[0]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| Bands::Bands (QObject * parent) | ||||
|   : QAbstractTableModel {parent} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| QModelIndex Bands::find (QVariant const& v) const | ||||
| { | ||||
|   auto f = v.value<Radio::Frequency> (); | ||||
|   auto end_iter = ADIF_bands + table_rows (); | ||||
|   auto row_iter = std::find_if (ADIF_bands, end_iter, [f] (ADIF_band const& band) { | ||||
|       return band.lower_bound_ <= f && f <= band.upper_bound_; | ||||
|     }); | ||||
|   if (row_iter != end_iter) | ||||
|     { | ||||
|       return index (row_iter - ADIF_bands, 0); // return the band row index
 | ||||
|     } | ||||
| 
 | ||||
|   return QModelIndex {}; | ||||
| } | ||||
| 
 | ||||
| int Bands::rowCount (QModelIndex const& parent) const | ||||
| { | ||||
|   return parent.isValid () ? 0 : table_rows (); | ||||
| } | ||||
| 
 | ||||
| int Bands::columnCount (QModelIndex const& parent) const | ||||
| { | ||||
|   return parent.isValid () ? 0 : 3; | ||||
| } | ||||
| 
 | ||||
| Qt::ItemFlags Bands::flags (QModelIndex const& index) const | ||||
| { | ||||
|   return QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; | ||||
| } | ||||
| 
 | ||||
| QVariant Bands::data (QModelIndex const& index, int role) const | ||||
| { | ||||
|   QVariant item; | ||||
| 
 | ||||
|   if (!index.isValid ()) | ||||
|     { | ||||
|       // Hijack root for OOB string.
 | ||||
|       if (Qt::DisplayRole == role) | ||||
|         { | ||||
|           item = out_of_band; | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       auto row = index.row (); | ||||
|       auto column = index.column (); | ||||
| 
 | ||||
|       if (row < table_rows ()) | ||||
|         { | ||||
|           switch (role) | ||||
|             { | ||||
|             case Qt::ToolTipRole: | ||||
|             case Qt::AccessibleDescriptionRole: | ||||
|               switch (column) | ||||
|                 { | ||||
|                 case 0: item = tr ("Band name"); break; | ||||
|                 case 1: item = tr ("Lower frequency limit"); break; | ||||
|                 case 2: item = tr ("Upper frequency limit"); break; | ||||
|                 } | ||||
|               break; | ||||
| 
 | ||||
|             case SortRole: | ||||
|             case Qt::DisplayRole: | ||||
|             case Qt::EditRole: | ||||
|               switch (column) | ||||
|                 { | ||||
|                 case 0: | ||||
|                   if (SortRole == role) | ||||
|                     { | ||||
|                       // band name sorts by lower bound
 | ||||
|                       item = ADIF_bands[row].lower_bound_; | ||||
|                     } | ||||
|                   else | ||||
|                     { | ||||
|                       item = ADIF_bands[row].name_; | ||||
|                     } | ||||
|                   break; | ||||
| 
 | ||||
|                 case 1: item = ADIF_bands[row].lower_bound_; break; | ||||
|                 case 2: item = ADIF_bands[row].upper_bound_; break; | ||||
|                 } | ||||
|               break; | ||||
| 
 | ||||
|             case Qt::AccessibleTextRole: | ||||
|               switch (column) | ||||
|                 { | ||||
|                 case 0: item = ADIF_bands[row].name_; break; | ||||
|                 case 1: item = ADIF_bands[row].lower_bound_; break; | ||||
|                 case 2: item = ADIF_bands[row].upper_bound_; break; | ||||
|                 } | ||||
|               break; | ||||
| 
 | ||||
|             case Qt::TextAlignmentRole: | ||||
|               switch (column) | ||||
|                 { | ||||
|                 case 0: | ||||
|                   item = Qt::AlignHCenter + Qt::AlignVCenter; | ||||
|                   break; | ||||
| 
 | ||||
|                 case 1: | ||||
|                 case 2: | ||||
|                   item = Qt::AlignRight + Qt::AlignVCenter; | ||||
|                   break; | ||||
|                 } | ||||
|               break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   return item; | ||||
| } | ||||
| 
 | ||||
| QVariant Bands::headerData (int section, Qt::Orientation orientation, int role) const | ||||
| { | ||||
|   QVariant result; | ||||
| 
 | ||||
|   if (Qt::DisplayRole == role && Qt::Horizontal == orientation) | ||||
|     { | ||||
|       switch (section) | ||||
|         { | ||||
|         case 0: result = tr ("Band"); break; | ||||
|         case 1: result = tr ("Lower Limit"); break; | ||||
|         case 2: result = tr ("Upper Limit"); break; | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       result = QAbstractTableModel::headerData (section, orientation, role); | ||||
|     } | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| #include "Bands.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| #include <QString> | ||||
| #include <QVariant> | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   // Local structure to hold a single ADIF band definition.
 | ||||
| 
 | ||||
|   // Table of ADIF band definitions as defined in the ADIF
 | ||||
|   // specification.
 | ||||
|   Bands::ADIFBand constexpr ADIF_bands[] = { | ||||
|     {"2190m",	136000u,  		137000u}, | ||||
|     {"630m",  472000u,  		479000u}, | ||||
|     {"560m",  501000u,  		504000u}, | ||||
|     {"160m",  1800000u,   	2000000u}, | ||||
|     {"80m",   3500000u,   	4000000u}, | ||||
|     {"60m",   5102000u,   	5406500u}, | ||||
|     {"40m",   7000000u,   	7300000u}, | ||||
|     {"30m",   10000000u,  	10150000u}, | ||||
|     {"20m",   14000000u,  	14350000u}, | ||||
|     {"17m",   18068000u,  	18168000u}, | ||||
|     {"15m",   21000000u,  	21450000u}, | ||||
|     {"12m",   24890000u,  	24990000u}, | ||||
|     {"10m",   28000000u,  	29700000u}, | ||||
|     {"6m",  	50000000u,  	54000000u}, | ||||
|     {"4m",  	70000000u,  	71000000u}, | ||||
|     {"2m",  	144000000u,   148000000u}, | ||||
|     {"1.25m", 222000000u,   225000000u}, | ||||
|     {"70cm",  420000000u,   450000000u}, | ||||
|     {"33cm",  902000000u,   928000000u}, | ||||
|     {"23cm",  1240000000u,  1300000000u}, | ||||
|     {"13cm",  2300000000u,  2450000000u}, | ||||
|     {"9cm",   3300000000u,  3500000000u}, | ||||
|     {"6cm",   5650000000u,  5925000000u}, | ||||
|     {"3cm",   10000000000u, 10500000000u}, | ||||
|     {"1.25cm",24000000000u, 24250000000u}, | ||||
|     {"6mm",   47000000000u, 47200000000u}, | ||||
|     {"4mm",   75500000000u, 81000000000u}, | ||||
|     {"2.5mm", 119980000000u,120020000000u}, | ||||
|     {"2mm",   142000000000u,149000000000u}, | ||||
|     {"1mm",   241000000000u,250000000000u}, | ||||
|   }; | ||||
| 
 | ||||
|   Bands::ADIFBand constexpr oob = {"OOB", 0, std::numeric_limits<Bands::Frequency>::max ()}; | ||||
| 
 | ||||
|   int constexpr table_rows () | ||||
|   { | ||||
|     return sizeof (ADIF_bands) / sizeof (ADIF_bands[0]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| Bands::Bands (QObject * parent) | ||||
|   : QAbstractTableModel {parent} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| auto Bands::find (Frequency f) const -> ADIFBand const * | ||||
| { | ||||
|   auto const& end_iter = ADIF_bands + table_rows (); | ||||
|   auto const& row_iter = std::find_if (ADIF_bands, end_iter, [f] (ADIFBand const& band) { | ||||
|       return band.lower_bound_ <= f && f <= band.upper_bound_; | ||||
|     }); | ||||
|   if (row_iter != end_iter) | ||||
|     { | ||||
|       return row_iter; | ||||
|     } | ||||
|   return &oob; | ||||
| } | ||||
| 
 | ||||
| auto Bands::out_of_band () const -> ADIFBand const * | ||||
| { | ||||
|   return &oob; | ||||
| } | ||||
| 
 | ||||
| int Bands::rowCount (QModelIndex const& parent) const | ||||
| { | ||||
|   return parent.isValid () ? 0 : table_rows (); | ||||
| } | ||||
| 
 | ||||
| int Bands::columnCount (QModelIndex const& parent) const | ||||
| { | ||||
|   return parent.isValid () ? 0 : 3; | ||||
| } | ||||
| 
 | ||||
| Qt::ItemFlags Bands::flags (QModelIndex const& index) const | ||||
| { | ||||
|   return QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; | ||||
| } | ||||
| 
 | ||||
| QVariant Bands::data (QModelIndex const& index, int role) const | ||||
| { | ||||
|   QVariant item; | ||||
| 
 | ||||
|   if (!index.isValid ()) | ||||
|     { | ||||
|       // Hijack root for OOB string.
 | ||||
|       if (Qt::DisplayRole == role) | ||||
|         { | ||||
|           item = oob.name_; | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       auto row = index.row (); | ||||
|       auto column = index.column (); | ||||
| 
 | ||||
|       if (row < table_rows ()) | ||||
|         { | ||||
|           switch (role) | ||||
|             { | ||||
|             case Qt::ToolTipRole: | ||||
|             case Qt::AccessibleDescriptionRole: | ||||
|               switch (column) | ||||
|                 { | ||||
|                 case 0: item = tr ("Band name"); break; | ||||
|                 case 1: item = tr ("Lower frequency limit"); break; | ||||
|                 case 2: item = tr ("Upper frequency limit"); break; | ||||
|                 } | ||||
|               break; | ||||
| 
 | ||||
|             case SortRole: | ||||
|             case Qt::DisplayRole: | ||||
|             case Qt::EditRole: | ||||
|               switch (column) | ||||
|                 { | ||||
|                 case 0: | ||||
|                   if (SortRole == role) | ||||
|                     { | ||||
|                       // band name sorts by lower bound
 | ||||
|                       item = ADIF_bands[row].lower_bound_; | ||||
|                     } | ||||
|                   else | ||||
|                     { | ||||
|                       item = ADIF_bands[row].name_; | ||||
|                     } | ||||
|                   break; | ||||
| 
 | ||||
|                 case 1: item = ADIF_bands[row].lower_bound_; break; | ||||
|                 case 2: item = ADIF_bands[row].upper_bound_; break; | ||||
|                 } | ||||
|               break; | ||||
| 
 | ||||
|             case Qt::AccessibleTextRole: | ||||
|               switch (column) | ||||
|                 { | ||||
|                 case 0: item = ADIF_bands[row].name_; break; | ||||
|                 case 1: item = ADIF_bands[row].lower_bound_; break; | ||||
|                 case 2: item = ADIF_bands[row].upper_bound_; break; | ||||
|                 } | ||||
|               break; | ||||
| 
 | ||||
|             case Qt::TextAlignmentRole: | ||||
|               switch (column) | ||||
|                 { | ||||
|                 case 0: | ||||
|                   item = Qt::AlignHCenter + Qt::AlignVCenter; | ||||
|                   break; | ||||
| 
 | ||||
|                 case 1: | ||||
|                 case 2: | ||||
|                   item = Qt::AlignRight + Qt::AlignVCenter; | ||||
|                   break; | ||||
|                 } | ||||
|               break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   return item; | ||||
| } | ||||
| 
 | ||||
| QVariant Bands::headerData (int section, Qt::Orientation orientation, int role) const | ||||
| { | ||||
|   QVariant result; | ||||
| 
 | ||||
|   if (Qt::DisplayRole == role && Qt::Horizontal == orientation) | ||||
|     { | ||||
|       switch (section) | ||||
|         { | ||||
|         case 0: result = tr ("Band"); break; | ||||
|         case 1: result = tr ("Lower Limit"); break; | ||||
|         case 2: result = tr ("Upper Limit"); break; | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       result = QAbstractTableModel::headerData (section, orientation, role); | ||||
|     } | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
|  | ||||
							
								
								
									
										126
									
								
								Bands.hpp
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								Bands.hpp
									
									
									
									
									
								
							| @ -1,58 +1,68 @@ | ||||
| #ifndef BANDS_HPP__ | ||||
| #define BANDS_HPP__ | ||||
| 
 | ||||
| #include <QAbstractTableModel> | ||||
| 
 | ||||
| #include "Radio.hpp" | ||||
| 
 | ||||
| //
 | ||||
| // Class Bands
 | ||||
| //
 | ||||
| //  Encapsulates information  about amateur radio bands  as defined by
 | ||||
| //  the  ADIF specification.  The model  is immutable.   The rows  are
 | ||||
| //  stored in asscending order of frequency.
 | ||||
| //
 | ||||
| // Responsibilities
 | ||||
| //
 | ||||
| //  Provides  a  well  known  band  name mapped  to  lower  and  upper
 | ||||
| //  frequency  limits.  Also  provides   a  convenience  operation  to
 | ||||
| //  determine the band details for  any given frequency, the result of
 | ||||
| //  which may be  invalid if the given frequency doesn't  lie within a
 | ||||
| //  recognised band.
 | ||||
| //
 | ||||
| // Collaborations
 | ||||
| //
 | ||||
| //  Implements the QAbstractTableModel interface as an immutable table
 | ||||
| //  where rows  are bands and  columns are band name,  lower frequency
 | ||||
| //  limit and, upper ferquency limit respectively.
 | ||||
| //
 | ||||
| class Bands final | ||||
|   : public QAbstractTableModel | ||||
| { | ||||
| public: | ||||
|   explicit Bands (QObject * parent = nullptr); | ||||
| 
 | ||||
|   //
 | ||||
|   // Model API
 | ||||
|   //
 | ||||
|   QModelIndex find (QVariant const&) const; // find band Frequency is in
 | ||||
| 
 | ||||
|   // Custom role for sorting.
 | ||||
|   static int constexpr SortRole = Qt::UserRole; | ||||
| 
 | ||||
|   // 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 headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; | ||||
| 
 | ||||
|   // The value return for the Qt::DisplayRole role for the root of the
 | ||||
|   // model (invalid index) is a special string representing out of
 | ||||
|   // band.
 | ||||
|   //
 | ||||
|   // All columns return a number for the custom role SortRole, this
 | ||||
|   // number defines a strict frequency order for the rows.
 | ||||
|   QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| #ifndef BANDS_HPP__ | ||||
| #define BANDS_HPP__ | ||||
| 
 | ||||
| #include <QAbstractTableModel> | ||||
| 
 | ||||
| #include "Radio.hpp" | ||||
| 
 | ||||
| //
 | ||||
| // Class Bands
 | ||||
| //
 | ||||
| //  Encapsulates information  about amateur radio bands  as defined by
 | ||||
| //  the  ADIF specification.  The model  is immutable.   The rows  are
 | ||||
| //  stored in asscending order of frequency.
 | ||||
| //
 | ||||
| // Responsibilities
 | ||||
| //
 | ||||
| //  Provides  a  well  known  band  name mapped  to  lower  and  upper
 | ||||
| //  frequency  limits.  Also  provides   a  convenience  operation  to
 | ||||
| //  determine the band details for  any given frequency, the result of
 | ||||
| //  which may be  invalid if the given frequency doesn't  lie within a
 | ||||
| //  recognised band.
 | ||||
| //
 | ||||
| // Collaborations
 | ||||
| //
 | ||||
| //  Implements the QAbstractTableModel interface as an immutable table
 | ||||
| //  where rows  are bands and  columns are band name,  lower frequency
 | ||||
| //  limit and, upper ferquency limit respectively.
 | ||||
| //
 | ||||
| class Bands final | ||||
|   : public QAbstractTableModel | ||||
| { | ||||
| public: | ||||
|   using Frequency = Radio::Frequency; | ||||
| 
 | ||||
|   struct ADIFBand | ||||
|   { | ||||
|     char const * const name_; | ||||
|     Radio::Frequency lower_bound_; | ||||
|     Radio::Frequency upper_bound_; | ||||
|   }; | ||||
| 
 | ||||
|   explicit Bands (QObject * parent = nullptr); | ||||
| 
 | ||||
|   //
 | ||||
|   // Model API
 | ||||
|   //
 | ||||
|   ADIFBand const * find (Frequency) const; // find band Frequency is in
 | ||||
|   ADIFBand const * out_of_band () const; | ||||
| 
 | ||||
|   // Custom role for sorting.
 | ||||
|   static int constexpr SortRole = Qt::UserRole; | ||||
| 
 | ||||
|   // 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 headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; | ||||
| 
 | ||||
|   // The value return for the Qt::DisplayRole role for the root of the
 | ||||
|   // model (invalid index) is a special string representing out of
 | ||||
|   // band.
 | ||||
|   //
 | ||||
|   // All columns return a number for the custom role SortRole, this
 | ||||
|   // number defines a strict frequency order for the rows.
 | ||||
|   QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -177,11 +177,13 @@ endif (APPLE) | ||||
| # | ||||
| set (wsjt_qt_CXXSRCS | ||||
|   qt_helpers.cpp | ||||
|   MetaDataRegistry.cpp | ||||
|   NetworkServerLookup.cpp | ||||
|   revision_utils.cpp | ||||
|   WFPalette.cpp | ||||
|   Radio.cpp | ||||
|   Bands.cpp | ||||
|   Modes.cpp | ||||
|   FrequencyList.cpp | ||||
|   StationList.cpp | ||||
|   FrequencyLineEdit.cpp | ||||
|  | ||||
| @ -8,11 +8,11 @@ | ||||
| class CandidateKeyFilter::impl final | ||||
| { | ||||
| public: | ||||
|   explicit impl (QAbstractItemModel const * referencing_model | ||||
|   explicit impl (int referenced_key_column | ||||
|                  , int referenced_key_role | ||||
|                  , QAbstractItemModel const * referencing_model | ||||
|                  , int referencing_key_column | ||||
|                  , int referenced_key_column | ||||
|                  , int referencing_key_role | ||||
|                  , int referenced_key_role) | ||||
|                  , int referencing_key_role) | ||||
|     : referencing_ {referencing_model} | ||||
|     , referencing_key_column_ {referencing_key_column} | ||||
|     , referencing_key_role_ {referencing_key_role} | ||||
| @ -29,14 +29,25 @@ public: | ||||
|   QModelIndex active_key_; | ||||
| }; | ||||
| 
 | ||||
| CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel const * referencing_model | ||||
|                                         , QAbstractItemModel * referenced_model | ||||
|                                         , int referencing_key_column | ||||
| CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel * referenced_model | ||||
|                                         , int referenced_key_column | ||||
|                                         , int referencing_key_role | ||||
|                                         , QObject * parent | ||||
|                                         , int referenced_key_role) | ||||
|   : QSortFilterProxyModel {nullptr} // ForeignKeyDelegate owns us
 | ||||
|   , m_ {referencing_model, referencing_key_column, referenced_key_column, referencing_key_role, referenced_key_role} | ||||
|   : QSortFilterProxyModel {parent} | ||||
|   , m_ {referenced_key_column, referenced_key_role, nullptr, 0, Qt::EditRole} | ||||
| { | ||||
|   setSourceModel (referenced_model); | ||||
| } | ||||
| 
 | ||||
| CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel * referenced_model | ||||
|                                         , QAbstractItemModel const * referencing_model | ||||
|                                         , int referenced_key_column | ||||
|                                         , int referencing_key_column | ||||
|                                         , QObject * parent | ||||
|                                         , int referenced_key_role | ||||
|                                         , int referencing_key_role) | ||||
|   : QSortFilterProxyModel {parent} | ||||
|   , m_ {referenced_key_column, referenced_key_role, referencing_model, referencing_key_column, referencing_key_role} | ||||
| { | ||||
|   setSourceModel (referenced_model); | ||||
| } | ||||
| @ -47,16 +58,24 @@ CandidateKeyFilter::~CandidateKeyFilter () | ||||
| 
 | ||||
| void CandidateKeyFilter::set_active_key (QModelIndex const& index) | ||||
| { | ||||
|   if (index.isValid () ) | ||||
|   if (m_->referencing_) | ||||
|     { | ||||
|       Q_ASSERT (index.column () == m_->referencing_key_column_); | ||||
|       m_->active_key_ = index; | ||||
|       if (index.isValid () ) | ||||
|         { | ||||
|           Q_ASSERT (index.column () == m_->referencing_key_column_); | ||||
|           m_->active_key_ = index; | ||||
|         } | ||||
|       invalidateFilter (); | ||||
|     } | ||||
|   invalidateFilter (); | ||||
| } | ||||
| 
 | ||||
| bool CandidateKeyFilter::filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const | ||||
| { | ||||
|   if (!m_->referencing_)            // many to many passes all
 | ||||
|     { | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|   auto candidate_key = sourceModel ()->index (candidate_row, m_->referenced_key_column_, candidate_parent).data (m_->referenced_key_role_); | ||||
| 
 | ||||
|   // Include the current key.
 | ||||
|  | ||||
| @ -12,12 +12,17 @@ class CandidateKeyFilter final | ||||
|   : public QSortFilterProxyModel | ||||
| { | ||||
| public: | ||||
|   explicit CandidateKeyFilter (QAbstractItemModel const * referencing_model | ||||
|                                , QAbstractItemModel * referenced_model | ||||
|                                , int referencing_key_column = 0 | ||||
|                                , int referenced_key_column = 0 | ||||
|                                , int referencing_key_role = Qt::EditRole | ||||
|   explicit CandidateKeyFilter (QAbstractItemModel * referenced_model | ||||
|                                , int referenced_key_column | ||||
|                                , QObject * parent = nullptr | ||||
|                                , int referenced_key_role = Qt::EditRole); | ||||
|   explicit CandidateKeyFilter (QAbstractItemModel * referenced_model | ||||
|                                , QAbstractItemModel const * referencing_model | ||||
|                                , int referenced_key_column | ||||
|                                , int referencing_key_column | ||||
|                                , QObject * parent = nullptr | ||||
|                                , int referenced_key_role = Qt::EditRole | ||||
|                                , int referencing_key_role = Qt::EditRole); | ||||
|   ~CandidateKeyFilter (); | ||||
| 
 | ||||
|   // this key is not to be filtered, usually because we want to allow
 | ||||
|  | ||||
| @ -171,6 +171,7 @@ | ||||
| #include "TransceiverFactory.hpp" | ||||
| #include "Transceiver.hpp" | ||||
| #include "Bands.hpp" | ||||
| #include "Modes.hpp" | ||||
| #include "FrequencyList.hpp" | ||||
| #include "StationList.hpp" | ||||
| #include "NetworkServerLookup.hpp" | ||||
| @ -182,17 +183,6 @@ | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   struct init | ||||
|   { | ||||
|     init () | ||||
|     { | ||||
|       qRegisterMetaType<Configuration::DataMode> ("Configuration::DataMode"); | ||||
|       qRegisterMetaTypeStreamOperators<Configuration::DataMode> ("Configuration::DataMode"); | ||||
|       qRegisterMetaType<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen"); | ||||
|       qRegisterMetaTypeStreamOperators<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen"); | ||||
|     } | ||||
|   } static_initializer; | ||||
| 
 | ||||
|   // these undocumented flag values when stored in (Qt::UserRole - 1)
 | ||||
|   // of a ComboBox item model index allow the item to be enabled or
 | ||||
|   // disabled
 | ||||
| @ -210,14 +200,17 @@ class FrequencyDialog final | ||||
|   : public QDialog | ||||
| { | ||||
| public: | ||||
|   using Frequency = Radio::Frequency; | ||||
|   using Item = FrequencyList::Item; | ||||
| 
 | ||||
|   explicit FrequencyDialog (QWidget * parent = nullptr) | ||||
|   explicit FrequencyDialog (Modes * modes_model, QWidget * parent = nullptr) | ||||
|     : QDialog {parent} | ||||
|   { | ||||
|     setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Frequency")); | ||||
| 
 | ||||
|     mode_combo_box_.setModel (modes_model); | ||||
| 
 | ||||
|     auto form_layout = new QFormLayout (); | ||||
|     form_layout->addRow (tr ("&Mode:"), &mode_combo_box_); | ||||
|     form_layout->addRow (tr ("&Frequency (MHz):"), &frequency_line_edit_); | ||||
| 
 | ||||
|     auto main_layout = new QVBoxLayout (this); | ||||
| @ -230,12 +223,13 @@ public: | ||||
|     connect (button_box, &QDialogButtonBox::rejected, this, &FrequencyDialog::reject); | ||||
|   } | ||||
| 
 | ||||
|   Frequency frequency () const | ||||
|   Item item () const | ||||
|   { | ||||
|     return frequency_line_edit_.frequency (); | ||||
|     return {frequency_line_edit_.frequency (), Modes::value (mode_combo_box_.currentText ())}; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   QComboBox mode_combo_box_; | ||||
|   FrequencyLineEdit frequency_line_edit_; | ||||
| }; | ||||
| 
 | ||||
| @ -249,7 +243,7 @@ class StationDialog final | ||||
| public: | ||||
|   explicit StationDialog (StationList const * stations, Bands * bands, QWidget * parent = nullptr) | ||||
|     : QDialog {parent} | ||||
|     , filtered_bands_ {new CandidateKeyFilter {stations, bands}} | ||||
|     , filtered_bands_ {new CandidateKeyFilter {bands, stations, 0, 0}} | ||||
|   { | ||||
|     setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Station")); | ||||
| 
 | ||||
| @ -311,6 +305,7 @@ public: | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| //
 | ||||
| // Class MessageItemDelegate
 | ||||
| //
 | ||||
| //	Item delegate for message entry such as free text message macros.
 | ||||
| @ -336,7 +331,6 @@ public: | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // Internal implementation of the Configuration class.
 | ||||
| class Configuration::impl final | ||||
|   : public QDialog | ||||
| @ -416,6 +410,7 @@ private: | ||||
|   void delete_selected_macros (QModelIndexList); | ||||
|   Q_SLOT void on_save_path_select_push_button_clicked (bool); | ||||
|   Q_SLOT void delete_frequencies (); | ||||
|   Q_SLOT void on_reset_frequencies_push_button_clicked (bool); | ||||
|   Q_SLOT void insert_frequency (); | ||||
|   Q_SLOT void delete_stations (); | ||||
|   Q_SLOT void insert_station (); | ||||
| @ -469,8 +464,9 @@ private: | ||||
|   QStringListModel macros_; | ||||
|   RearrangableMacrosModel next_macros_; | ||||
|   QAction * macro_delete_action_; | ||||
|    | ||||
| 
 | ||||
|   Bands bands_; | ||||
|   Modes modes_; | ||||
|   FrequencyList frequencies_; | ||||
|   FrequencyList next_frequencies_; | ||||
|   StationList stations_; | ||||
| @ -697,24 +693,17 @@ void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_s | ||||
|   m_->sync_transceiver (force_signal); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget * parent) | ||||
|   : QDialog {parent} | ||||
|   , self_ {self} | ||||
|   , ui_ {new Ui::configuration_dialog} | ||||
|   , settings_ {settings} | ||||
|   , doc_dir_ {QApplication::applicationDirPath ()} | ||||
|   , frequencies_ { | ||||
|     { 136000, 136130, 474200, 1836600, 1838000, 3576000, 3592600, 5287200, 5357000, | ||||
|       7038600, 7076000, 10138000, 10138700, 14076000, 14095600, 18102000, 18104600, | ||||
|       21076000, 21094600, 24917000, 24924600, 28076000, 28124600, 50276000, 50293000, | ||||
|       70091000, 144000000, 144489000, 222000000, 432000000, 432300000, | ||||
|       902000000, 1296000000, 1296500000, 2301000000, 2304000000, 2320000000, 3400000000, | ||||
|       3456000000, 5760000000,10368000000, 24048000000 } | ||||
|     } | ||||
|   , frequencies_ {&bands_} | ||||
|   , next_frequencies_ {&bands_} | ||||
|   , stations_ {&bands_} | ||||
|   , next_stations_ {&bands_} | ||||
|   , frequency_dialog_ {new FrequencyDialog {this}} | ||||
|   , frequency_dialog_ {new FrequencyDialog {&modes_, this}} | ||||
|   , station_dialog_ {new StationDialog {&next_stations_, &bands_, this}} | ||||
|   , rig_active_ {false} | ||||
|   , have_rig_ {false} | ||||
| @ -891,12 +880,12 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget * | ||||
|   //
 | ||||
|   // setup working frequencies table model & view
 | ||||
|   //
 | ||||
|   frequencies_.sort (0); | ||||
|   frequencies_.sort (FrequencyList::frequency_column); | ||||
| 
 | ||||
|   ui_->frequencies_table_view->setModel (&next_frequencies_); | ||||
|   ui_->frequencies_table_view->sortByColumn (0, Qt::AscendingOrder); | ||||
|   ui_->frequencies_table_view->setItemDelegateForColumn (0, new FrequencyItemDelegate {&bands_, this}); | ||||
|   ui_->frequencies_table_view->setColumnHidden (1, true); | ||||
|   ui_->frequencies_table_view->sortByColumn (FrequencyList::frequency_column, Qt::AscendingOrder); | ||||
|   ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList::mode_column, new ForeignKeyDelegate {&modes_, 0, this}); | ||||
|   ui_->frequencies_table_view->setColumnHidden (FrequencyList::frequency_mhz_column, true); | ||||
| 
 | ||||
|   frequency_delete_action_ = new QAction {tr ("&Delete"), ui_->frequencies_table_view}; | ||||
|   ui_->frequencies_table_view->insertAction (nullptr, frequency_delete_action_); | ||||
| @ -910,13 +899,11 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget * | ||||
|   //
 | ||||
|   // setup stations table model & view
 | ||||
|   //
 | ||||
|   stations_.sort (0); | ||||
|   stations_.sort (StationList::band_column); | ||||
| 
 | ||||
|   ui_->stations_table_view->setModel (&next_stations_); | ||||
|   ui_->stations_table_view->sortByColumn (0, Qt::AscendingOrder); | ||||
|   ui_->stations_table_view->setColumnWidth (1, 150); | ||||
|   ui_->stations_table_view->setItemDelegateForColumn (0, new ForeignKeyDelegate {&next_stations_, &bands_, 0, 0, this}); | ||||
|   ui_->stations_table_view->setItemDelegateForColumn (1, new FrequencyDeltaItemDelegate {this}); | ||||
|   ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder); | ||||
|   ui_->stations_table_view->setItemDelegateForColumn (StationList::band_column, new ForeignKeyDelegate {&bands_, &next_stations_, 0, StationList::band_column, this}); | ||||
| 
 | ||||
|   station_delete_action_ = new QAction {tr ("&Delete"), ui_->stations_table_view}; | ||||
|   ui_->stations_table_view->insertAction (nullptr, station_delete_action_); | ||||
| @ -1041,8 +1028,8 @@ void Configuration::impl::initialize_models () | ||||
|     } | ||||
| 
 | ||||
|   next_macros_.setStringList (macros_.stringList ()); | ||||
|   next_frequencies_ = frequencies_.frequencies (); | ||||
|   next_stations_ = stations_.stations (); | ||||
|   next_frequencies_.frequency_list (frequencies_.frequency_list ()); | ||||
|   next_stations_.station_list (stations_.station_list ()); | ||||
| 
 | ||||
|   set_rig_invariants (); | ||||
| } | ||||
| @ -1170,10 +1157,10 @@ void Configuration::impl::read_settings () | ||||
| 
 | ||||
|   if (settings_->contains ("frequencies")) | ||||
|     { | ||||
|       frequencies_ = settings_->value ("frequencies").value<Radio::Frequencies> (); | ||||
|       frequencies_.frequency_list (settings_->value ("frequencies").value<FrequencyList::FrequencyItems> ()); | ||||
|     } | ||||
| 
 | ||||
|   stations_ = settings_->value ("stations").value<StationList::Stations> (); | ||||
|   stations_.station_list (settings_->value ("stations").value<StationList::Stations> ()); | ||||
| 
 | ||||
|   log_as_RTTY_ = settings_->value ("toRTTY", false).toBool (); | ||||
|   report_in_comments_ = settings_->value("dBtoComments", false).toBool (); | ||||
| @ -1262,8 +1249,8 @@ void Configuration::impl::write_settings () | ||||
|   settings_->setValue ("After73", id_after_73_); | ||||
|   settings_->setValue ("TxQSYAllowed", tx_QSY_allowed_); | ||||
|   settings_->setValue ("Macros", macros_.stringList ()); | ||||
|   settings_->setValue ("frequencies", QVariant::fromValue (frequencies_.frequencies ())); | ||||
|   settings_->setValue ("stations", QVariant::fromValue (stations_.stations ())); | ||||
|   settings_->setValue ("frequencies", QVariant::fromValue (frequencies_.frequency_list ())); | ||||
|   settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ())); | ||||
|   settings_->setValue ("toRTTY", log_as_RTTY_); | ||||
|   settings_->setValue ("dBtoComments", report_in_comments_); | ||||
|   settings_->setValue ("Rig", rig_params_.rig_name); | ||||
| @ -1674,16 +1661,16 @@ void Configuration::impl::accept () | ||||
|       macros_.setStringList (next_macros_.stringList ()); | ||||
|     } | ||||
| 
 | ||||
|   if (frequencies_.frequencies () != next_frequencies_.frequencies ()) | ||||
|   if (frequencies_.frequency_list () != next_frequencies_.frequency_list ()) | ||||
|     { | ||||
|       frequencies_ = next_frequencies_.frequencies (); | ||||
|       frequencies_.sort (0); | ||||
|       frequencies_.frequency_list (next_frequencies_.frequency_list ()); | ||||
|       frequencies_.sort (FrequencyList::frequency_column); | ||||
|     } | ||||
| 
 | ||||
|   if (stations_.stations () != next_stations_.stations ()) | ||||
|   if (stations_.station_list () != next_stations_.station_list ()) | ||||
|     { | ||||
|       stations_ = next_stations_.stations (); | ||||
|       stations_.sort (0); | ||||
|       stations_.station_list(next_stations_.station_list ()); | ||||
|       stations_.sort (StationList::band_column); | ||||
|     } | ||||
|   | ||||
|   write_settings ();		// make visible to all
 | ||||
| @ -1975,13 +1962,26 @@ void Configuration::impl::delete_frequencies () | ||||
|   auto selection_model = ui_->frequencies_table_view->selectionModel (); | ||||
|   selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | ||||
|   next_frequencies_.removeDisjointRows (selection_model->selectedRows ()); | ||||
|   ui_->frequencies_table_view->resizeColumnToContents (FrequencyList::mode_column); | ||||
| } | ||||
| 
 | ||||
| void Configuration::impl::on_reset_frequencies_push_button_clicked (bool /* checked */) | ||||
| { | ||||
|   if (QMessageBox::Yes == QMessageBox::question (this, tr ("Reset Working Frequencies") | ||||
|                                                  , tr ("Are you sure you want to discard your current " | ||||
|                                                        "working frequencies and replace them with default " | ||||
|                                                        "ones?"))) | ||||
|     { | ||||
|       next_frequencies_.reset_to_defaults (); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Configuration::impl::insert_frequency () | ||||
| { | ||||
|   if (QDialog::Accepted == frequency_dialog_->exec ()) | ||||
|     { | ||||
|       ui_->frequencies_table_view->setCurrentIndex (next_frequencies_.add (frequency_dialog_->frequency ())); | ||||
|       ui_->frequencies_table_view->setCurrentIndex (next_frequencies_.add (frequency_dialog_->item ())); | ||||
|       ui_->frequencies_table_view->resizeColumnToContents (FrequencyList::mode_column); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -1990,6 +1990,8 @@ void Configuration::impl::delete_stations () | ||||
|   auto selection_model = ui_->stations_table_view->selectionModel (); | ||||
|   selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | ||||
|   next_stations_.removeDisjointRows (selection_model->selectedRows ()); | ||||
|   ui_->stations_table_view->resizeColumnToContents (StationList::band_column); | ||||
|   ui_->stations_table_view->resizeColumnToContents (StationList::offset_column); | ||||
| } | ||||
| 
 | ||||
| void Configuration::impl::insert_station () | ||||
| @ -1997,6 +1999,8 @@ void Configuration::impl::insert_station () | ||||
|   if (QDialog::Accepted == station_dialog_->exec ()) | ||||
|     { | ||||
|       ui_->stations_table_view->setCurrentIndex (next_stations_.add (station_dialog_->station ())); | ||||
|       ui_->stations_table_view->resizeColumnToContents (StationList::band_column); | ||||
|       ui_->stations_table_view->resizeColumnToContents (StationList::offset_column); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										251
									
								
								Configuration.ui
									
									
									
									
									
								
							
							
						
						
									
										251
									
								
								Configuration.ui
									
									
									
									
									
								
							| @ -1807,9 +1807,15 @@ for assessing propagation and system performance.</string> | ||||
|          <property name="title"> | ||||
|           <string>Working Frequencies</string> | ||||
|          </property> | ||||
|          <layout class="QGridLayout" name="gridLayout_15"> | ||||
|           <item row="0" column="0" rowspan="2"> | ||||
|          <layout class="QHBoxLayout" name="horizontalLayout"> | ||||
|           <item> | ||||
|            <widget class="QTableView" name="frequencies_table_view"> | ||||
|             <property name="sizePolicy"> | ||||
|              <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||||
|               <horstretch>1</horstretch> | ||||
|               <verstretch>0</verstretch> | ||||
|              </sizepolicy> | ||||
|             </property> | ||||
|             <property name="contextMenuPolicy"> | ||||
|              <enum>Qt::ActionsContextMenu</enum> | ||||
|             </property> | ||||
| @ -1836,113 +1842,128 @@ for assessing propagation and system performance.</string> | ||||
|             </attribute> | ||||
|            </widget> | ||||
|           </item> | ||||
|           <item row="0" column="2"> | ||||
|            <widget class="QGroupBox" name="groupBox_3"> | ||||
|             <property name="toolTip"> | ||||
|              <string>See WSPR documentattion Appendix C for details of how to determine these factors for your radio.</string> | ||||
|             </property> | ||||
|             <property name="title"> | ||||
|              <string>Frequency Calibration</string> | ||||
|             </property> | ||||
|             <layout class="QFormLayout" name="formLayout_7"> | ||||
|              <property name="fieldGrowthPolicy"> | ||||
|               <enum>QFormLayout::AllNonFixedFieldsGrow</enum> | ||||
|              </property> | ||||
|              <item row="0" column="0"> | ||||
|               <widget class="QLabel" name="label_7"> | ||||
|                <property name="text"> | ||||
|                 <string>Intercept:</string> | ||||
|           <item> | ||||
|            <layout class="QVBoxLayout" name="verticalLayout_7"> | ||||
|             <item> | ||||
|              <layout class="QHBoxLayout" name="horizontalLayout_6"> | ||||
|               <item> | ||||
|                <widget class="QPushButton" name="reset_frequencies_push_button"> | ||||
|                 <property name="text"> | ||||
|                  <string>Reset</string> | ||||
|                 </property> | ||||
|                </widget> | ||||
|               </item> | ||||
|               <item> | ||||
|                <spacer name="horizontalSpacer_6"> | ||||
|                 <property name="orientation"> | ||||
|                  <enum>Qt::Horizontal</enum> | ||||
|                 </property> | ||||
|                 <property name="sizeHint" stdset="0"> | ||||
|                  <size> | ||||
|                   <width>40</width> | ||||
|                   <height>20</height> | ||||
|                  </size> | ||||
|                 </property> | ||||
|                </spacer> | ||||
|               </item> | ||||
|              </layout> | ||||
|             </item> | ||||
|             <item> | ||||
|              <widget class="QGroupBox" name="groupBox_3"> | ||||
|               <property name="toolTip"> | ||||
|                <string>See WSPR documentattion Appendix C for details of how to determine these factors for your radio.</string> | ||||
|               </property> | ||||
|               <property name="title"> | ||||
|                <string>Frequency Calibration</string> | ||||
|               </property> | ||||
|               <layout class="QFormLayout" name="formLayout_7"> | ||||
|                <property name="fieldGrowthPolicy"> | ||||
|                 <enum>QFormLayout::AllNonFixedFieldsGrow</enum> | ||||
|                </property> | ||||
|                <property name="buddy"> | ||||
|                 <cstring>calibration_intercept_spin_box</cstring> | ||||
|                </property> | ||||
|               </widget> | ||||
|              </item> | ||||
|              <item row="0" column="1"> | ||||
|               <widget class="QDoubleSpinBox" name="calibration_intercept_spin_box"> | ||||
|                <property name="alignment"> | ||||
|                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|                </property> | ||||
|                <property name="suffix"> | ||||
|                 <string> Hz</string> | ||||
|                </property> | ||||
|                <property name="decimals"> | ||||
|                 <number>2</number> | ||||
|                </property> | ||||
|                <property name="minimum"> | ||||
|                 <double>-99999.990000000005239</double> | ||||
|                </property> | ||||
|                <property name="maximum"> | ||||
|                 <double>99999.990000000005239</double> | ||||
|                </property> | ||||
|                <property name="singleStep"> | ||||
|                 <double>0.100000000000000</double> | ||||
|                </property> | ||||
|               </widget> | ||||
|              </item> | ||||
|              <item row="1" column="0"> | ||||
|               <widget class="QLabel" name="label_8"> | ||||
|                <property name="text"> | ||||
|                 <string>Slope:</string> | ||||
|                </property> | ||||
|                <property name="buddy"> | ||||
|                 <cstring>calibration_slope_ppm_spin_box</cstring> | ||||
|                </property> | ||||
|               </widget> | ||||
|              </item> | ||||
|              <item row="1" column="1"> | ||||
|               <widget class="QDoubleSpinBox" name="calibration_slope_ppm_spin_box"> | ||||
|                <property name="alignment"> | ||||
|                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|                </property> | ||||
|                <property name="suffix"> | ||||
|                 <string> ppm</string> | ||||
|                </property> | ||||
|                <property name="decimals"> | ||||
|                 <number>4</number> | ||||
|                </property> | ||||
|                <property name="minimum"> | ||||
|                 <double>-999.999900000000025</double> | ||||
|                </property> | ||||
|                <property name="maximum"> | ||||
|                 <double>999.999900000000025</double> | ||||
|                </property> | ||||
|                <property name="singleStep"> | ||||
|                 <double>0.100000000000000</double> | ||||
|                </property> | ||||
|                <property name="value"> | ||||
|                 <double>0.000000000000000</double> | ||||
|                </property> | ||||
|               </widget> | ||||
|              </item> | ||||
|             </layout> | ||||
|            </widget> | ||||
|           </item> | ||||
|           <item row="0" column="3"> | ||||
|            <spacer name="horizontalSpacer_6"> | ||||
|             <property name="orientation"> | ||||
|              <enum>Qt::Horizontal</enum> | ||||
|             </property> | ||||
|             <property name="sizeHint" stdset="0"> | ||||
|              <size> | ||||
|               <width>40</width> | ||||
|               <height>20</height> | ||||
|              </size> | ||||
|             </property> | ||||
|            </spacer> | ||||
|           </item> | ||||
|           <item row="1" column="2"> | ||||
|            <spacer name="verticalSpacer_6"> | ||||
|             <property name="orientation"> | ||||
|              <enum>Qt::Vertical</enum> | ||||
|             </property> | ||||
|             <property name="sizeHint" stdset="0"> | ||||
|              <size> | ||||
|               <width>20</width> | ||||
|               <height>40</height> | ||||
|              </size> | ||||
|             </property> | ||||
|            </spacer> | ||||
|                <item row="0" column="0"> | ||||
|                 <widget class="QLabel" name="label_7"> | ||||
|                  <property name="text"> | ||||
|                   <string>Intercept:</string> | ||||
|                  </property> | ||||
|                  <property name="buddy"> | ||||
|                   <cstring>calibration_intercept_spin_box</cstring> | ||||
|                  </property> | ||||
|                 </widget> | ||||
|                </item> | ||||
|                <item row="0" column="1"> | ||||
|                 <widget class="QDoubleSpinBox" name="calibration_intercept_spin_box"> | ||||
|                  <property name="alignment"> | ||||
|                   <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|                  </property> | ||||
|                  <property name="suffix"> | ||||
|                   <string> Hz</string> | ||||
|                  </property> | ||||
|                  <property name="decimals"> | ||||
|                   <number>2</number> | ||||
|                  </property> | ||||
|                  <property name="minimum"> | ||||
|                   <double>-99999.990000000005239</double> | ||||
|                  </property> | ||||
|                  <property name="maximum"> | ||||
|                   <double>99999.990000000005239</double> | ||||
|                  </property> | ||||
|                  <property name="singleStep"> | ||||
|                   <double>0.100000000000000</double> | ||||
|                  </property> | ||||
|                 </widget> | ||||
|                </item> | ||||
|                <item row="1" column="0"> | ||||
|                 <widget class="QLabel" name="label_8"> | ||||
|                  <property name="text"> | ||||
|                   <string>Slope:</string> | ||||
|                  </property> | ||||
|                  <property name="buddy"> | ||||
|                   <cstring>calibration_slope_ppm_spin_box</cstring> | ||||
|                  </property> | ||||
|                 </widget> | ||||
|                </item> | ||||
|                <item row="1" column="1"> | ||||
|                 <widget class="QDoubleSpinBox" name="calibration_slope_ppm_spin_box"> | ||||
|                  <property name="alignment"> | ||||
|                   <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|                  </property> | ||||
|                  <property name="suffix"> | ||||
|                   <string> ppm</string> | ||||
|                  </property> | ||||
|                  <property name="decimals"> | ||||
|                   <number>4</number> | ||||
|                  </property> | ||||
|                  <property name="minimum"> | ||||
|                   <double>-999.999900000000025</double> | ||||
|                  </property> | ||||
|                  <property name="maximum"> | ||||
|                   <double>999.999900000000025</double> | ||||
|                  </property> | ||||
|                  <property name="singleStep"> | ||||
|                   <double>0.100000000000000</double> | ||||
|                  </property> | ||||
|                  <property name="value"> | ||||
|                   <double>0.000000000000000</double> | ||||
|                  </property> | ||||
|                 </widget> | ||||
|                </item> | ||||
|               </layout> | ||||
|              </widget> | ||||
|             </item> | ||||
|             <item> | ||||
|              <spacer name="verticalSpacer_6"> | ||||
|               <property name="orientation"> | ||||
|                <enum>Qt::Vertical</enum> | ||||
|               </property> | ||||
|               <property name="sizeHint" stdset="0"> | ||||
|                <size> | ||||
|                 <width>20</width> | ||||
|                 <height>40</height> | ||||
|                </size> | ||||
|               </property> | ||||
|              </spacer> | ||||
|             </item> | ||||
|            </layout> | ||||
|           </item> | ||||
|          </layout> | ||||
|         </widget> | ||||
| @ -1992,6 +2013,9 @@ Right click for insert and delete options.</string> | ||||
|             <property name="wordWrap"> | ||||
|              <bool>true</bool> | ||||
|             </property> | ||||
|             <attribute name="horizontalHeaderCascadingSectionResizes"> | ||||
|              <bool>true</bool> | ||||
|             </attribute> | ||||
|             <attribute name="horizontalHeaderStretchLastSection"> | ||||
|              <bool>true</bool> | ||||
|             </attribute> | ||||
| @ -2274,6 +2298,7 @@ soundcard changes</string> | ||||
|   <tabstop>udpWindowToFront</tabstop> | ||||
|   <tabstop>udpWindowRestore</tabstop> | ||||
|   <tabstop>frequencies_table_view</tabstop> | ||||
|   <tabstop>reset_frequencies_push_button</tabstop> | ||||
|   <tabstop>calibration_intercept_spin_box</tabstop> | ||||
|   <tabstop>calibration_slope_ppm_spin_box</tabstop> | ||||
|   <tabstop>stations_table_view</tabstop> | ||||
| @ -2351,12 +2376,12 @@ soundcard changes</string> | ||||
|   </connection> | ||||
|  </connections> | ||||
|  <buttongroups> | ||||
|   <buttongroup name="CAT_handshake_button_group"/> | ||||
|   <buttongroup name="split_mode_button_group"/> | ||||
|   <buttongroup name="CAT_data_bits_button_group"/> | ||||
|   <buttongroup name="CAT_stop_bits_button_group"/> | ||||
|   <buttongroup name="TX_audio_source_button_group"/> | ||||
|   <buttongroup name="PTT_method_button_group"/> | ||||
|   <buttongroup name="TX_mode_button_group"/> | ||||
|   <buttongroup name="CAT_handshake_button_group"/> | ||||
|   <buttongroup name="TX_audio_source_button_group"/> | ||||
|   <buttongroup name="CAT_stop_bits_button_group"/> | ||||
|   <buttongroup name="CAT_data_bits_button_group"/> | ||||
|   <buttongroup name="PTT_method_button_group"/> | ||||
|  </buttongroups> | ||||
| </ui> | ||||
|  | ||||
| @ -4,15 +4,24 @@ | ||||
| 
 | ||||
| #include "CandidateKeyFilter.hpp" | ||||
| 
 | ||||
| ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel const * referencing_model | ||||
|                                         , QAbstractItemModel * referenced_model | ||||
|                                         , int referencing_key_column | ||||
| ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel * referenced_model | ||||
|                                         , int referenced_key_column | ||||
|                                         , QObject * parent | ||||
|                                         , int referencing_key_role | ||||
|                                         , int referenced_key_role) | ||||
|   : QStyledItemDelegate {parent} | ||||
|   , candidate_key_filter_ {new CandidateKeyFilter {referencing_model, referenced_model, referencing_key_column, referenced_key_column, referencing_key_role, referenced_key_role}} | ||||
|   , candidate_key_filter_ {new CandidateKeyFilter {referenced_model, referenced_key_column, nullptr, referenced_key_role}} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel * referenced_model | ||||
|                                         , QAbstractItemModel const * referencing_model | ||||
|                                         , int referenced_key_column | ||||
|                                         , int referencing_key_column | ||||
|                                         , QObject * parent | ||||
|                                         , int referenced_key_role | ||||
|                                         , int referencing_key_role) | ||||
|   : QStyledItemDelegate {parent} | ||||
|   , candidate_key_filter_ {new CandidateKeyFilter {referenced_model, referencing_model, referenced_key_column, referencing_key_column, nullptr, referenced_key_role, referencing_key_role}} | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -17,13 +17,20 @@ class ForeignKeyDelegate final | ||||
|   : public QStyledItemDelegate | ||||
| { | ||||
| public: | ||||
|   explicit ForeignKeyDelegate (QAbstractItemModel const * referencing_model | ||||
|                                , QAbstractItemModel * referenced_model | ||||
|                                , int referencing_key_column = 0 | ||||
|                                , int referenced_key_column = 0 | ||||
|   // many to many relationship
 | ||||
|   explicit ForeignKeyDelegate (QAbstractItemModel * referenced_model | ||||
|                                , int referenced_key_column | ||||
|                                , QObject * parent = nullptr | ||||
|                                , int referencing_key_role = Qt::EditRole | ||||
|                                , int referenced_key_role = Qt::EditRole); | ||||
| 
 | ||||
|   // one to many (referenced to referencing) relationship
 | ||||
|   explicit ForeignKeyDelegate (QAbstractItemModel * referenced_model | ||||
|                                , QAbstractItemModel const * referencing_model | ||||
|                                , int referenced_key_column | ||||
|                                , int referencing_key_column | ||||
|                                , QObject * parent = nullptr | ||||
|                                , int referenced_key_role = Qt::EditRole | ||||
|                                , int referencing_key_role = Qt::EditRole); | ||||
|   ~ForeignKeyDelegate (); | ||||
| 
 | ||||
|   QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; | ||||
|  | ||||
| @ -1,15 +1,6 @@ | ||||
| #include "FrequencyItemDelegate.hpp" | ||||
| 
 | ||||
| #include "Radio.hpp" | ||||
| #include "FrequencyLineEdit.hpp" | ||||
| #include "Bands.hpp" | ||||
| 
 | ||||
| QString FrequencyItemDelegate::displayText (QVariant const& value, QLocale const& locale) const | ||||
| { | ||||
|   auto frequency = value.value<Radio::Frequency> (); | ||||
|   auto band_name = bands_->data (bands_->find (frequency)); | ||||
|   return Radio::pretty_frequency_MHz_string (frequency, locale) + " MHz (" + band_name.toString () + ')'; | ||||
| } | ||||
| 
 | ||||
| QWidget * FrequencyItemDelegate::createEditor (QWidget * parent | ||||
| 					       , QStyleOptionViewItem const& /* option */ | ||||
| @ -21,11 +12,6 @@ QWidget * FrequencyItemDelegate::createEditor (QWidget * parent | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| QString FrequencyDeltaItemDelegate::displayText (QVariant const& value, QLocale const& locale) const | ||||
| { | ||||
|   return Radio::pretty_frequency_MHz_string (value.value<Radio::FrequencyDelta> (), locale) + " MHz"; | ||||
| } | ||||
| 
 | ||||
| QWidget * FrequencyDeltaItemDelegate::createEditor (QWidget * parent | ||||
| 					       , QStyleOptionViewItem const& /* option */ | ||||
| 					       , QModelIndex const& /* index */) const | ||||
|  | ||||
| @ -1,53 +1,45 @@ | ||||
| #ifndef FREQUENCY_ITEM_DELEGATE_HPP_ | ||||
| #define FREQUENCY_ITEM_DELEGATE_HPP_ | ||||
| 
 | ||||
| #include <QStyledItemDelegate> | ||||
| 
 | ||||
| class Bands; | ||||
| 
 | ||||
| //
 | ||||
| // Class FrequencyItemDelegate
 | ||||
| //
 | ||||
| //	Item delegate for displaying and editing a Frequency item in a
 | ||||
| //	view that uses a FrequencyLineEdit as an item delegate for the
 | ||||
| //	edit role.
 | ||||
| //
 | ||||
| class FrequencyItemDelegate final | ||||
|   : public QStyledItemDelegate | ||||
| { | ||||
| public: | ||||
|   explicit FrequencyItemDelegate (Bands const * bands, QObject * parent = nullptr) | ||||
|     : QStyledItemDelegate {parent} | ||||
|     , bands_ {bands} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   QString displayText (QVariant const& value, QLocale const&) const override; | ||||
|   QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; | ||||
| 
 | ||||
| private: | ||||
|   Bands const * bands_; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| //
 | ||||
| // Class FrequencyDeltaItemDelegate
 | ||||
| //
 | ||||
| //	Item delegate for displaying and editing a FrequencyDelta item
 | ||||
| //	in a view that uses a FrequencyDeltaLineEdit as an item
 | ||||
| //	delegate for the edit role.
 | ||||
| //
 | ||||
| class FrequencyDeltaItemDelegate final | ||||
|   : public QStyledItemDelegate | ||||
| { | ||||
| public: | ||||
|   explicit FrequencyDeltaItemDelegate (QObject * parent = nullptr) | ||||
|     : QStyledItemDelegate {parent} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   QString displayText (QVariant const& value, QLocale const&) const override; | ||||
|   QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| #ifndef FREQUENCY_ITEM_DELEGATE_HPP_ | ||||
| #define FREQUENCY_ITEM_DELEGATE_HPP_ | ||||
| 
 | ||||
| #include <QStyledItemDelegate> | ||||
| 
 | ||||
| //
 | ||||
| // Class FrequencyItemDelegate
 | ||||
| //
 | ||||
| //	Item delegate for displaying and editing a Frequency item in a
 | ||||
| //	view that uses a FrequencyLineEdit as an item delegate for the
 | ||||
| //	edit role.
 | ||||
| //
 | ||||
| class FrequencyItemDelegate final | ||||
|   : public QStyledItemDelegate | ||||
| { | ||||
| public: | ||||
|   explicit FrequencyItemDelegate (QObject * parent = nullptr) | ||||
|     : QStyledItemDelegate {parent} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| //
 | ||||
| // Class FrequencyDeltaItemDelegate
 | ||||
| //
 | ||||
| //	Item delegate for displaying and editing a FrequencyDelta item
 | ||||
| //	in a view that uses a FrequencyDeltaLineEdit as an item
 | ||||
| //	delegate for the edit role.
 | ||||
| //
 | ||||
| class FrequencyDeltaItemDelegate final | ||||
|   : public QStyledItemDelegate | ||||
| { | ||||
| public: | ||||
|   explicit FrequencyDeltaItemDelegate (QObject * parent = nullptr) | ||||
|     : QStyledItemDelegate {parent} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -11,25 +11,120 @@ | ||||
| #include <QMimeData> | ||||
| #include <QDataStream> | ||||
| #include <QByteArray> | ||||
| #include <QDebug> | ||||
| 
 | ||||
| #include "Bands.hpp" | ||||
| #include "pimpl_impl.hpp" | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   FrequencyList::FrequencyItems const default_frequency_list = | ||||
|     { | ||||
|       {136000, Modes::WSPR}, | ||||
|       {136130, Modes::JT65}, | ||||
|       {474200, Modes::JT65}, | ||||
|       {474200, Modes::JT9}, | ||||
|       {474200, Modes::WSPR}, | ||||
|       {1836600, Modes::WSPR}, | ||||
|       {1838000, Modes::JT65}, | ||||
|       {1840000, Modes::JT9}, | ||||
|       {3576000, Modes::JT65}, | ||||
|       {3578000, Modes::JT9}, | ||||
|       {3559260, Modes::WSPR}, | ||||
|       {5357000, Modes::JT65}, | ||||
|       {5287200, Modes::WSPR}, | ||||
|       {7038600, Modes::WSPR}, | ||||
|       {7076000, Modes::JT65}, | ||||
|       {7078000, Modes::JT9}, | ||||
|       {10138000, Modes::JT65}, | ||||
|       {10138700, Modes::WSPR}, | ||||
|       {10140000, Modes::JT9}, | ||||
|       {14095600, Modes::WSPR}, | ||||
|       {14076000, Modes::JT65}, | ||||
|       {14078000, Modes::JT9}, | ||||
|       {18102000, Modes::JT65}, | ||||
|       {18104000, Modes::JT9}, | ||||
|       {18104460, Modes::WSPR}, | ||||
|       {21076000, Modes::JT65}, | ||||
|       {21078000, Modes::JT9}, | ||||
|       {21094600, Modes::WSPR}, | ||||
|       {24917000, Modes::JT65}, | ||||
|       {24919000, Modes::JT9}, | ||||
|       {24924600, Modes::WSPR}, | ||||
|       {28076000, Modes::JT65}, | ||||
|       {28078000, Modes::JT9}, | ||||
|       {28124600, Modes::WSPR}, | ||||
|       {50276000, Modes::JT65}, | ||||
|       {50293000, Modes::WSPR}, | ||||
|       {70091000, Modes::JT65}, | ||||
|       {70091000, Modes::WSPR}, | ||||
|       {144000000, Modes::JT4}, | ||||
|       {144489000, Modes::JT65}, | ||||
|       {144489000, Modes::WSPR}, | ||||
|       {222000000, Modes::JT4}, | ||||
|       {222000000, Modes::JT65}, | ||||
|       {432000000, Modes::JT4}, | ||||
|       {432000000, Modes::JT65}, | ||||
|       {432300000, Modes::WSPR}, | ||||
|       {902000000, Modes::JT4}, | ||||
|       {902000000, Modes::JT65}, | ||||
|       {1296000000, Modes::JT4}, | ||||
|       {1296000000, Modes::JT65}, | ||||
|       {1296500000, Modes::WSPR}, | ||||
|       {2301000000, Modes::JT4}, | ||||
|       {2301000000, Modes::JT65}, | ||||
|       {2304000000, Modes::JT4}, | ||||
|       {2304000000, Modes::JT65}, | ||||
|       {2320000000, Modes::JT4}, | ||||
|       {2320000000, Modes::JT65}, | ||||
|       {3400000000, Modes::JT4}, | ||||
|       {3400000000, Modes::JT65}, | ||||
|       {3456000000, Modes::JT4}, | ||||
|       {3456000000, Modes::JT65}, | ||||
|       {5760000000, Modes::JT4}, | ||||
|       {5760000000, Modes::JT65}, | ||||
|       {10368000000, Modes::JT4}, | ||||
|       {10368000000, Modes::JT65}, | ||||
|       {24048000000, Modes::JT4}, | ||||
|       {24048000000, Modes::JT65}, | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| QDebug operator << (QDebug debug, FrequencyList::Item const& item) | ||||
| { | ||||
|   debug.nospace () << "FrequencyItem(" | ||||
|                    << item.frequency_ << ", " | ||||
|                    << item.mode_ << ')'; | ||||
|   return debug.space (); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| 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_; | ||||
| } | ||||
| 
 | ||||
| class FrequencyList::impl final | ||||
|   : public QAbstractTableModel | ||||
| { | ||||
| public: | ||||
|   impl (Frequencies frequencies, QObject * parent) | ||||
|   impl (Bands const * bands, QObject * parent) | ||||
|     : QAbstractTableModel {parent} | ||||
|     , frequencies_ {frequencies} | ||||
|     , bands_ {bands} | ||||
|     , mode_filter_ {Modes::NULL_MODE} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   Frequencies const& frequencies () const {return frequencies_;} | ||||
|   void assign (Frequencies); | ||||
|   QModelIndex add (Frequency); | ||||
|   FrequencyItems frequency_list (FrequencyItems); | ||||
|   QModelIndex add (Item); | ||||
| 
 | ||||
| protected: | ||||
|   // Implement the QAbstractTableModel interface
 | ||||
|   int rowCount (QModelIndex const& parent = QModelIndex {}) const override; | ||||
|   int columnCount (QModelIndex const& parent = QModelIndex {}) const override; | ||||
| @ -42,21 +137,17 @@ protected: | ||||
|   QStringList mimeTypes () const override; | ||||
|   QMimeData * mimeData (QModelIndexList const&) const override; | ||||
| 
 | ||||
| private: | ||||
|   static int constexpr num_cols {2}; | ||||
|   static int constexpr num_cols {3}; | ||||
|   static auto constexpr mime_type ="application/wsjt.Frequencies"; | ||||
| 
 | ||||
|   Frequencies frequencies_; | ||||
|   Bands const * bands_; | ||||
|   FrequencyItems frequency_list_; | ||||
|   Mode mode_filter_; | ||||
| }; | ||||
| 
 | ||||
| FrequencyList::FrequencyList (QObject * parent) | ||||
|   : FrequencyList {{}, parent} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| FrequencyList::FrequencyList (Frequencies frequencies, QObject * parent) | ||||
| FrequencyList::FrequencyList (Bands const * bands, QObject * parent) | ||||
|   : QSortFilterProxyModel {parent} | ||||
|   , m_ {frequencies, parent} | ||||
|   , m_ {bands, parent} | ||||
| { | ||||
|   setSourceModel (&*m_); | ||||
|   setSortRole (SortRole); | ||||
| @ -66,25 +157,52 @@ FrequencyList::~FrequencyList () | ||||
| { | ||||
| } | ||||
| 
 | ||||
| FrequencyList& FrequencyList::operator = (Frequencies frequencies) | ||||
| auto FrequencyList::frequency_list (FrequencyItems frequency_list) -> FrequencyItems | ||||
| { | ||||
|   m_->assign (frequencies); | ||||
|   return *this; | ||||
|   return m_->frequency_list (frequency_list); | ||||
| } | ||||
| 
 | ||||
| auto FrequencyList::frequencies () const -> Frequencies | ||||
| auto FrequencyList::frequency_list () const -> FrequencyItems const& | ||||
| { | ||||
|   return m_->frequencies (); | ||||
|   return m_->frequency_list_; | ||||
| } | ||||
| 
 | ||||
| QModelIndex FrequencyList::add (Frequency f) | ||||
| QModelIndex FrequencyList::best_working_frequency (Frequency f, Mode mode) const | ||||
| { | ||||
|   auto const& target_band = m_->bands_->find (f); | ||||
|   if (target_band != m_->bands_->out_of_band ()) | ||||
|     { | ||||
|       // find a frequency in the same band that is allowed for the
 | ||||
|       // target mode
 | ||||
|       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->name_ == target_band->name_) | ||||
|             { | ||||
|               if (m_->frequency_list_[source_row].mode_ == mode) | ||||
|                 { | ||||
|                   return index (row, 0); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   return QModelIndex {}; | ||||
| } | ||||
| 
 | ||||
| void FrequencyList::reset_to_defaults () | ||||
| { | ||||
|   m_->frequency_list (default_frequency_list); | ||||
| } | ||||
| 
 | ||||
| QModelIndex FrequencyList::add (Item f) | ||||
| { | ||||
|   return mapFromSource (m_->add (f)); | ||||
| } | ||||
| 
 | ||||
| bool FrequencyList::remove (Frequency f) | ||||
| bool FrequencyList::remove (Item f) | ||||
| { | ||||
|   auto row = m_->frequencies ().indexOf (f); | ||||
|   auto row = m_->frequency_list_.indexOf (f); | ||||
| 
 | ||||
|   if (0 > row) | ||||
|     { | ||||
| @ -123,38 +241,54 @@ bool FrequencyList::removeDisjointRows (QModelIndexList rows) | ||||
|           result = false; | ||||
|         } | ||||
|     } | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| void FrequencyList::filter (Mode mode) | ||||
| { | ||||
|   m_->mode_filter_ = mode; | ||||
|   invalidateFilter (); | ||||
| } | ||||
| 
 | ||||
| bool FrequencyList::filterAcceptsRow (int source_row, QModelIndex const& /* parent */) const | ||||
| { | ||||
|   bool result {true}; | ||||
|   if (m_->mode_filter_ != Modes::NULL_MODE) | ||||
|     { | ||||
|       auto const& item = m_->frequency_list_[source_row]; | ||||
|       result = item.mode_ == Modes::NULL_MODE || m_->mode_filter_ == item.mode_; | ||||
|     } | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void FrequencyList::impl::assign (Frequencies frequencies) | ||||
| auto FrequencyList::impl::frequency_list (FrequencyItems frequency_list) -> FrequencyItems | ||||
| { | ||||
|   beginResetModel (); | ||||
|   std::swap (frequencies_, frequencies); | ||||
|   std::swap (frequency_list_, frequency_list); | ||||
|   endResetModel (); | ||||
|   return frequency_list; | ||||
| } | ||||
| 
 | ||||
| QModelIndex FrequencyList::impl::add (Frequency f) | ||||
| QModelIndex FrequencyList::impl::add (Item f) | ||||
| { | ||||
|   // Any Frequency that isn't in the list may be added
 | ||||
|   if (!frequencies_.contains (f)) | ||||
|   if (!frequency_list_.contains (f)) | ||||
|     { | ||||
|       auto row = frequencies_.size (); | ||||
|       auto row = frequency_list_.size (); | ||||
| 
 | ||||
|       beginInsertRows (QModelIndex {}, row, row); | ||||
|       frequencies_.append (f); | ||||
|       frequency_list_.append (f); | ||||
|       endInsertRows (); | ||||
| 
 | ||||
|       return index (row, 0); | ||||
|     } | ||||
| 
 | ||||
|   return QModelIndex {}; | ||||
| } | ||||
| 
 | ||||
| int FrequencyList::impl::rowCount (QModelIndex const& parent) const | ||||
| { | ||||
|   return parent.isValid () ? 0 : frequencies_.size (); | ||||
|   return parent.isValid () ? 0 : frequency_list_.size (); | ||||
| } | ||||
| 
 | ||||
| int FrequencyList::impl::columnCount (QModelIndex const& parent) const | ||||
| @ -165,26 +299,17 @@ int FrequencyList::impl::columnCount (QModelIndex const& parent) const | ||||
| Qt::ItemFlags FrequencyList::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 < frequencies_.size () | ||||
|       && row < frequency_list_.size () | ||||
|       && column < num_cols) | ||||
|     { | ||||
|       switch (column) | ||||
|       if (frequency_mhz_column != column) | ||||
|         { | ||||
|         case 0: | ||||
|           result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; | ||||
|           break; | ||||
| 
 | ||||
|         case 1: | ||||
|           result |= Qt::ItemIsDragEnabled; | ||||
|           break; | ||||
|           result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| @ -192,25 +317,51 @@ QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const | ||||
| { | ||||
|   QVariant item; | ||||
| 
 | ||||
|   auto row = index.row (); | ||||
|   auto column = index.column (); | ||||
|   auto const& row = index.row (); | ||||
|   auto const& column = index.column (); | ||||
| 
 | ||||
|   if (index.isValid () | ||||
|       && row < frequencies_.size () | ||||
|       && row < frequency_list_.size () | ||||
|       && column < num_cols) | ||||
|     { | ||||
|       auto frequency = frequencies_.at (row); | ||||
| 
 | ||||
|       auto const& frequency_item = frequency_list_.at (row); | ||||
|       switch (column) | ||||
|         { | ||||
|         case 0: | ||||
|         case mode_column: | ||||
|           switch (role) | ||||
|             { | ||||
|             case SortRole: | ||||
|             case Qt::DisplayRole: | ||||
|             case Qt::EditRole: | ||||
|             case Qt::AccessibleTextRole: | ||||
|               item = frequency; | ||||
|               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->name_ + ')'; | ||||
|               } | ||||
|               break; | ||||
| 
 | ||||
|             case Qt::ToolTipRole: | ||||
| @ -224,22 +375,24 @@ QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const | ||||
|             } | ||||
|           break; | ||||
| 
 | ||||
|         case 1: | ||||
|         case frequency_mhz_column: | ||||
|           switch (role) | ||||
|             { | ||||
|             case Qt::DisplayRole: | ||||
|             case Qt::EditRole: | ||||
|             case Qt::AccessibleTextRole: | ||||
|               item = static_cast<double> (frequency / 1.e6); | ||||
|               item = frequency_item.frequency_ / 1.e6; | ||||
|               break; | ||||
| 
 | ||||
|             case SortRole:	// use the underlying Frequency value
 | ||||
|               item = frequency; | ||||
|             case Qt::DisplayRole: | ||||
|               { | ||||
|                 auto const& band = bands_->find (frequency_item.frequency_); | ||||
|                 item = Radio::pretty_frequency_MHz_string (frequency_item.frequency_) + " MHz (" + band->name_ + ')'; | ||||
|               } | ||||
|               break; | ||||
| 
 | ||||
|             case Qt::ToolTipRole: | ||||
|             case Qt::AccessibleDescriptionRole: | ||||
|               item = tr ("Frequency MHz"); | ||||
|               item = tr ("Frequency (MHz)"); | ||||
|               break; | ||||
| 
 | ||||
|             case Qt::TextAlignmentRole: | ||||
| @ -249,7 +402,6 @@ QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const | ||||
|           break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   return item; | ||||
| } | ||||
| 
 | ||||
| @ -257,21 +409,44 @@ bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant cons | ||||
| { | ||||
|   bool changed {false}; | ||||
| 
 | ||||
|   auto row = model_index.row (); | ||||
|   auto const& row = model_index.row (); | ||||
|   if (model_index.isValid () | ||||
|       && Qt::EditRole == role | ||||
|       && row < frequencies_.size () | ||||
|       && 0 == model_index.column () | ||||
|       && value.canConvert<Frequency> ()) | ||||
|       && row < frequency_list_.size ()) | ||||
|     { | ||||
|       auto frequency = value.value<Frequency> (); | ||||
|       auto original_frequency = frequencies_.at (row); | ||||
|       if (frequency != original_frequency) | ||||
|       QVector<int> roles; | ||||
|       roles << role; | ||||
| 
 | ||||
|       auto& item = frequency_list_[row]; | ||||
|       switch (model_index.column ()) | ||||
|         { | ||||
|           frequencies_.replace (row, frequency); | ||||
|           Q_EMIT dataChanged (model_index, index (model_index.row (), 1), QVector<int> {} << role); | ||||
|         case mode_column: | ||||
|           if (value.canConvert<Mode> ()) | ||||
|             { | ||||
|               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<Frequency> ()) | ||||
|             { | ||||
|               auto frequency = value.value<Frequency> (); | ||||
|               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; | ||||
|         } | ||||
|       changed = true; | ||||
|     } | ||||
| 
 | ||||
|   return changed; | ||||
| @ -280,22 +455,21 @@ bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant cons | ||||
| QVariant FrequencyList::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 0: header = tr ("Frequency"); break; | ||||
|         case 1: header = tr ("Frequency (MHz)"); 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; | ||||
| } | ||||
| 
 | ||||
| @ -306,12 +480,11 @@ bool FrequencyList::impl::removeRows (int row, int count, QModelIndex const& par | ||||
|       beginRemoveRows (parent, row, row + count - 1); | ||||
|       for (auto r = 0; r < count; ++r) | ||||
|         { | ||||
|           frequencies_.removeAt (row); | ||||
|           frequency_list_.removeAt (row); | ||||
|         } | ||||
|       endRemoveRows (); | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| @ -322,12 +495,11 @@ bool FrequencyList::impl::insertRows (int row, int count, QModelIndex const& par | ||||
|       beginInsertRows (parent, row, row + count - 1); | ||||
|       for (auto r = 0; r < count; ++r) | ||||
|         { | ||||
|           frequencies_.insert (row, Frequency {}); | ||||
|           frequency_list_.insert (row, Item {0, Mode::NULL_MODE}); | ||||
|         } | ||||
|       endInsertRows (); | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| @ -346,7 +518,7 @@ QMimeData * FrequencyList::impl::mimeData (QModelIndexList const& items) const | ||||
| 
 | ||||
|   Q_FOREACH (auto const& item, items) | ||||
|     { | ||||
|       if (item.isValid ()) | ||||
|       if (item.isValid () && frequency_column == item.column ()) | ||||
|         { | ||||
|           stream << QString {data (item, Qt::DisplayRole).toString ()}; | ||||
|         } | ||||
|  | ||||
| @ -3,9 +3,13 @@ | ||||
| 
 | ||||
| #include "pimpl_h.hpp" | ||||
| 
 | ||||
| #include <QList> | ||||
| #include <QSortFilterProxyModel> | ||||
| 
 | ||||
| #include "Radio.hpp" | ||||
| #include "Modes.hpp" | ||||
| 
 | ||||
| class Bands; | ||||
| 
 | ||||
| //
 | ||||
| // Class FrequencyList
 | ||||
| @ -31,23 +35,45 @@ | ||||
| class FrequencyList final | ||||
|   : public QSortFilterProxyModel | ||||
| { | ||||
|   Q_OBJECT; | ||||
| 
 | ||||
| public: | ||||
|   using Frequency = Radio::Frequency; | ||||
|   using Frequencies = Radio::Frequencies; | ||||
|   using Mode = Modes::Mode; | ||||
| 
 | ||||
|   explicit FrequencyList (QObject * parent = nullptr); | ||||
|   explicit FrequencyList (Frequencies, QObject * parent = nullptr); | ||||
|   struct Item | ||||
|   { | ||||
|     Frequency frequency_; | ||||
|     Mode mode_; | ||||
|   }; | ||||
|   using FrequencyItems = QList<Item>; | ||||
| 
 | ||||
|   enum Column {mode_column, frequency_column, frequency_mhz_column}; | ||||
| 
 | ||||
|   explicit FrequencyList (Bands const *, QObject * parent = nullptr); | ||||
|   ~FrequencyList (); | ||||
| 
 | ||||
|   // Load and store contents
 | ||||
|   FrequencyList& operator = (Frequencies); | ||||
|   Frequencies frequencies () const; | ||||
|   FrequencyItems frequency_list (FrequencyItems); | ||||
|   FrequencyItems const& frequency_list () const; | ||||
| 
 | ||||
|   // Find nearest best working frequency given a frequency and mode
 | ||||
|   QModelIndex best_working_frequency (Frequency, Mode) const; | ||||
| 
 | ||||
|   // Set filter
 | ||||
|   void filter (Mode); | ||||
| 
 | ||||
|   // Reset
 | ||||
|   Q_SLOT void reset_to_defaults (); | ||||
| 
 | ||||
|   // Model API
 | ||||
|   QModelIndex add (Frequency); | ||||
|   bool remove (Frequency); | ||||
|   QModelIndex add (Item); | ||||
|   bool remove (Item); | ||||
|   bool removeDisjointRows (QModelIndexList); | ||||
| 
 | ||||
|   // Proxy API
 | ||||
|   bool filterAcceptsRow (int source_row, QModelIndex const& parent) const override; | ||||
| 
 | ||||
|   // Custom roles.
 | ||||
|   static int constexpr SortRole = Qt::UserRole; | ||||
| 
 | ||||
| @ -56,4 +82,22 @@ private: | ||||
|   pimpl<impl> m_; | ||||
| }; | ||||
| 
 | ||||
| inline | ||||
| bool operator == (FrequencyList::Item const& lhs, FrequencyList::Item const& rhs) | ||||
| { | ||||
|   return | ||||
|     lhs.frequency_ == rhs.frequency_ | ||||
|     && lhs.mode_ == rhs.mode_; | ||||
| } | ||||
| 
 | ||||
| QDataStream& operator << (QDataStream&, FrequencyList::Item const&); | ||||
| QDataStream& operator >> (QDataStream&, FrequencyList::Item&); | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| QDebug operator << (QDebug, FrequencyList::Item const&); | ||||
| #endif | ||||
| 
 | ||||
| Q_DECLARE_METATYPE (FrequencyList::Item); | ||||
| Q_DECLARE_METATYPE (FrequencyList::FrequencyItems); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -1,92 +1,87 @@ | ||||
| #include "LiveFrequencyValidator.hpp" | ||||
| 
 | ||||
| #include <QLocale> | ||||
| #include <QString> | ||||
| #include <QComboBox> | ||||
| #include <QLineEdit> | ||||
| 
 | ||||
| #include "Bands.hpp" | ||||
| #include "FrequencyList.hpp" | ||||
| 
 | ||||
| #include "moc_LiveFrequencyValidator.cpp" | ||||
| 
 | ||||
| LiveFrequencyValidator::LiveFrequencyValidator (QComboBox * combo_box | ||||
|                                                 , Bands const * bands | ||||
|                                                 , FrequencyList const * frequencies | ||||
|                                                 , QWidget * parent) | ||||
|   : QRegExpValidator { | ||||
|   QRegExp {				// frequency in MHz or band
 | ||||
|     bands->data (QModelIndex {}).toString () // out of band string
 | ||||
|       + QString {R"(|((\d{0,6}(\)"}		 // up to 6 digits
 | ||||
|     + QLocale {}.decimalPoint () // (followed by decimal separator
 | ||||
|                    + R"(\d{0,2})?)([Mm]{1,2}|([Cc][Mm])))|(\d{0,4}(\)" // followed by up to 2 digits and either 'm' or 'cm' or 'mm' (case insensitive))
 | ||||
|                    + QLocale {}.decimalPoint () // or a decimal separator
 | ||||
|                                   + R"(\d{0,6})?))"	       //  followed by up to 6 digits
 | ||||
|                                   } | ||||
|   , parent | ||||
|       } | ||||
|   , bands_ {bands} | ||||
|   , frequencies_ {frequencies} | ||||
|   , combo_box_ {combo_box} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| auto LiveFrequencyValidator::validate (QString& input, int& pos) const -> State | ||||
| { | ||||
|   auto state = QRegExpValidator::validate (input, pos); | ||||
| 
 | ||||
|   // by never being Acceptable we force fixup calls on ENTER or
 | ||||
|   // losing focus
 | ||||
|   return Acceptable == state ? Intermediate : state; | ||||
| } | ||||
| 
 | ||||
| void LiveFrequencyValidator::fixup (QString& input) const | ||||
| { | ||||
|   QRegExpValidator::fixup (input); | ||||
| 
 | ||||
|   auto out_of_band = bands_->data (QModelIndex {}).toString (); | ||||
| 
 | ||||
|   if (!out_of_band.startsWith (input)) | ||||
|     { | ||||
|       if (input.contains ('m', Qt::CaseInsensitive)) | ||||
| 	{ | ||||
| 	  input = input.toLower (); | ||||
| 
 | ||||
| 	  QVector<QVariant> frequencies; | ||||
| 	  for (int r = 0; r < frequencies_->rowCount (); ++r) | ||||
| 	    { | ||||
| 	      auto frequency = frequencies_->index (r, 0).data (); | ||||
| 	      auto band_index = bands_->find (frequency); | ||||
| 	      if (band_index.data ().toString () == input) | ||||
| 		{ | ||||
| 		  frequencies << frequency; | ||||
| 		} | ||||
| 	    } | ||||
| 	  if (!frequencies.isEmpty ()) | ||||
| 	    { | ||||
| 	      Q_EMIT valid (frequencies.first ().value<Frequency> ()); | ||||
| 	    } | ||||
| 	  else | ||||
| 	    { | ||||
| 	      input = QString {}; | ||||
| 	    } | ||||
| 	} | ||||
|       else | ||||
| 	{ | ||||
| 	  // frequency input
 | ||||
| 	  auto f = Radio::frequency (input, 6); | ||||
| 	  input = bands_->data (bands_->find (f)).toString (); | ||||
| 	  Q_EMIT valid (f); | ||||
| 	} | ||||
| 
 | ||||
|       if (out_of_band == input) | ||||
| 	{ | ||||
| 	  combo_box_->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}"); | ||||
| 	} | ||||
|       else | ||||
| 	{ | ||||
| 	  combo_box_->lineEdit ()->setStyleSheet ({}); | ||||
| 	} | ||||
|       combo_box_->setCurrentText (input); | ||||
|     } | ||||
| } | ||||
| #include "LiveFrequencyValidator.hpp" | ||||
| 
 | ||||
| #include <QLocale> | ||||
| #include <QString> | ||||
| #include <QComboBox> | ||||
| #include <QLineEdit> | ||||
| 
 | ||||
| #include "Bands.hpp" | ||||
| #include "FrequencyList.hpp" | ||||
| 
 | ||||
| #include "moc_LiveFrequencyValidator.cpp" | ||||
| 
 | ||||
| LiveFrequencyValidator::LiveFrequencyValidator (QComboBox * combo_box | ||||
|                                                 , Bands const * bands | ||||
|                                                 , FrequencyList const * frequencies | ||||
|                                                 , QWidget * parent) | ||||
|   : QRegExpValidator { | ||||
|       QRegExp {       // frequency in MHz or band
 | ||||
|         bands->data (QModelIndex {}).toString () // out of band string
 | ||||
|           + QString {R"(|((\d{0,6}(\)"}    // or up to 6 digits
 | ||||
|           + QLocale {}.decimalPoint () // (followed by decimal separator
 | ||||
|           + R"(\d{0,2})?)([Mm]{1,2}|([Cc][Mm])))|(\d{0,4}(\)" // followed by up to 2 digits and either 'm' or 'cm' or 'mm' (case insensitive))
 | ||||
|           + QLocale {}.decimalPoint () // or a decimal separator
 | ||||
|           + R"(\d{0,6})?))"        //  followed by up to 6 digits
 | ||||
|       } | ||||
|       , parent | ||||
|     } | ||||
|   , bands_ {bands} | ||||
|   , frequencies_ {frequencies} | ||||
|   , combo_box_ {combo_box} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| auto LiveFrequencyValidator::validate (QString& input, int& pos) const -> State | ||||
| { | ||||
|   auto state = QRegExpValidator::validate (input, pos); | ||||
|   // by never being Acceptable we force fixup calls on ENTER or
 | ||||
|   // losing focus
 | ||||
|   return Acceptable == state ? Intermediate : state; | ||||
| } | ||||
| 
 | ||||
| void LiveFrequencyValidator::fixup (QString& input) const | ||||
| { | ||||
|   QRegExpValidator::fixup (input); | ||||
|   auto const& out_of_band = bands_->out_of_band (); | ||||
|   if (!QString {out_of_band->name_}.startsWith (input)) | ||||
|     { | ||||
|       if (input.contains ('m', Qt::CaseInsensitive)) | ||||
|         { | ||||
|           input = input.toLower (); | ||||
| 
 | ||||
|           QVector<QVariant> frequencies; | ||||
|           Q_FOREACH (auto const& item, frequencies_->frequency_list ()) | ||||
|             { | ||||
|               if (bands_->find (item.frequency_)->name_ == input) | ||||
|                 { | ||||
|                   frequencies << item.frequency_; | ||||
|                 } | ||||
|             } | ||||
|           if (!frequencies.isEmpty ()) | ||||
|             { | ||||
|               Q_EMIT valid (frequencies.first ().value<Frequency> ()); | ||||
|             } | ||||
|           else | ||||
|             { | ||||
|               input = QString {}; | ||||
|             } | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           // frequency input
 | ||||
|           auto f = Radio::frequency (input, 6); | ||||
|           input = bands_->find (f)->name_; | ||||
|           Q_EMIT valid (f); | ||||
|         } | ||||
| 
 | ||||
|       if (bands_->out_of_band ()->name_ == input) | ||||
|         { | ||||
|           combo_box_->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}"); | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           combo_box_->lineEdit ()->setStyleSheet ({}); | ||||
|         } | ||||
|       combo_box_->setCurrentText (input); | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										72
									
								
								MetaDataRegistry.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								MetaDataRegistry.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | ||||
| #include "MetaDataRegistry.hpp" | ||||
| 
 | ||||
| #include <QMetaType> | ||||
| #include <QItemEditorFactory> | ||||
| #include <QStandardItemEditorCreator> | ||||
| 
 | ||||
| #include "Radio.hpp" | ||||
| #include "FrequencyList.hpp" | ||||
| #include "AudioDevice.hpp" | ||||
| #include "Configuration.hpp" | ||||
| #include "StationList.hpp" | ||||
| #include "Transceiver.hpp" | ||||
| #include "TransceiverFactory.hpp" | ||||
| #include "WFPalette.hpp" | ||||
| 
 | ||||
| #include "FrequencyLineEdit.hpp" | ||||
| 
 | ||||
| void register_types () | ||||
| { | ||||
|   // Default custom item view delegates
 | ||||
|   auto factory = new QItemEditorFactory; | ||||
| 
 | ||||
|   // Radio namespace
 | ||||
|   auto frequency_type_id = qRegisterMetaType<Radio::Frequency> ("Frequency"); | ||||
|   factory->registerEditor (frequency_type_id, new QStandardItemEditorCreator<FrequencyLineEdit> ()); | ||||
|   auto frequency_delta_type_id = qRegisterMetaType<Radio::FrequencyDelta> ("FrequencyDelta"); | ||||
|   factory->registerEditor (frequency_delta_type_id, new QStandardItemEditorCreator<FrequencyDeltaLineEdit> ()); | ||||
| 
 | ||||
|   // Frequency list model
 | ||||
|   qRegisterMetaType<FrequencyList::Item> ("Item"); | ||||
|   qRegisterMetaTypeStreamOperators<FrequencyList::Item> ("Item"); | ||||
|   qRegisterMetaType<FrequencyList::FrequencyItems> ("FrequencyItems"); | ||||
|   qRegisterMetaTypeStreamOperators<FrequencyList::FrequencyItems> ("FrequencyItems"); | ||||
| 
 | ||||
|   // Audio device
 | ||||
|   qRegisterMetaType<AudioDevice::Channel> ("AudioDevice::Channel"); | ||||
| 
 | ||||
|   // Configuration
 | ||||
|   qRegisterMetaType<Configuration::DataMode> ("Configuration::DataMode"); | ||||
|   qRegisterMetaTypeStreamOperators<Configuration::DataMode> ("Configuration::DataMode"); | ||||
|   qRegisterMetaType<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen"); | ||||
|   qRegisterMetaTypeStreamOperators<Configuration::Type2MsgGen> ("Configuration::Type2MsgGen"); | ||||
| 
 | ||||
|   // Station details
 | ||||
|   qRegisterMetaType<StationList::Station> ("Station"); | ||||
|   qRegisterMetaTypeStreamOperators<StationList::Station> ("Station"); | ||||
|   qRegisterMetaType<StationList::Stations> ("Stations"); | ||||
|   qRegisterMetaTypeStreamOperators<StationList::Stations> ("Stations"); | ||||
| 
 | ||||
|   // Transceiver
 | ||||
|   qRegisterMetaType<Transceiver::TransceiverState> ("Transceiver::TransceiverState"); | ||||
|   qRegisterMetaType<Transceiver::MODE> ("Transceiver::MODE"); | ||||
| 
 | ||||
|   // Transceiver factory
 | ||||
|   qRegisterMetaType<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits"); | ||||
|   qRegisterMetaTypeStreamOperators<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits"); | ||||
|   qRegisterMetaType<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits"); | ||||
|   qRegisterMetaTypeStreamOperators<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits"); | ||||
|   qRegisterMetaType<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake"); | ||||
|   qRegisterMetaTypeStreamOperators<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake"); | ||||
|   qRegisterMetaType<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod"); | ||||
|   qRegisterMetaTypeStreamOperators<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod"); | ||||
|   qRegisterMetaType<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource"); | ||||
|   qRegisterMetaTypeStreamOperators<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource"); | ||||
|   qRegisterMetaType<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode"); | ||||
|   qRegisterMetaTypeStreamOperators<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode"); | ||||
| 
 | ||||
|   // Waterfall palette
 | ||||
|   qRegisterMetaTypeStreamOperators<WFPalette::Colours> ("Colours"); | ||||
| 
 | ||||
|   QItemEditorFactory::setDefaultFactory (factory); | ||||
| } | ||||
							
								
								
									
										6
									
								
								MetaDataRegistry.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								MetaDataRegistry.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| #ifndef META_DATA_REGISTRY_HPP__ | ||||
| #define META_DATA_REGISTRY_HPP__ | ||||
| 
 | ||||
| void register_types (); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										92
									
								
								Modes.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Modes.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| #include "Modes.hpp" | ||||
| 
 | ||||
| #include <QString> | ||||
| #include <QVariant> | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   char const * const mode_names[] = | ||||
|     { | ||||
|       "", | ||||
|       "JT65", | ||||
|       "JT9", | ||||
|       "JT9W-1", | ||||
|       "JT4", | ||||
|       "WSPR", | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| Modes::Modes (QObject * parent) | ||||
|   : QAbstractListModel {parent} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| char const * Modes::name (Mode m) | ||||
| { | ||||
|   return mode_names[static_cast<int> (m)]; | ||||
| } | ||||
| 
 | ||||
| auto Modes::value (QString const& s) -> Mode | ||||
| { | ||||
|   auto end = mode_names + sizeof (mode_names) / sizeof (mode_names[0]); | ||||
|   auto p = std::find_if (mode_names, end | ||||
|                          , [&s] (char const * const name) { | ||||
|                            return name == s; | ||||
|                          }); | ||||
|   return p != end ? static_cast<Mode> (p - mode_names) : NULL_MODE; | ||||
| } | ||||
| 
 | ||||
| QVariant Modes::data (QModelIndex const& index, int role) const | ||||
| { | ||||
|   QVariant item; | ||||
| 
 | ||||
|   if (index.isValid ()) | ||||
|     { | ||||
|       auto const& row = index.row (); | ||||
|       switch (role) | ||||
|         { | ||||
|         case Qt::ToolTipRole: | ||||
|         case Qt::AccessibleDescriptionRole: | ||||
|           item = tr ("Mode"); | ||||
|           break; | ||||
| 
 | ||||
|         case Qt::EditRole: | ||||
|           item = static_cast<Mode> (row); | ||||
|           break; | ||||
| 
 | ||||
|         case Qt::DisplayRole: | ||||
|         case Qt::AccessibleTextRole: | ||||
|           item = mode_names[row]; | ||||
|           break; | ||||
| 
 | ||||
|         case Qt::TextAlignmentRole: | ||||
|           item = Qt::AlignHCenter + Qt::AlignVCenter; | ||||
|           break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   return item; | ||||
| } | ||||
| 
 | ||||
| QVariant Modes::headerData (int section, Qt::Orientation orientation, int role) const | ||||
| { | ||||
|   QVariant result; | ||||
| 
 | ||||
|   if (Qt::DisplayRole == role && Qt::Horizontal == orientation) | ||||
|     { | ||||
|       result = tr ("Mode"); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       result = QAbstractListModel::headerData (section, orientation, role); | ||||
|     } | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| ENUM_QDEBUG_OPS_IMPL (Modes, Mode); | ||||
| #endif | ||||
| 
 | ||||
| ENUM_QDATASTREAM_OPS_IMPL (Modes, Mode); | ||||
| ENUM_CONVERSION_OPS_IMPL (Modes, Mode); | ||||
							
								
								
									
										49
									
								
								Modes.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Modes.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| #ifndef MODES_HPP__ | ||||
| #define MODES_HPP__ | ||||
| 
 | ||||
| #include <QAbstractListModel> | ||||
| 
 | ||||
| #include "qt_helpers.hpp" | ||||
| 
 | ||||
| class Modes final | ||||
|   : public QAbstractListModel | ||||
| { | ||||
|   Q_OBJECT; | ||||
|   Q_ENUMS (Mode); | ||||
| 
 | ||||
| public: | ||||
|   enum Mode | ||||
|   { | ||||
|     NULL_MODE, | ||||
|     JT65, | ||||
|     JT9, | ||||
|     JT9W_1, | ||||
|     JT4, | ||||
|     WSPR, | ||||
|   }; | ||||
| 
 | ||||
|   explicit Modes (QObject * parent = nullptr); | ||||
| 
 | ||||
|   static char const * name (Mode); | ||||
|   static Mode value (QString const&); | ||||
| 
 | ||||
|   // Implement the QAbstractListModel interface
 | ||||
|   int rowCount (QModelIndex const& parent = QModelIndex {}) const override | ||||
|   { | ||||
|     return parent.isValid () ? 0 : 6; // the number of modes in the
 | ||||
|                                       // Mode enumeration class
 | ||||
|   } | ||||
|   QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; | ||||
|   QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; | ||||
| }; | ||||
| 
 | ||||
| Q_DECLARE_METATYPE (Modes::Mode); | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| ENUM_QDEBUG_OPS_DECL (Modes, Mode); | ||||
| #endif | ||||
| 
 | ||||
| ENUM_QDATASTREAM_OPS_DECL (Modes, Mode); | ||||
| ENUM_CONVERSION_OPS_DECL (Modes, Mode); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										14
									
								
								Radio.cpp
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								Radio.cpp
									
									
									
									
									
								
							| @ -2,7 +2,6 @@ | ||||
| 
 | ||||
| #include <cmath> | ||||
| 
 | ||||
| #include <QMetaType> | ||||
| #include <QString> | ||||
| #include <QChar> | ||||
| #include <QDebug> | ||||
| @ -14,19 +13,6 @@ namespace Radio | ||||
| { | ||||
|   namespace | ||||
|   { | ||||
|     struct init | ||||
|     { | ||||
|       init () | ||||
|       { | ||||
|         qRegisterMetaType<Frequency> ("Frequency"); | ||||
| 
 | ||||
|         qRegisterMetaType<Frequencies> ("Frequencies"); | ||||
|         qRegisterMetaTypeStreamOperators<Frequencies> ("Frequencies"); | ||||
| 
 | ||||
|         qRegisterMetaType<FrequencyDelta> ("FrequencyDelta"); | ||||
|       } | ||||
|     } static_initaializer; | ||||
| 
 | ||||
|     double constexpr MHz_factor {1.e6}; | ||||
|     int constexpr frequency_precsion {6}; | ||||
| 
 | ||||
|  | ||||
| @ -3,7 +3,6 @@ | ||||
| 
 | ||||
| #include <QObject> | ||||
| #include <QLocale> | ||||
| #include <QList> | ||||
| 
 | ||||
| class QVariant; | ||||
| class QString; | ||||
| @ -18,7 +17,6 @@ namespace Radio | ||||
|   // Frequency types
 | ||||
|   //
 | ||||
|   using Frequency = quint64; | ||||
|   using Frequencies = QList<Frequency>; | ||||
|   using FrequencyDelta = qint64; | ||||
| 
 | ||||
|   //
 | ||||
| @ -48,7 +46,6 @@ namespace Radio | ||||
| } | ||||
| 
 | ||||
| Q_DECLARE_METATYPE (Radio::Frequency); | ||||
| Q_DECLARE_METATYPE (Radio::Frequencies); | ||||
| Q_DECLARE_METATYPE (Radio::FrequencyDelta); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -19,20 +19,6 @@ | ||||
| 
 | ||||
| #include "Bands.hpp" | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   struct init | ||||
|   { | ||||
|     init () | ||||
|     { | ||||
|       qRegisterMetaType<StationList::Station> ("Station"); | ||||
|       qRegisterMetaTypeStreamOperators<StationList::Station> ("Station"); | ||||
|       qRegisterMetaType<StationList::Stations> ("Stations"); | ||||
|       qRegisterMetaTypeStreamOperators<StationList::Stations> ("Stations"); | ||||
|     } | ||||
|   } static_initializer; | ||||
| } | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| QDebug operator << (QDebug debug, StationList::Station const& station) | ||||
| { | ||||
| @ -70,12 +56,10 @@ public: | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   Stations const& stations () const {return stations_;} | ||||
|   void assign (Stations); | ||||
|   Stations station_list (Stations); | ||||
|   QModelIndex add (Station); | ||||
|   FrequencyDelta offset (Frequency) const; | ||||
| 
 | ||||
| protected: | ||||
|   // Implement the QAbstractTableModel interface.
 | ||||
|   int rowCount (QModelIndex const& parent = QModelIndex {}) const override; | ||||
|   int columnCount (QModelIndex const& parent = QModelIndex {}) const override; | ||||
| @ -90,7 +74,6 @@ protected: | ||||
|   QMimeData * mimeData (QModelIndexList const&) const override; | ||||
|   bool dropMimeData (QMimeData const *, Qt::DropAction, int row, int column, QModelIndex const& parent) override; | ||||
| 
 | ||||
| private: | ||||
|   // Helper method for band validation.
 | ||||
|   QModelIndex first_matching_band (QString const& band_name) const | ||||
|   { | ||||
| @ -127,15 +110,14 @@ StationList::~StationList () | ||||
| { | ||||
| } | ||||
| 
 | ||||
| StationList& StationList::operator = (Stations stations) | ||||
| auto StationList::station_list (Stations stations) -> Stations | ||||
| { | ||||
|   m_->assign (stations); | ||||
|   return *this; | ||||
|   return m_->station_list (stations); | ||||
| } | ||||
| 
 | ||||
| auto StationList::stations () const -> Stations | ||||
| auto StationList::station_list () const -> Stations const& | ||||
| { | ||||
|   return m_->stations (); | ||||
|   return m_->stations_; | ||||
| } | ||||
| 
 | ||||
| QModelIndex StationList::add (Station s) | ||||
| @ -145,13 +127,11 @@ QModelIndex StationList::add (Station s) | ||||
| 
 | ||||
| bool StationList::remove (Station s) | ||||
| { | ||||
|   auto row = m_->stations ().indexOf (s); | ||||
| 
 | ||||
|   auto row = m_->stations_.indexOf (s); | ||||
|   if (0 > row) | ||||
|     { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|   return removeRow (row); | ||||
| } | ||||
| 
 | ||||
| @ -194,11 +174,12 @@ auto StationList::offset (Frequency f) const -> FrequencyDelta | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void StationList::impl::assign (Stations stations) | ||||
| auto StationList::impl::station_list (Stations stations) -> Stations | ||||
| { | ||||
|   beginResetModel (); | ||||
|   std::swap (stations_, stations); | ||||
|   endResetModel (); | ||||
|   return stations; | ||||
| } | ||||
| 
 | ||||
| QModelIndex StationList::impl::add (Station s) | ||||
| @ -221,22 +202,19 @@ QModelIndex StationList::impl::add (Station s) | ||||
| auto StationList::impl::offset (Frequency f) const -> FrequencyDelta | ||||
| { | ||||
|   // Lookup band for frequency
 | ||||
|   auto band_index = bands_->find (f); | ||||
|   if (band_index.isValid ()) | ||||
|   auto const& band = bands_->find (f); | ||||
|   if (band != bands_->out_of_band ()) | ||||
|     { | ||||
|       auto band_name = band_index.data ().toString (); | ||||
| 
 | ||||
|       // Lookup station for band
 | ||||
|       for (int i = 0; i < stations ().size (); ++i) | ||||
|       for (int i = 0; i < stations_.size (); ++i) | ||||
|         { | ||||
|           if (stations_[i].band_name_ == band_name) | ||||
|           if (stations_[i].band_name_ == band->name_) | ||||
|             { | ||||
|               return stations_[i].offset_; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   return 0;			// no offset
 | ||||
|   return 0;                     // no offset
 | ||||
| } | ||||
| 
 | ||||
| int StationList::impl::rowCount (QModelIndex const& parent) const | ||||
| @ -260,7 +238,7 @@ Qt::ItemFlags StationList::impl::flags (QModelIndex const& index) const | ||||
|       && row < stations_.size () | ||||
|       && column < num_columns) | ||||
|     { | ||||
|       if (2 == column) | ||||
|       if (description_column == column) | ||||
|         { | ||||
|           result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; | ||||
|         } | ||||
| @ -289,7 +267,7 @@ QVariant StationList::impl::data (QModelIndex const& index, int role) const | ||||
|     { | ||||
|       switch (column) | ||||
|         { | ||||
|         case 0:			// band name
 | ||||
|         case band_column: | ||||
|           switch (role) | ||||
|             { | ||||
|             case SortRole: | ||||
| @ -318,19 +296,19 @@ QVariant StationList::impl::data (QModelIndex const& index, int role) const | ||||
|             } | ||||
|           break; | ||||
| 
 | ||||
|         case 1:			// frequency offset
 | ||||
|         case offset_column: | ||||
|           { | ||||
|             auto frequency_offset = stations_.at (row).offset_; | ||||
|             switch (role) | ||||
|               { | ||||
|               case SortRole: | ||||
|               case Qt::EditRole: | ||||
|               case Qt::AccessibleTextRole: | ||||
|                 item = frequency_offset; | ||||
|                 break; | ||||
| 
 | ||||
|               case SortRole: | ||||
|               case Qt::DisplayRole: | ||||
|               case Qt::EditRole: | ||||
|                 item = frequency_offset; | ||||
|                 item = Radio::pretty_frequency_MHz_string (frequency_offset) + " MHz"; | ||||
|                 break; | ||||
| 
 | ||||
|               case Qt::ToolTipRole: | ||||
| @ -345,7 +323,7 @@ QVariant StationList::impl::data (QModelIndex const& index, int role) const | ||||
|           } | ||||
|           break; | ||||
| 
 | ||||
|         case 2:			// antenna description
 | ||||
|         case description_column: | ||||
|           switch (role) | ||||
|             { | ||||
|             case SortRole: | ||||
| @ -379,9 +357,9 @@ QVariant StationList::impl::headerData (int section, Qt::Orientation orientation | ||||
|     { | ||||
|       switch (section) | ||||
|         { | ||||
|         case 0: header = tr ("Band"); break; | ||||
|         case 1: header = tr ("Offset"); break; | ||||
|         case 2: header = tr ("Antenna Description"); break; | ||||
|         case band_column: header = tr ("Band"); break; | ||||
|         case offset_column: header = tr ("Offset"); break; | ||||
|         case description_column: header = tr ("Antenna Description"); break; | ||||
|         } | ||||
|     } | ||||
|   else | ||||
| @ -407,7 +385,7 @@ bool StationList::impl::setData (QModelIndex const& model_index, QVariant const& | ||||
| 
 | ||||
|       switch (model_index.column ()) | ||||
|         { | ||||
|         case 0: | ||||
|         case band_column: | ||||
|           { | ||||
|             // Check if band name is valid.
 | ||||
|             auto band_index = first_matching_band (value.toString ()); | ||||
| @ -420,7 +398,7 @@ bool StationList::impl::setData (QModelIndex const& model_index, QVariant const& | ||||
|           } | ||||
|           break; | ||||
| 
 | ||||
|         case 1: | ||||
|         case offset_column: | ||||
|           { | ||||
|             stations_[row].offset_ = value.value<FrequencyDelta> (); | ||||
|             Q_EMIT dataChanged (model_index, model_index, roles); | ||||
| @ -428,7 +406,7 @@ bool StationList::impl::setData (QModelIndex const& model_index, QVariant const& | ||||
|           } | ||||
|           break; | ||||
| 
 | ||||
|         case 2: | ||||
|         case description_column: | ||||
|           stations_[row].antenna_description_ = value.toString (); | ||||
|           Q_EMIT dataChanged (model_index, model_index, roles); | ||||
|           changed = true; | ||||
| @ -508,9 +486,8 @@ bool StationList::impl::dropMimeData (QMimeData const * data, Qt::DropAction act | ||||
|     { | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|   if (parent.isValid () | ||||
|       && 2 == parent.column () | ||||
|       && description_column == parent.column () | ||||
|       && data->hasFormat (mime_type)) | ||||
|     { | ||||
|       QByteArray encoded_data {data->data (mime_type)}; | ||||
| @ -534,17 +511,16 @@ bool StationList::impl::dropMimeData (QMimeData const * data, Qt::DropAction act | ||||
|           QString frequency_string; | ||||
|           stream >> frequency_string; | ||||
|           auto frequency = Radio::frequency (frequency_string, 0); | ||||
|           auto band_index = bands_->find (frequency); | ||||
|           auto const& band = bands_->find (frequency); | ||||
|           if (stations_.cend () == std::find_if (stations_.cbegin () | ||||
|                                                  , stations_.cend () | ||||
|                                                  , [&band_index] (Station const& s) {return s.band_name_ == band_index.data ().toString ();})) | ||||
|                                                  , [&band] (Station const& s) {return s.band_name_ == band->name_;})) | ||||
|             { | ||||
|               add (Station {band_index.data ().toString (), 0, QString {}}); | ||||
|               // not found so add it
 | ||||
|               add (Station {band->name_, 0, QString {}}); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| @ -59,13 +59,15 @@ public: | ||||
| 
 | ||||
|   using Stations = QList<Station>; | ||||
| 
 | ||||
|   enum Column {band_column, offset_column, description_column}; | ||||
| 
 | ||||
|   explicit StationList (Bands const * bands, QObject * parent = nullptr); | ||||
|   explicit StationList (Bands const * bands, Stations, QObject * parent = nullptr); | ||||
|   ~StationList (); | ||||
| 
 | ||||
|   // Load and store contents.
 | ||||
|   StationList& operator = (Stations); | ||||
|   Stations stations () const; | ||||
|   // Load and query contents.
 | ||||
|   Stations station_list (Stations); | ||||
|   Stations const& station_list () const; | ||||
| 
 | ||||
|   //
 | ||||
|   // Model API
 | ||||
| @ -83,10 +85,6 @@ private: | ||||
|   pimpl<impl> m_; | ||||
| }; | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| QDebug operator << (QDebug debug, StationList::Station const&); | ||||
| #endif | ||||
| 
 | ||||
| // Station equivalence
 | ||||
| inline | ||||
| bool operator == (StationList::Station const& lhs, StationList::Station const& rhs) | ||||
| @ -96,6 +94,13 @@ bool operator == (StationList::Station const& lhs, StationList::Station const& r | ||||
|     && lhs.antenna_description_ == rhs.antenna_description_; | ||||
| } | ||||
| 
 | ||||
| QDataStream& operator << (QDataStream&, StationList::Station const&); | ||||
| QDataStream& operator >> (QDataStream&, StationList::Station&); | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| QDebug operator << (QDebug debug, StationList::Station const&); | ||||
| #endif | ||||
| 
 | ||||
| Q_DECLARE_METATYPE (StationList::Station); | ||||
| Q_DECLARE_METATYPE (StationList::Stations); | ||||
| 
 | ||||
|  | ||||
| @ -2,18 +2,6 @@ | ||||
| 
 | ||||
| #include "moc_Transceiver.cpp" | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   struct init | ||||
|   { | ||||
|     init () | ||||
|     { | ||||
|       qRegisterMetaType<Transceiver::TransceiverState> ("Transceiver::TransceiverState"); | ||||
|       qRegisterMetaType<Transceiver::MODE> ("Transceiver::MODE"); | ||||
|     } | ||||
|   } static_initialization; | ||||
| } | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| 
 | ||||
| ENUM_QDEBUG_OPS_IMPL (Transceiver, MODE); | ||||
|  | ||||
| @ -21,25 +21,6 @@ char const * const TransceiverFactory::basic_transceiver_name_ = "None"; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   struct init | ||||
|   { | ||||
|     init () | ||||
|     { | ||||
|       qRegisterMetaType<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits"); | ||||
|       qRegisterMetaTypeStreamOperators<TransceiverFactory::DataBits> ("TransceiverFactory::DataBits"); | ||||
|       qRegisterMetaType<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits"); | ||||
|       qRegisterMetaTypeStreamOperators<TransceiverFactory::StopBits> ("TransceiverFactory::StopBits"); | ||||
|       qRegisterMetaType<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake"); | ||||
|       qRegisterMetaTypeStreamOperators<TransceiverFactory::Handshake> ("TransceiverFactory::Handshake"); | ||||
|       qRegisterMetaType<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod"); | ||||
|       qRegisterMetaTypeStreamOperators<TransceiverFactory::PTTMethod> ("TransceiverFactory::PTTMethod"); | ||||
|       qRegisterMetaType<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource"); | ||||
|       qRegisterMetaTypeStreamOperators<TransceiverFactory::TXAudioSource> ("TransceiverFactory::TXAudioSource"); | ||||
|       qRegisterMetaType<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode"); | ||||
|       qRegisterMetaTypeStreamOperators<TransceiverFactory::SplitMode> ("TransceiverFactory::SplitMode"); | ||||
|     } | ||||
|   } static_initializer; | ||||
| 
 | ||||
|   enum				// supported non-hamlib radio interfaces | ||||
|     { | ||||
|       NonHamlibBaseId = 9899 | ||||
|  | ||||
| @ -33,14 +33,6 @@ namespace | ||||
| { | ||||
|   int constexpr points {256}; | ||||
| 
 | ||||
|   struct init | ||||
|   { | ||||
|     init () | ||||
|     { | ||||
|       qRegisterMetaTypeStreamOperators<WFPalette::Colours> ("Colours"); | ||||
|     } | ||||
|   } static_initaializer; | ||||
| 
 | ||||
|   using Colours = WFPalette::Colours; | ||||
| 
 | ||||
|   // ensure that palette colours are useable for interpolation
 | ||||
|  | ||||
							
								
								
									
										4
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								main.cpp
									
									
									
									
									
								
							| @ -23,7 +23,7 @@ | ||||
| #endif | ||||
| 
 | ||||
| #include "revision_utils.hpp" | ||||
| 
 | ||||
| #include "MetaDataRegistry.hpp" | ||||
| #include "SettingsGroup.hpp" | ||||
| #include "TraceFile.hpp" | ||||
| #include "mainwindow.h" | ||||
| @ -31,6 +31,8 @@ | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|   register_types ();            // make the Qt magic happen
 | ||||
| 
 | ||||
|   // Multiple instances:
 | ||||
|   QSharedMemory mem_jt9; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										196
									
								
								mainwindow.cpp
									
									
									
									
									
								
							
							
						
						
									
										196
									
								
								mainwindow.cpp
									
									
									
									
									
								
							| @ -61,27 +61,6 @@ namespace | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class BandAndFrequencyItemDelegate final | ||||
|   : public QStyledItemDelegate | ||||
| { | ||||
| public: | ||||
|   explicit BandAndFrequencyItemDelegate (Bands const * bands, QObject * parent = nullptr) | ||||
|     : QStyledItemDelegate {parent} | ||||
|     , bands_ {bands} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   QString displayText (QVariant const& v, QLocale const&) const override | ||||
|   { | ||||
|     return Radio::pretty_frequency_MHz_string (Radio::frequency (v, 6)) | ||||
|       + QChar::Nbsp | ||||
|       + '(' + (bands_->data (bands_->find (Radio::frequency (v, 6)))).toString () + ')'; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   Bands const * bands_; | ||||
| }; | ||||
| 
 | ||||
| //--------------------------------------------------- MainWindow constructor
 | ||||
| MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdmem, | ||||
|                        unsigned downSampleFactor, QWidget *parent) : | ||||
| @ -278,15 +257,11 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme | ||||
| 
 | ||||
|   // Hook up working frequencies.
 | ||||
|   ui->bandComboBox->setModel (m_config.frequencies ()); | ||||
|   ui->bandComboBox->setModelColumn (1); // MHz
 | ||||
|   ui->bandComboBox->setModelColumn (FrequencyList::frequency_mhz_column); | ||||
| 
 | ||||
|   // Add delegate to show bands alongside frequencies in combo box
 | ||||
|   // popup list.
 | ||||
|   ui->bandComboBox->view ()->setItemDelegateForColumn (1, new BandAndFrequencyItemDelegate {m_config.bands (), this}); | ||||
| 
 | ||||
|   // combo box drop downs are limited to the drop down selector width,
 | ||||
|   // this almost random increase improves the situation
 | ||||
|   ui->bandComboBox->view ()->setMinimumWidth (ui->bandComboBox->view ()->sizeHintForColumn (1) + 40); | ||||
|   // combo box drop down width defaults to the line edit + decorator width,
 | ||||
|   // here we change that to the column width size hint of the model column
 | ||||
|   ui->bandComboBox->view ()->setMinimumWidth (ui->bandComboBox->view ()->sizeHintForColumn (FrequencyList::frequency_mhz_column)); | ||||
| 
 | ||||
|   // Enable live band combo box entry validation and action.
 | ||||
|   auto band_validator = new LiveFrequencyValidator {ui->bandComboBox | ||||
| @ -646,7 +621,6 @@ void MainWindow::writeSettings() | ||||
|   m_settings->setValue("GUItab",ui->tabWidget->currentIndex()); | ||||
|   m_settings->setValue("OutBufSize",outBufSize); | ||||
|   m_settings->setValue("LockTxFreq",m_lockTxFreq); | ||||
|   m_settings->setValue("Plus2kHz",m_plus2kHz); | ||||
|   m_settings->setValue("PctTx",m_pctx); | ||||
|   m_settings->setValue("dBm",m_dBm); | ||||
|   m_settings->setValue("UploadSpots",m_uploadSpots); | ||||
| @ -736,8 +710,6 @@ void MainWindow::readSettings() | ||||
|   outBufSize=m_settings->value("OutBufSize",4096).toInt(); | ||||
|   m_lockTxFreq=m_settings->value("LockTxFreq",false).toBool(); | ||||
|   ui->cbTxLock->setChecked(m_lockTxFreq); | ||||
|   m_plus2kHz=m_settings->value("Plus2kHz",false).toBool(); | ||||
|   ui->cbPlus2kHz->setChecked(m_plus2kHz); | ||||
|   ui->sunriseBands->setText(m_settings->value("SunriseBands","").toString()); | ||||
|   on_sunriseBands_editingFinished(); | ||||
|   ui->dayBands->setText(m_settings->value("DayBands","").toString()); | ||||
| @ -1176,29 +1148,33 @@ void MainWindow::qsy (Frequency f) | ||||
| void MainWindow::displayDialFrequency () | ||||
| { | ||||
|   // lookup band
 | ||||
|   auto bands_model = m_config.bands (); | ||||
|   QString t {bands_model->data(bands_model->find(m_dialFreq)).toString()}; | ||||
|   ui->bandComboBox->setCurrentText (t); | ||||
|   m_wideGraph->setRxBand(t); | ||||
|   auto const& band_name = m_config.bands ()->find (m_dialFreq)->name_; | ||||
|   ui->bandComboBox->setCurrentText (band_name); | ||||
|   m_wideGraph->setRxBand (band_name); | ||||
| 
 | ||||
|   // search working frequencies for one we are within 10kHz of
 | ||||
|   auto frequencies = m_config.frequencies (); | ||||
|   // search working frequencies for one we are within 10kHz of (1 Mhz
 | ||||
|   // of on VHF and up)
 | ||||
|   bool valid {false}; | ||||
|   quint64 min_offset=99999999; | ||||
| 
 | ||||
|   for (int row = 0; row < frequencies->rowCount (); ++row) { | ||||
|   quint64 min_offset {99999999}; | ||||
|   auto const& frequencies = m_config.frequencies (); | ||||
|   for (int row = 0; row < frequencies->rowCount (); ++row) | ||||
|     { | ||||
|       auto const& source_row = frequencies->mapToSource (frequencies->index (row, 0)).row (); | ||||
|       auto const& item = frequencies->frequency_list ()[source_row]; | ||||
|       // we need to do specific checks for above and below here to
 | ||||
|       // ensure that we can use unsigned Radio::Frequency since we
 | ||||
|       // potentially use the full 64-bit unsigned range.
 | ||||
|       auto working_frequency = frequencies->data (frequencies->index (row, 0)).value<Frequency> (); | ||||
|       auto offset = m_dialFreq > working_frequency ? m_dialFreq - working_frequency : working_frequency - m_dialFreq; | ||||
|       if(offset<min_offset) { | ||||
|          m_freqNominal=working_frequency; | ||||
|          min_offset=offset; | ||||
|       auto const& working_frequency = item.frequency_; | ||||
|       auto const& offset = m_dialFreq > working_frequency ? m_dialFreq - working_frequency : working_frequency - m_dialFreq; | ||||
|       if (offset < min_offset) { | ||||
|          m_freqNominal = working_frequency; | ||||
|          min_offset = offset; | ||||
|       } | ||||
|   } | ||||
|   if ((min_offset < 10000u) or (m_config.enable_VHF_features() and | ||||
|                                 min_offset < 1000000u)) valid = true; | ||||
|   if (min_offset < 10000u or (m_config.enable_VHF_features() and | ||||
|                               min_offset < 1000000u)) { | ||||
|     valid = true; | ||||
|   } | ||||
| 
 | ||||
|   ui->labDialFreq->setProperty ("oob", !valid); | ||||
|   // the following sequence is necessary to update the style
 | ||||
| @ -1672,15 +1648,16 @@ void MainWindow::readFromStdout()                             //readFromStdout | ||||
|         msgBox("Cannot open \"" + f.fileName () + "\" for append:" + f.errorString ()); | ||||
|       } | ||||
| 
 | ||||
|       if (m_config.insert_blank () && m_blankLine) { | ||||
|         QString band; | ||||
|         if (QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged > 50) { | ||||
|           auto const& bands_model = m_config.bands (); | ||||
|           band = ' ' + bands_model->data (bands_model->find (m_dialFreq + ui->TxFreqSpinBox->value ())).toString (); | ||||
|         } | ||||
|         ui->decodedTextBrowser->insertLineSpacer (band.rightJustified  (40, '-')); | ||||
|         m_blankLine = false; | ||||
|       } | ||||
|         if (m_config.insert_blank () && m_blankLine) | ||||
|           { | ||||
|             QString band; | ||||
|             if (QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged > 50) | ||||
|               { | ||||
|                 band = ' ' + QString {m_config.bands ()->find (m_dialFreq)->name_}; | ||||
|               } | ||||
|             ui->decodedTextBrowser->insertLineSpacer (band.rightJustified  (40, '-')); | ||||
|             m_blankLine = false; | ||||
|           } | ||||
| 
 | ||||
|       DecodedText decodedtext; | ||||
|       decodedtext = t.replace("\n",""); //t.replace("\n","").mid(0,t.length()-4);
 | ||||
| @ -2251,9 +2228,8 @@ void MainWindow::startTx2() | ||||
|     transmit (snr); | ||||
|     signalMeter->setValue(0); | ||||
|     if(m_mode.mid(0,4)=="WSPR" and !m_tune) { | ||||
|       auto const& bands_model = m_config.bands (); | ||||
|       t = " Transmiting " + m_mode + " ----------------------- " + | ||||
|           bands_model->data(bands_model->find(m_dialFreq)).toString (); | ||||
|         m_config.bands ()->find (m_dialFreq)->name_; | ||||
|       ui->decodedTextBrowser->append(t.rightJustified (71, '-')); | ||||
| 
 | ||||
|       QFile f {m_dataDir.absoluteFilePath ("ALL_WSPR.TXT")}; | ||||
| @ -2986,10 +2962,8 @@ void MainWindow::acceptQSO2(QDateTime const& QSO_date, QString const& call, QStr | ||||
|                             , QString const& tx_power, QString const& comments | ||||
|                             , QString const& name) | ||||
| { | ||||
|   auto const& bands_model = m_config.bands (); | ||||
|   auto band = bands_model->data (bands_model->find (m_dialFreq + ui->TxFreqSpinBox->value ())).toString (); | ||||
|   QString date = m_dateTimeQSO.toString("yyyyMMdd"); | ||||
|   m_logBook.addAsWorked(m_hisCall,band,m_modeTx,date); | ||||
|   m_logBook.addAsWorked (m_hisCall, m_config.bands ()->find (m_dialFreq)->name_, m_modeTx, date); | ||||
| 
 | ||||
|   m_messageClient->qso_logged (QSO_date, call, grid, dial_freq, mode, rpt_sent, rpt_received, tx_power, comments, name); | ||||
| 
 | ||||
| @ -3009,6 +2983,7 @@ void MainWindow::acceptQSO2(QDateTime const& QSO_date, QString const& call, QStr | ||||
| void MainWindow::on_actionJT9_1_triggered() | ||||
| { | ||||
|   m_mode="JT9"; | ||||
|   switch_mode (Modes::JT9); | ||||
|   if(m_modeTx!="JT9") on_pbTxMode_clicked(); | ||||
|   statusChanged(); | ||||
|   m_TRperiod=60; | ||||
| @ -3036,6 +3011,7 @@ void MainWindow::on_actionJT9_1_triggered() | ||||
| void MainWindow::on_actionJT9W_1_triggered() | ||||
| { | ||||
|   m_mode="JT9W-1"; | ||||
|   switch_mode (Modes::JT9W_1); | ||||
|   if(m_modeTx!="JT9") on_pbTxMode_clicked(); | ||||
|   statusChanged(); | ||||
|   m_TRperiod=60; | ||||
| @ -3068,6 +3044,7 @@ void MainWindow::on_actionJT65_triggered() | ||||
|     on_pbTxMode_clicked(); | ||||
|   } | ||||
|   m_mode="JT65"; | ||||
|   switch_mode (Modes::JT65); | ||||
|   if(m_modeTx!="JT65") on_pbTxMode_clicked(); | ||||
|   statusChanged(); | ||||
|   m_TRperiod=60; | ||||
| @ -3105,6 +3082,7 @@ void MainWindow::on_actionJT65_triggered() | ||||
| void MainWindow::on_actionJT9_JT65_triggered() | ||||
| { | ||||
|   m_mode="JT9+JT65"; | ||||
|   switch_mode (Modes::JT65); | ||||
|   if(m_modeTx != "JT65") m_modeTx="JT9"; | ||||
|   m_nSubMode=0;                    //Dual-mode always means JT9 and JT65A
 | ||||
|   statusChanged(); | ||||
| @ -3133,6 +3111,7 @@ void MainWindow::on_actionJT9_JT65_triggered() | ||||
| void MainWindow::on_actionJT4_triggered() | ||||
| { | ||||
|   m_mode="JT4"; | ||||
|   switch_mode (Modes::JT4); | ||||
|   m_modeTx="JT4"; | ||||
|   statusChanged(); | ||||
|   m_TRperiod=60; | ||||
| @ -3171,6 +3150,7 @@ void MainWindow::on_actionJT4_triggered() | ||||
| void MainWindow::on_actionWSPR_2_triggered() | ||||
| { | ||||
|   m_mode="WSPR-2"; | ||||
|   switch_mode (Modes::WSPR); | ||||
|   m_modeTx="WSPR-2";                                    //### not needed ?? ###
 | ||||
|   statusChanged(); | ||||
|   m_TRperiod=120; | ||||
| @ -3194,8 +3174,20 @@ void MainWindow::on_actionWSPR_2_triggered() | ||||
| void MainWindow::on_actionWSPR_15_triggered() | ||||
| { | ||||
|   msgBox("WSPR-15 is not yet available"); | ||||
|   switch_mode (Modes::WSPR); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::switch_mode (Mode mode) | ||||
| { | ||||
|   auto f = m_dialFreq; | ||||
|   m_config.frequencies ()->filter (mode); | ||||
|   auto const& index = m_config.frequencies ()->best_working_frequency (f, mode); | ||||
|   if (index.isValid ()) | ||||
|     { | ||||
|       ui->bandComboBox->setCurrentIndex (index.row ()); | ||||
|       on_bandComboBox_activated (index.row ()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MainWindow::WSPR_config(bool b) | ||||
| { | ||||
| @ -3328,26 +3320,44 @@ bool MainWindow::gridOK(QString g) | ||||
|   return b; | ||||
| } | ||||
| 
 | ||||
| void MainWindow::on_bandComboBox_currentIndexChanged (int index) | ||||
| { | ||||
|   auto const& frequencies = m_config.frequencies (); | ||||
|   auto const& source_index = frequencies->mapToSource (frequencies->index (index, FrequencyList::frequency_column)); | ||||
|   Frequency frequency {m_dialFreq}; | ||||
|   if (source_index.isValid ()) | ||||
|     { | ||||
|       frequency = frequencies->frequency_list ()[source_index.row ()].frequency_; | ||||
|     } | ||||
| 
 | ||||
|   // Lookup band
 | ||||
|   auto const& band  = m_config.bands ()->find (frequency); | ||||
|   auto const& out_of_band  = m_config.bands ()->out_of_band (); | ||||
|   if (out_of_band != band) | ||||
|     { | ||||
|       ui->bandComboBox->lineEdit ()->setStyleSheet ({}); | ||||
|       ui->bandComboBox->setCurrentText (band->name_); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       ui->bandComboBox->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}"); | ||||
|       ui->bandComboBox->setCurrentText (out_of_band->name_); | ||||
|     } | ||||
|   displayDialFrequency (); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::on_bandComboBox_activated (int index) | ||||
| { | ||||
|   auto frequencies = m_config.frequencies (); | ||||
|   auto frequency = frequencies->data (frequencies->index (index, 0)); | ||||
|   // Lookup band
 | ||||
|   auto bands = m_config.bands (); | ||||
|   auto band_index = bands->find (frequency); | ||||
|   if (band_index.isValid ()) { | ||||
|     ui->bandComboBox->lineEdit ()->setStyleSheet ({}); | ||||
|     ui->bandComboBox->setCurrentText (band_index.data ().toString ()); | ||||
|   } else { | ||||
|     ui->bandComboBox->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}"); | ||||
|     ui->bandComboBox->setCurrentText (bands->data (QModelIndex {}).toString ()); | ||||
|   } | ||||
|   auto f = frequency.value<Frequency> (); | ||||
|   if (m_plus2kHz) f += 2000; | ||||
|   auto const& frequencies = m_config.frequencies (); | ||||
|   auto const& source_index = frequencies->mapToSource (frequencies->index (index, FrequencyList::frequency_column)); | ||||
|   Frequency frequency {m_dialFreq}; | ||||
|   if (source_index.isValid ()) | ||||
|     { | ||||
|       frequency = frequencies->frequency_list ()[source_index.row ()].frequency_; | ||||
|     } | ||||
|   m_bandEdited = true; | ||||
|   band_changed (f); | ||||
|   m_wideGraph->setRxBand(band_index.data().toString()); | ||||
| //  qDebug() << "bandComboBox_activated" << index << 0.000001*f;
 | ||||
|   band_changed (frequency); | ||||
|   m_wideGraph->setRxBand (m_config.bands ()->find (frequency)->name_); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::band_changed (Frequency f) | ||||
| @ -3607,23 +3617,6 @@ void MainWindow::on_cbTxLock_clicked(bool checked) | ||||
|   if(m_lockTxFreq) on_pbR2T_clicked(); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::on_cbPlus2kHz_toggled(bool checked) | ||||
| { | ||||
|   m_plus2kHz = checked; | ||||
| 
 | ||||
|   if (m_config.transceiver_online (false)) { // update state only if not starting up
 | ||||
|       psk_Reporter->sendReport();    // Upload any queued spots before changing band
 | ||||
|       auto f = m_dialFreq; | ||||
|       if (m_plus2kHz) { | ||||
|         f += 2000; | ||||
|       } else { | ||||
|         f -= 2000; | ||||
|       } | ||||
|       m_bandEdited = true; | ||||
|       band_changed (f); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void MainWindow::handle_transceiver_update (Transceiver::TransceiverState s) | ||||
| { | ||||
|   transmitDisplay (s.ptt ()); | ||||
| @ -3868,9 +3861,6 @@ void MainWindow::transmitDisplay (bool transmitting) | ||||
|       ui->cbTxLock->setEnabled (QSY_allowed); | ||||
|     } | ||||
| 
 | ||||
|       // Allow +2kHz only when not transmitting or if TX QSYs are allowed
 | ||||
|     ui->cbPlus2kHz->setEnabled (!transmitting || m_config.tx_QSY_allowed ()); | ||||
| 
 | ||||
|       // the following are always disallowed in transmit
 | ||||
|     ui->menuMode->setEnabled (!transmitting); | ||||
|     ui->bandComboBox->setEnabled (!transmitting); | ||||
| @ -4173,9 +4163,8 @@ void MainWindow::p1ReadFromStdout()                        //p1readFromStdout | ||||
| 
 | ||||
|       if (m_config.insert_blank () && m_blankLine) { | ||||
|         QString band; | ||||
|         auto const& bands_model = m_config.bands (); | ||||
|         Frequency f=1000000.0*rxFields.at(3).toDouble()+0.5; | ||||
|         band = ' ' + bands_model->data (bands_model->find (f)).toString (); | ||||
|         band = ' ' + m_config.bands ()->find (f)->name_; | ||||
|         ui->decodedTextBrowser->append(band.rightJustified (71, '-')); | ||||
|         m_blankLine = false; | ||||
|       } | ||||
| @ -4355,10 +4344,9 @@ void MainWindow::bandHopping() | ||||
| 
 | ||||
|   m_band00=iband; | ||||
|   auto frequencies = m_config.frequencies (); | ||||
|   for (int i=0; i<99; i++) { | ||||
|     auto frequency=frequencies->data (frequencies->index (i, 0)); | ||||
|   for (int row = 0; row < frequencies->rowCount (); ++row) { | ||||
|     auto frequency=frequencies->data (frequencies->index (row, FrequencyList::frequency_column)); | ||||
|     auto f = frequency.value<Frequency>(); | ||||
|     if(f==0) break; | ||||
|     if(f==f0) { | ||||
|       on_bandComboBox_activated(i);                        //Set new band
 | ||||
| //      qDebug() << nhr << nmin << int(sec) << "Band selected" << i << 0.000001*f0 << 0.000001*f;
 | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| #include "soundout.h" | ||||
| #include "commons.h" | ||||
| #include "Radio.hpp" | ||||
| #include "Modes.hpp" | ||||
| #include "Configuration.hpp" | ||||
| #include "Transceiver.hpp" | ||||
| #include "psk_reporter.h" | ||||
| @ -65,6 +66,7 @@ class MainWindow : public QMainWindow | ||||
| 
 | ||||
| public: | ||||
|   using Frequency = Radio::Frequency; | ||||
|   using Mode = Modes::Mode; | ||||
| 
 | ||||
|   // Multiple instances: call MainWindow() with *thekey
 | ||||
|   explicit MainWindow(bool multiple, QSettings *, QSharedMemory *shdmem, | ||||
| @ -176,12 +178,12 @@ private slots: | ||||
|                   , QString const& rpt_sent, QString const& rpt_received | ||||
|                   , QString const& tx_power, QString const& comments | ||||
|                   , QString const& name); | ||||
|   void on_bandComboBox_currentIndexChanged (int index); | ||||
|   void on_bandComboBox_activated (int index); | ||||
|   void on_readFreq_clicked(); | ||||
|   void on_pbTxMode_clicked(); | ||||
|   void on_RxFreqSpinBox_valueChanged(int n); | ||||
|   void on_cbTxLock_clicked(bool checked); | ||||
|   void on_cbPlus2kHz_toggled(bool checked); | ||||
|   void on_outAttenuation_valueChanged (int); | ||||
|   void rigOpen (); | ||||
|   void handle_transceiver_update (Transceiver::TransceiverState); | ||||
| @ -233,8 +235,6 @@ private slots: | ||||
|   void on_graylineDuration_editingFinished(); | ||||
| 
 | ||||
| private: | ||||
|   void enable_DXCC_entity (bool on); | ||||
| 
 | ||||
|   Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo, | ||||
|       unsigned channels, unsigned msBuffered) const; | ||||
|   Q_SIGNAL void stopAudioOutputStream () const; | ||||
| @ -370,7 +370,6 @@ private: | ||||
|   bool    m_lockTxFreq; | ||||
|   bool    m_tx2QSO; | ||||
|   bool    m_CATerror; | ||||
|   bool    m_plus2kHz; | ||||
|   bool    m_bAstroData; | ||||
|   bool    m_bEME; | ||||
|   bool    m_bShMsgs; | ||||
| @ -507,6 +506,8 @@ private: | ||||
|   void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text); | ||||
|   void replayDecodes (); | ||||
|   void postDecode (bool is_new, QString const& message); | ||||
|   void enable_DXCC_entity (bool on); | ||||
|   void switch_mode (Mode); | ||||
|   void bandHopping(); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -1348,16 +1348,6 @@ | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="1" column="0"> | ||||
|          <widget class="QCheckBox" name="cbPlus2kHz"> | ||||
|           <property name="toolTip"> | ||||
|            <string>Add 2 kHz to requested dial frequency</string> | ||||
|           </property> | ||||
|           <property name="text"> | ||||
|            <string>+2 kHz</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="1" column="2"> | ||||
|          <widget class="QPushButton" name="readFreq"> | ||||
|           <property name="maximumSize"> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user