| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | #include "WorkedBefore.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | #include <functional>
 | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  | #include <stdexcept>
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | #include <boost/functional/hash.hpp>
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | #include <boost/multi_index_container.hpp>
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | #include <boost/multi_index/hashed_index.hpp>
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | #include <boost/multi_index/ordered_index.hpp>
 | 
					
						
							|  |  |  | #include <boost/multi_index/key_extractors.hpp>
 | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  | #include <boost/range/iterator_range.hpp>
 | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  | #include <QtConcurrent/QtConcurrentRun>
 | 
					
						
							|  |  |  | #include <QFuture>
 | 
					
						
							|  |  |  | #include <QFutureWatcher>
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | #include <QChar>
 | 
					
						
							|  |  |  | #include <QString>
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | #include <QByteArray>
 | 
					
						
							|  |  |  | #include <QStandardPaths>
 | 
					
						
							|  |  |  | #include <QDir>
 | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  | #include <QFileInfo>
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | #include <QFile>
 | 
					
						
							|  |  |  | #include <QTextStream>
 | 
					
						
							| 
									
										
										
										
											2019-05-29 23:35:18 +01:00
										 |  |  | #include "Configuration.hpp"
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | #include "qt_helpers.hpp"
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | #include "pimpl_impl.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  | #include "moc_WorkedBefore.cpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  | using namespace boost::multi_index; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | // hash function for QString members in hashed indexes
 | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | std::size_t hash_value (QString const& s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return std::hash<QString> {} (s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | // worked before set element
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | struct worked_entry | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |   explicit worked_entry (QString const& call, QString const& grid, QString const& band | 
					
						
							|  |  |  |                          , QString const& mode, QString const& country, AD1CCty::Continent continent | 
					
						
							|  |  |  |                          , int CQ_zone, int ITU_zone) | 
					
						
							|  |  |  |     : call_ {call} | 
					
						
							|  |  |  |     , grid_ {grid} | 
					
						
							|  |  |  |     , band_ {band} | 
					
						
							|  |  |  |     , mode_ {mode} | 
					
						
							|  |  |  |     , country_ {country} | 
					
						
							|  |  |  |     , continent_ {continent} | 
					
						
							|  |  |  |     , CQ_zone_ {CQ_zone} | 
					
						
							|  |  |  |     , ITU_zone_ {ITU_zone} | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |   QString call_; | 
					
						
							|  |  |  |   QString grid_; | 
					
						
							|  |  |  |   QString band_; | 
					
						
							|  |  |  |   QString mode_; | 
					
						
							|  |  |  |   QString country_; | 
					
						
							|  |  |  |   AD1CCty::Continent continent_; | 
					
						
							|  |  |  |   int CQ_zone_; | 
					
						
							|  |  |  |   int ITU_zone_; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | bool operator == (worked_entry const& lhs, worked_entry const& rhs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return | 
					
						
							|  |  |  |     lhs.continent_ == rhs.continent_  // check 1st as it is fast
 | 
					
						
							|  |  |  |     && lhs.CQ_zone_ == rhs.CQ_zone_   // ditto
 | 
					
						
							|  |  |  |     && lhs.ITU_zone_ == rhs.ITU_zone_ // ditto
 | 
					
						
							|  |  |  |     && lhs.call_ == rhs.call_         // check the rest in decreasing
 | 
					
						
							|  |  |  |     && lhs.grid_ == rhs.grid_         // domain size order to shortcut
 | 
					
						
							|  |  |  |     && lhs.country_ == rhs.country_   // differences as quickly as possible
 | 
					
						
							|  |  |  |     && lhs.band_ == rhs.band_ | 
					
						
							|  |  |  |     && lhs.mode_ == rhs.mode_; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::size_t hash_value (worked_entry const& we) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   std::size_t seed {0}; | 
					
						
							|  |  |  |   boost::hash_combine (seed, we.call_); | 
					
						
							|  |  |  |   boost::hash_combine (seed, we.grid_); | 
					
						
							|  |  |  |   boost::hash_combine (seed, we.band_); | 
					
						
							|  |  |  |   boost::hash_combine (seed, we.mode_); | 
					
						
							|  |  |  |   boost::hash_combine (seed, we.country_); | 
					
						
							|  |  |  |   boost::hash_combine (seed, we.continent_); | 
					
						
							|  |  |  |   boost::hash_combine (seed, we.CQ_zone_); | 
					
						
							|  |  |  |   boost::hash_combine (seed, we.ITU_zone_); | 
					
						
							|  |  |  |   return seed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined (QT_NO_DEBUG_STREAM)
 | 
					
						
							|  |  |  | QDebug operator << (QDebug dbg, worked_entry const& e) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   QDebugStateSaver saver {dbg}; | 
					
						
							|  |  |  |   dbg.nospace () << "worked_entry(" | 
					
						
							|  |  |  |                  << e.call_ << ", " | 
					
						
							|  |  |  |                  << e.grid_ << ", " | 
					
						
							|  |  |  |                  << e.band_ << ", " | 
					
						
							|  |  |  |                  << e.mode_ << ", " | 
					
						
							|  |  |  |                  << e.country_ << ", " | 
					
						
							|  |  |  |                  << e.continent_ << ", " | 
					
						
							|  |  |  |                  << e.CQ_zone_ << ", " | 
					
						
							|  |  |  |                  << e.ITU_zone_ << ')'; | 
					
						
							|  |  |  |   return dbg; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // less then predidate for the Continent enum class, needed for
 | 
					
						
							|  |  |  | // ordered indexes
 | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  | struct Continent_less | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-26 16:51:54 +01:00
										 |  |  |   bool operator () (AD1CCty::Continent lhs, AD1CCty::Continent rhs) const | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |   { | 
					
						
							|  |  |  |     return static_cast<int> (lhs) < static_cast<int> (rhs); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | // index tags
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | struct call_mode_band {}; | 
					
						
							|  |  |  | struct call_band {}; | 
					
						
							|  |  |  | struct grid_mode_band {}; | 
					
						
							|  |  |  | struct grid_band {}; | 
					
						
							|  |  |  | struct entity_mode_band {}; | 
					
						
							|  |  |  | struct entity_band {}; | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  | struct continent_mode_band {}; | 
					
						
							|  |  |  | struct continent_band {}; | 
					
						
							|  |  |  | struct CQ_zone_mode_band {}; | 
					
						
							|  |  |  | struct CQ_zone_band {}; | 
					
						
							|  |  |  | struct ITU_zone_mode_band {}; | 
					
						
							|  |  |  | struct ITU_zone_band {}; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  | // set with multiple ordered unique indexes that allow for optimally
 | 
					
						
							|  |  |  | // efficient determination of various categories of worked before
 | 
					
						
							|  |  |  | // status
 | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  | typedef multi_index_container< | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |   worked_entry, | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |   indexed_by< | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     // basic unordered set constraint - we don't need duplicate worked entries
 | 
					
						
							|  |  |  |     hashed_unique<identity<worked_entry>>, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // The following indexes are used to discover worked before stuff.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // They are ordered so as to support partial lookups and
 | 
					
						
							|  |  |  |     // non-unique because container inserts must be valid for all
 | 
					
						
							|  |  |  |     // indexes.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |     // call+mode+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<call_mode_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::call_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::mode_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |     // call+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<call_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::call_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |     // grid+mode+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<grid_mode_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::grid_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::mode_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |     // grid+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<grid_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::grid_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |     // country+mode+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<entity_mode_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::country_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::mode_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |     // country+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<entity_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::country_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |     // continent+mode+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<continent_mode_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, AD1CCty::Continent, &worked_entry::continent_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::mode_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> >, | 
					
						
							|  |  |  |                        composite_key_compare<Continent_less, std::less<QString>, std::less<QString> > >, | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |     // continent+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<continent_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, AD1CCty::Continent, &worked_entry::continent_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> >, | 
					
						
							|  |  |  |                        composite_key_compare<Continent_less, std::less<QString> > >, | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |     // CQ-zone+mode+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<CQ_zone_mode_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, int, &worked_entry::CQ_zone_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::mode_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |     // CQ-zone+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<CQ_zone_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, int, &worked_entry::CQ_zone_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |     // ITU-zone+mode+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<ITU_zone_mode_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, int, &worked_entry::ITU_zone_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::mode_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > >, | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |     // ITU-zone+band
 | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |     ordered_non_unique<tag<ITU_zone_band>, | 
					
						
							|  |  |  |                        composite_key<worked_entry, | 
					
						
							|  |  |  |                                      member<worked_entry, int, &worked_entry::ITU_zone_>, | 
					
						
							|  |  |  |                                      member<worked_entry, QString, &worked_entry::band_> > > > | 
					
						
							|  |  |  |   > worked_before_database_type; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto const logFileName = "wsjtx_log.adi"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |   // Expception class suitable for using with QtConcurrent across
 | 
					
						
							|  |  |  |   // thread boundaries
 | 
					
						
							|  |  |  |   class LoaderException final | 
					
						
							|  |  |  |     : public QException | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     LoaderException (std::exception const& e) : error_ {e.what ()} {} | 
					
						
							|  |  |  |     QString error () const {return error_;} | 
					
						
							|  |  |  |     void raise () const override {throw *this;} | 
					
						
							|  |  |  |     LoaderException * clone () const override {return new LoaderException {*this};} | 
					
						
							|  |  |  |   private: | 
					
						
							|  |  |  |     QString error_; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |   QString extractField (QString const& record, QString const& fieldName) | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |   { | 
					
						
							|  |  |  |     int fieldNameIndex = record.indexOf ('<' + fieldName + ':', 0, Qt::CaseInsensitive); | 
					
						
							|  |  |  |     if (fieldNameIndex >=0) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         int closingBracketIndex = record.indexOf('>',fieldNameIndex); | 
					
						
							|  |  |  |         int fieldLengthIndex = record.indexOf(':',fieldNameIndex);  // find the size delimiter
 | 
					
						
							|  |  |  |         int dataTypeIndex = -1; | 
					
						
							|  |  |  |         if (fieldLengthIndex >= 0) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             dataTypeIndex = record.indexOf(':',fieldLengthIndex+1);  // check for a second : indicating there is a data type
 | 
					
						
							|  |  |  |             if (dataTypeIndex > closingBracketIndex) | 
					
						
							|  |  |  |               dataTypeIndex = -1; // second : was found but it was beyond the closing >
 | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |         else | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             throw LoaderException (std::runtime_error {"Invalid ADIF field " + fieldName.toStdString () + ": " + record.toStdString ()}); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |         if (closingBracketIndex > fieldNameIndex && fieldLengthIndex > fieldNameIndex && fieldLengthIndex < closingBracketIndex) | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |           { | 
					
						
							|  |  |  |             int fieldLengthCharCount = closingBracketIndex - fieldLengthIndex -1; | 
					
						
							|  |  |  |             if (dataTypeIndex >= 0) | 
					
						
							|  |  |  |               fieldLengthCharCount -= 2; // data type indicator is always a colon followed by a single character
 | 
					
						
							|  |  |  |             QString fieldLengthString = record.mid(fieldLengthIndex+1,fieldLengthCharCount); | 
					
						
							|  |  |  |             int fieldLength = fieldLengthString.toInt(); | 
					
						
							|  |  |  |             if (fieldLength > 0) | 
					
						
							|  |  |  |               { | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |                 return record.mid(closingBracketIndex+1,fieldLength); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |               } | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |         else | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             throw LoaderException (std::runtime_error {"Malformed ADIF field " + fieldName.toStdString () + ": " + record.toStdString ()}); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |     return QString {}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   worked_before_database_type loader (QString const& path, AD1CCty const * prefixes) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     worked_before_database_type worked; | 
					
						
							|  |  |  |     QFile inputFile {path}; | 
					
						
							|  |  |  |     if (inputFile.exists ()) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         if (inputFile.open (QFile::ReadOnly)) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             QTextStream in {&inputFile}; | 
					
						
							|  |  |  |             QString buffer; | 
					
						
							|  |  |  |             bool pre_read {false}; | 
					
						
							|  |  |  |             int end_position {-1}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // skip optional header record
 | 
					
						
							|  |  |  |             do | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 buffer += in.readLine () + '\n'; | 
					
						
							|  |  |  |                 if (buffer.startsWith (QChar {'<'})) // denotes no header
 | 
					
						
							|  |  |  |                   { | 
					
						
							|  |  |  |                     pre_read = true; | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                   { | 
					
						
							|  |  |  |                     end_position = buffer.indexOf ("<EOH>", 0, Qt::CaseInsensitive); | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             while (!in.atEnd () && !pre_read && end_position < 0); | 
					
						
							|  |  |  |             if (!pre_read)            // found header
 | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 if (end_position < 0) | 
					
						
							|  |  |  |                   { | 
					
						
							|  |  |  |                     throw LoaderException (std::runtime_error {"Invalid ADIF header"}); | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 buffer.remove (0, end_position + 5); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             while (!in.atEnd ()) | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 end_position = buffer.indexOf ("<EOR>", 0, Qt::CaseInsensitive); | 
					
						
							|  |  |  |                 do | 
					
						
							|  |  |  |                   { | 
					
						
							|  |  |  |                     if (!in.atEnd () && end_position < 0) | 
					
						
							|  |  |  |                       { | 
					
						
							|  |  |  |                         buffer += in.readLine () + '\n'; | 
					
						
							|  |  |  |                       } | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 while ((end_position = buffer.indexOf ("<EOR>", 0, Qt::CaseInsensitive)) < 0 && !in.atEnd ()); | 
					
						
							| 
									
										
										
										
											2018-12-10 17:06:02 +00:00
										 |  |  |                 if (end_position >= 0) // require valid ADIF record
 | 
					
						
							|  |  |  |                                        // with terminator
 | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |                   { | 
					
						
							| 
									
										
										
										
											2018-12-10 17:06:02 +00:00
										 |  |  |                     auto record = buffer.left (end_position + 5).trimmed (); | 
					
						
							|  |  |  |                     auto next_record = buffer.indexOf (QChar {'<'}, end_position + 5); | 
					
						
							|  |  |  |                     buffer.remove (0, next_record >=0 ? next_record : buffer.size ()); | 
					
						
							|  |  |  |                     record = record.mid (record.indexOf (QChar {'<'})); | 
					
						
							|  |  |  |                     auto call = extractField (record, "CALL"); | 
					
						
							|  |  |  |                     if (call.size ()) // require CALL field before we
 | 
					
						
							|  |  |  |                                       // will parse a record
 | 
					
						
							|  |  |  |                       { | 
					
						
							|  |  |  |                         auto const& entity = prefixes->lookup (call); | 
					
						
							| 
									
										
										
										
											2019-05-22 02:23:04 +01:00
										 |  |  |                         auto mode = extractField (record, "MODE").toUpper (); | 
					
						
							|  |  |  |                         if (!mode.size () || "MFSK" == mode) | 
					
						
							|  |  |  |                           { | 
					
						
							|  |  |  |                             mode = extractField (record, "SUBMODE").toUpper (); | 
					
						
							|  |  |  |                           } | 
					
						
							| 
									
										
										
										
											2018-12-10 17:06:02 +00:00
										 |  |  |                         worked.emplace (call.toUpper () | 
					
						
							|  |  |  |                                         , extractField (record, "GRIDSQUARE").left (4).toUpper () // not interested in 6-digit grids
 | 
					
						
							|  |  |  |                                         , extractField (record, "BAND").toUpper () | 
					
						
							| 
									
										
										
										
											2019-05-22 02:23:04 +01:00
										 |  |  |                                         , mode | 
					
						
							| 
									
										
										
										
											2018-12-10 17:06:02 +00:00
										 |  |  |                                         , entity.entity_name | 
					
						
							|  |  |  |                                         , entity.continent | 
					
						
							|  |  |  |                                         , entity.CQ_zone | 
					
						
							|  |  |  |                                         , entity.ITU_zone); | 
					
						
							|  |  |  |                       } | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |                   } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             throw LoaderException (std::runtime_error {"Error opening ADIF log file for read: " + inputFile.errorString ().toStdString ()}); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     return worked; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class WorkedBefore::impl final | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2019-05-29 23:35:18 +01:00
										 |  |  |   impl (Configuration const * configuration) | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |     : configuration_ {configuration} | 
					
						
							|  |  |  |     , path_ {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (logFileName)} | 
					
						
							| 
									
										
										
										
											2019-05-29 23:35:18 +01:00
										 |  |  |     , prefixes_ {configuration} | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |   void reload () | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     async_loader_ = QtConcurrent::run (loader, path_, &prefixes_); | 
					
						
							|  |  |  |     loader_watcher_.setFuture (async_loader_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |   Configuration const * configuration_; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |   QString path_; | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |   AD1CCty prefixes_; | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |   QFutureWatcher<worked_before_database_type> loader_watcher_; | 
					
						
							|  |  |  |   QFuture<worked_before_database_type> async_loader_; | 
					
						
							| 
									
										
										
										
											2018-11-14 10:44:36 -05:00
										 |  |  |   worked_before_database_type worked_; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-29 23:35:18 +01:00
										 |  |  | WorkedBefore::WorkedBefore (Configuration const * configuration) | 
					
						
							|  |  |  |   : m_ {configuration} | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-29 23:35:18 +01:00
										 |  |  |   Q_ASSERT (configuration); | 
					
						
							| 
									
										
										
										
											2018-11-30 21:50:44 +00:00
										 |  |  |   connect (&m_->loader_watcher_, &QFutureWatcher<worked_before_database_type>::finished, [this] () { | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |       QString error; | 
					
						
							|  |  |  |       size_t n {0}; | 
					
						
							|  |  |  |       try | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |           m_->worked_ = m_->loader_watcher_.result (); | 
					
						
							|  |  |  |           n = m_->worked_.size (); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |       catch (LoaderException const& e) | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |           error = e.error (); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-11-30 16:26:46 +00:00
										 |  |  |       Q_EMIT finished_loading (n, error); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   reload (); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void WorkedBefore::reload () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   m_->reload (); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WorkedBefore::~WorkedBefore () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString const& WorkedBefore::path () const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return m_->path_; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 22:20:09 +01:00
										 |  |  | AD1CCty const * WorkedBefore::countries () const | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-30 22:20:09 +01:00
										 |  |  |   return &m_->prefixes_; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool WorkedBefore::add (QString const& call | 
					
						
							|  |  |  |                         , QString const& grid | 
					
						
							|  |  |  |                         , QString const& band | 
					
						
							|  |  |  |                         , QString const& mode | 
					
						
							|  |  |  |                         , QByteArray const& ADIF_record) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (call.size ()) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |       auto const& entity = m_->prefixes_.lookup (call); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |       QFile file {m_->path_}; | 
					
						
							|  |  |  |       if (!file.open(QIODevice::Text | QIODevice::Append)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           QTextStream out {&file}; | 
					
						
							|  |  |  |           if (!file.size ()) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2020-06-24 20:23:14 +01:00
										 |  |  |               out << "WSJT-X ADIF Export<eoh>" << // new file
 | 
					
						
							| 
									
										
										
										
											2020-06-13 16:04:41 +01:00
										 |  |  | #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
 | 
					
						
							|  |  |  |                  endl | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |                  Qt::endl | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |                  ; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-13 16:04:41 +01:00
										 |  |  |           out << ADIF_record << " <eor>" << | 
					
						
							|  |  |  | #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
 | 
					
						
							|  |  |  |                  endl | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |                  Qt::endl | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |                  ; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |       m_->worked_.emplace (call.toUpper (), grid.left (4).toUpper (), band.toUpper (), mode.toUpper () | 
					
						
							|  |  |  |                            , entity.entity_name, entity.continent, entity.CQ_zone, entity.ITU_zone); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool WorkedBefore::country_worked (QString const& country, QString const& mode, QString const& band) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (mode.size ()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |             country.size () | 
					
						
							|  |  |  |             && m_->worked_.get<entity_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<entity_mode_band> ().find (std::make_tuple (country, mode.toUpper (), band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |             country.size () | 
					
						
							|  |  |  |             && m_->worked_.get<entity_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<entity_mode_band> ().find (std::make_tuple (country, mode.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |             country.size () | 
					
						
							|  |  |  |             && m_->worked_.get<entity_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<entity_band> ().find (std::make_tuple (country, band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |             country.size () | 
					
						
							|  |  |  |             && m_->worked_.get<entity_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |             != m_->worked_.get<entity_band> ().find (country); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool WorkedBefore::grid_worked (QString const& grid, QString const& mode, QString const& band) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |   auto gridsquare = grid.left (4).toUpper (); | 
					
						
							|  |  |  |   if (m_->configuration_->highlight_only_fields ()) | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |       // can't use a direct set find operation or a set operation with
 | 
					
						
							|  |  |  |       // a (CompatibleKey, CompatibleCompare) concept so we must
 | 
					
						
							|  |  |  |       // partially scan the index
 | 
					
						
							|  |  |  |       auto range = boost::make_iterator_range ( | 
					
						
							|  |  |  |                                                m_->worked_.get<grid_mode_band> ().lower_bound (gridsquare.left (2)) | 
					
						
							|  |  |  |                                                , m_->worked_.get<grid_mode_band> ().upper_bound (gridsquare.left (2) + "99")); | 
					
						
							|  |  |  |       for (worked_entry const& worked : range) | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |           if ((!mode.size () || mode.toUpper () == worked.mode_) | 
					
						
							|  |  |  |               && (!band.size () || worked.band_ == band.toUpper ())) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               return true; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |       if (mode.size ()) | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |           if (band.size ()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               return m_->worked_.get<grid_mode_band> ().end () | 
					
						
							|  |  |  |                 != m_->worked_.get<grid_mode_band> ().find (std::make_tuple (gridsquare, mode.toUpper (), band.toUpper ())); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               // partial key lookup
 | 
					
						
							|  |  |  |               return m_->worked_.get<grid_mode_band> ().end () | 
					
						
							|  |  |  |                 != m_->worked_.get<grid_mode_band> ().find (std::make_tuple (gridsquare, mode.toUpper ())); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |           if (band.size ()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               return m_->worked_.get<grid_band> ().end () | 
					
						
							|  |  |  |                 != m_->worked_.get<grid_band> ().find (std::make_tuple (gridsquare, band.toUpper ())); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               // partial key lookup
 | 
					
						
							|  |  |  |               return m_->worked_.get<grid_band> ().end () | 
					
						
							|  |  |  |                 != m_->worked_.get<grid_band> ().find (gridsquare); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-09 11:25:50 +01:00
										 |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool WorkedBefore::call_worked (QString const& call, QString const& mode, QString const& band) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (mode.size ()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return m_->worked_.get<call_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<call_mode_band> ().find (std::make_tuple (call.toUpper (), mode.toUpper (), band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return m_->worked_.get<call_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<call_mode_band> ().find (std::make_tuple (call.toUpper (), mode.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return m_->worked_.get<call_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<call_band> ().find (std::make_tuple (call.toUpper (), band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return m_->worked_.get<call_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<call_band> ().find (std::make_tuple (call.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool WorkedBefore::continent_worked (Continent continent, QString const& mode, QString const& band) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (mode.size ()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return m_->worked_.get<continent_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<continent_mode_band> ().find (std::make_tuple (continent, mode.toUpper (), band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return m_->worked_.get<continent_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<continent_mode_band> ().find (std::make_tuple (continent, mode.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return m_->worked_.get<continent_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<continent_band> ().find (std::make_tuple (continent, band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return m_->worked_.get<continent_band> ().end () | 
					
						
							|  |  |  |             != m_->worked_.get<continent_band> ().find (continent); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool WorkedBefore::CQ_zone_worked (int CQ_zone, QString const& mode, QString const& band) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (mode.size ()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return m_->worked_.get<CQ_zone_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<CQ_zone_mode_band> ().find (std::make_tuple (CQ_zone, mode.toUpper (), band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return m_->worked_.get<CQ_zone_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<CQ_zone_mode_band> ().find (std::make_tuple (CQ_zone, mode.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return m_->worked_.get<CQ_zone_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<CQ_zone_band> ().find (std::make_tuple (CQ_zone, band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return m_->worked_.get<CQ_zone_band> ().end () | 
					
						
							|  |  |  |             != m_->worked_.get<CQ_zone_band> ().find (CQ_zone); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool WorkedBefore::ITU_zone_worked (int ITU_zone, QString const& mode, QString const& band) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (mode.size ()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return m_->worked_.get<ITU_zone_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<ITU_zone_mode_band> ().find (std::make_tuple (ITU_zone, mode.toUpper (), band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return m_->worked_.get<ITU_zone_mode_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<ITU_zone_mode_band> ().find (std::make_tuple (ITU_zone, mode.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (band.size ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           return m_->worked_.get<ITU_zone_band> ().end () | 
					
						
							| 
									
										
										
										
											2018-11-29 00:56:53 +00:00
										 |  |  |             != m_->worked_.get<ITU_zone_band> ().find (std::make_tuple (ITU_zone, band.toUpper ())); | 
					
						
							| 
									
										
										
										
											2018-10-26 03:24:36 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           // partial key lookup
 | 
					
						
							|  |  |  |           return m_->worked_.get<ITU_zone_band> ().end () | 
					
						
							|  |  |  |             != m_->worked_.get<ITU_zone_band> ().find (ITU_zone); | 
					
						
							| 
									
										
										
										
											2018-10-25 00:00:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |