2018-10-24 19:00:19 -04:00
# include "WorkedBefore.hpp"
2018-11-14 10:44:36 -05:00
# include <functional>
2018-11-30 11:26:46 -05:00
# include <stdexcept>
2018-11-14 10:44:36 -05:00
# include <boost/functional/hash.hpp>
2018-10-24 19:00:19 -04:00
# include <boost/multi_index_container.hpp>
2018-11-14 10:44:36 -05:00
# include <boost/multi_index/hashed_index.hpp>
2018-10-24 19:00:19 -04:00
# include <boost/multi_index/ordered_index.hpp>
# include <boost/multi_index/key_extractors.hpp>
2019-08-09 06:25:50 -04:00
# include <boost/range/iterator_range.hpp>
2020-09-09 17:40:07 -04:00
# include <QCoreApplication>
2018-11-30 11:26:46 -05:00
# include <QtConcurrent/QtConcurrentRun>
# include <QFuture>
# include <QFutureWatcher>
2018-11-14 10:44:36 -05:00
# include <QChar>
# include <QString>
2018-10-24 19:00:19 -04:00
# include <QByteArray>
# include <QStandardPaths>
# include <QDir>
2018-11-30 11:26:46 -05:00
# include <QFileInfo>
2018-10-24 19:00:19 -04:00
# include <QFile>
# include <QTextStream>
2020-09-07 15:36:09 -04:00
# include <QDateTime>
2019-05-29 18:35:18 -04:00
# include "Configuration.hpp"
2020-09-07 15:36:09 -04:00
# include "revision_utils.hpp"
2018-11-14 10:44:36 -05:00
# include "qt_helpers.hpp"
2018-10-24 19:00:19 -04:00
# include "pimpl_impl.hpp"
2018-11-30 11:26:46 -05:00
# include "moc_WorkedBefore.cpp"
2018-10-25 22:24:36 -04: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-24 19:00:19 -04:00
// worked before set element
2018-11-14 10:44:36 -05:00
//
2018-10-24 19:00:19 -04:00
struct worked_entry
{
2018-10-25 22:24:36 -04: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-24 19:00:19 -04:00
{
}
2018-10-25 22:24:36 -04: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-25 22:24:36 -04:00
struct Continent_less
{
2018-10-26 11:51:54 -04:00
bool operator ( ) ( AD1CCty : : Continent lhs , AD1CCty : : Continent rhs ) const
2018-10-25 22:24:36 -04:00
{
return static_cast < int > ( lhs ) < static_cast < int > ( rhs ) ;
}
2018-10-24 19:00:19 -04:00
} ;
2018-11-14 10:44:36 -05:00
// index tags
2018-10-24 19:00:19 -04:00
struct call_mode_band { } ;
struct call_band { } ;
struct grid_mode_band { } ;
struct grid_band { } ;
struct entity_mode_band { } ;
struct entity_band { } ;
2018-10-25 22:24:36 -04: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-24 19:00:19 -04: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-25 22:24:36 -04:00
typedef multi_index_container <
2018-10-24 19:00:19 -04:00
worked_entry ,
2018-10-25 22:24:36 -04: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-24 19:00:19 -04: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-24 19:00:19 -04: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-24 19:00:19 -04: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-24 19:00:19 -04: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-24 19:00:19 -04: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-25 22:24:36 -04: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-25 22:24:36 -04: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-25 22:24:36 -04: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-25 22:24:36 -04: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-25 22:24:36 -04: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-25 22:24:36 -04: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-25 22:24:36 -04: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-24 19:00:19 -04:00
namespace
{
auto const logFileName = " wsjtx_log.adi " ;
2018-11-30 11:26:46 -05: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-25 22:24:36 -04:00
QString extractField ( QString const & record , QString const & fieldName )
2018-10-24 19:00:19 -04: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 11:26:46 -05:00
else
{
2020-09-09 17:40:07 -04:00
throw LoaderException ( std : : runtime_error { QCoreApplication : : translate ( " WorkedBefore " , " Invalid ADIF field %0: %1 " ) . arg ( fieldName ) . arg ( record ) . toLocal8Bit ( ) } ) ;
2018-11-30 11:26:46 -05:00
}
2018-10-24 19:00:19 -04:00
2018-11-30 11:26:46 -05:00
if ( closingBracketIndex > fieldNameIndex & & fieldLengthIndex > fieldNameIndex & & fieldLengthIndex < closingBracketIndex )
2018-10-24 19:00:19 -04: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-25 22:24:36 -04:00
return record . mid ( closingBracketIndex + 1 , fieldLength ) ;
2018-10-24 19:00:19 -04:00
}
}
2018-11-30 11:26:46 -05:00
else
{
2020-09-09 17:40:07 -04:00
throw LoaderException ( std : : runtime_error { QCoreApplication : : translate ( " WorkedBefore " , " Malformed ADIF field %0: %1 " ) . arg ( fieldName ) . arg ( record ) . toLocal8Bit ( ) } ) ;
2018-11-30 11:26:46 -05:00
}
2018-10-24 19:00:19 -04:00
}
2018-11-30 11:26:46 -05: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 )
{
2020-09-09 17:40:07 -04:00
throw LoaderException ( std : : runtime_error { QCoreApplication : : translate ( " WorkedBefore " , " Invalid ADIF header " ) . toLocal8Bit ( ) } ) ;
2018-11-30 11:26:46 -05:00
}
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 12:06:02 -05:00
if ( end_position > = 0 ) // require valid ADIF record
// with terminator
2018-11-30 11:26:46 -05:00
{
2018-12-10 12:06:02 -05: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-21 21:23:04 -04:00
auto mode = extractField ( record , " MODE " ) . toUpper ( ) ;
if ( ! mode . size ( ) | | " MFSK " = = mode )
{
mode = extractField ( record , " SUBMODE " ) . toUpper ( ) ;
}
2018-12-10 12:06:02 -05:00
worked . emplace ( call . toUpper ( )
, extractField ( record , " GRIDSQUARE " ) . left ( 4 ) . toUpper ( ) // not interested in 6-digit grids
, extractField ( record , " BAND " ) . toUpper ( )
2019-05-21 21:23:04 -04:00
, mode
2018-12-10 12:06:02 -05:00
, entity . entity_name
, entity . continent
, entity . CQ_zone
, entity . ITU_zone ) ;
}
2018-11-30 11:26:46 -05:00
}
}
}
else
{
2020-09-09 17:40:07 -04:00
throw LoaderException ( std : : runtime_error { QCoreApplication : : translate ( " WorkedBefore " , " Error opening ADIF log file for read: %0 " ) . arg ( inputFile . errorString ( ) ) . toLocal8Bit ( ) } ) ;
2018-11-30 11:26:46 -05:00
}
}
return worked ;
2018-10-24 19:00:19 -04:00
}
}
class WorkedBefore : : impl final
{
public :
2019-05-29 18:35:18 -04:00
impl ( Configuration const * configuration )
2019-08-09 06:25:50 -04:00
: configuration_ { configuration }
, path_ { QDir { QStandardPaths : : writableLocation ( QStandardPaths : : DataLocation ) } . absoluteFilePath ( logFileName ) }
2019-05-29 18:35:18 -04:00
, prefixes_ { configuration }
2018-10-24 19:00:19 -04:00
{
}
2018-11-30 11:26:46 -05:00
void reload ( )
{
async_loader_ = QtConcurrent : : run ( loader , path_ , & prefixes_ ) ;
loader_watcher_ . setFuture ( async_loader_ ) ;
}
2019-08-09 06:25:50 -04:00
Configuration const * configuration_ ;
2018-10-24 19:00:19 -04:00
QString path_ ;
2018-10-25 22:24:36 -04:00
AD1CCty prefixes_ ;
2018-11-30 11:26:46 -05: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-24 19:00:19 -04:00
} ;
2019-05-29 18:35:18 -04:00
WorkedBefore : : WorkedBefore ( Configuration const * configuration )
: m_ { configuration }
2018-10-24 19:00:19 -04:00
{
2019-05-29 18:35:18 -04:00
Q_ASSERT ( configuration ) ;
2018-11-30 16:50:44 -05:00
connect ( & m_ - > loader_watcher_ , & QFutureWatcher < worked_before_database_type > : : finished , [ this ] ( ) {
2018-11-30 11:26:46 -05:00
QString error ;
size_t n { 0 } ;
try
2018-10-24 19:00:19 -04:00
{
2018-11-30 11:26:46 -05:00
m_ - > worked_ = m_ - > loader_watcher_ . result ( ) ;
n = m_ - > worked_ . size ( ) ;
2018-10-24 19:00:19 -04:00
}
2018-11-30 11:26:46 -05:00
catch ( LoaderException const & e )
2018-10-24 19:00:19 -04:00
{
2018-11-30 11:26:46 -05:00
error = e . error ( ) ;
2018-10-24 19:00:19 -04:00
}
2018-11-30 11:26:46 -05:00
Q_EMIT finished_loading ( n , error ) ;
} ) ;
reload ( ) ;
}
void WorkedBefore : : reload ( )
{
m_ - > reload ( ) ;
2018-10-24 19:00:19 -04:00
}
WorkedBefore : : ~ WorkedBefore ( )
{
}
QString const & WorkedBefore : : path ( ) const
{
return m_ - > path_ ;
}
2019-05-30 17:20:09 -04:00
AD1CCty const * WorkedBefore : : countries ( ) const
2018-10-24 19:00:19 -04:00
{
2019-05-30 17:20:09 -04:00
return & m_ - > prefixes_ ;
2018-10-24 19:00:19 -04: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-25 22:24:36 -04:00
auto const & entity = m_ - > prefixes_ . lookup ( call ) ;
2018-10-24 19:00:19 -04:00
QFile file { m_ - > path_ } ;
if ( ! file . open ( QIODevice : : Text | QIODevice : : Append ) )
{
return false ;
}
else
{
QTextStream out { & file } ;
if ( ! file . size ( ) )
{
2020-09-07 15:36:09 -04:00
auto ts = QDateTime : : currentDateTimeUtc ( ) . toString ( " yyyyMMdd HHmmss " ) ;
auto ver = version ( true ) ;
out < < // new file
QString {
" ADIF Export \n "
" <adif_ver:5>3.1.1 \n "
" <created_timestamp:15>%0 \n "
" <programid:6>WSJT-X \n "
" <programversion:%1>%2 \n "
" <eoh> "
} . arg ( ts ) . arg ( ver . size ( ) ) . arg ( ver )
< <
2020-06-13 11:04:41 -04:00
# if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
endl
# else
Qt : : endl
# endif
;
2018-10-24 19:00:19 -04:00
}
2020-06-13 11:04:41 -04:00
out < < ADIF_record < < " <eor> " < <
# if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
endl
# else
Qt : : endl
# endif
;
2018-10-24 19:00:19 -04:00
}
2018-11-28 19:56:53 -05: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-24 19:00:19 -04: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-28 19:56:53 -05:00
! = m_ - > worked_ . get < entity_mode_band > ( ) . find ( std : : make_tuple ( country , mode . toUpper ( ) , band . toUpper ( ) ) ) ;
2018-10-24 19:00:19 -04:00
}
else
{
// partial key lookup
return
country . size ( )
& & m_ - > worked_ . get < entity_mode_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < entity_mode_band > ( ) . find ( std : : make_tuple ( country , mode . toUpper ( ) ) ) ;
2018-10-24 19:00:19 -04:00
}
}
else
{
if ( band . size ( ) )
{
return
country . size ( )
& & m_ - > worked_ . get < entity_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < entity_band > ( ) . find ( std : : make_tuple ( country , band . toUpper ( ) ) ) ;
2018-10-24 19:00:19 -04:00
}
else
{
// partial key lookup
return
country . size ( )
& & m_ - > worked_ . get < entity_band > ( ) . end ( )
2018-10-25 22:24:36 -04:00
! = m_ - > worked_ . get < entity_band > ( ) . find ( country ) ;
2018-10-24 19:00:19 -04:00
}
}
}
bool WorkedBefore : : grid_worked ( QString const & grid , QString const & mode , QString const & band ) const
{
2019-08-09 06:25:50 -04:00
auto gridsquare = grid . left ( 4 ) . toUpper ( ) ;
if ( m_ - > configuration_ - > highlight_only_fields ( ) )
2018-10-24 19:00:19 -04:00
{
2019-08-09 06:25:50 -04: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-24 19:00:19 -04:00
{
2019-08-09 06:25:50 -04:00
if ( ( ! mode . size ( ) | | mode . toUpper ( ) = = worked . mode_ )
& & ( ! band . size ( ) | | worked . band_ = = band . toUpper ( ) ) )
{
return true ;
}
2018-10-24 19:00:19 -04:00
}
}
else
{
2019-08-09 06:25:50 -04:00
if ( mode . size ( ) )
2018-10-24 19:00:19 -04:00
{
2019-08-09 06:25:50 -04: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-24 19:00:19 -04:00
}
else
{
2019-08-09 06:25:50 -04: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-24 19:00:19 -04:00
}
}
2019-08-09 06:25:50 -04:00
return false ;
2018-10-24 19:00:19 -04: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-28 19:56:53 -05:00
! = m_ - > worked_ . get < call_mode_band > ( ) . find ( std : : make_tuple ( call . toUpper ( ) , mode . toUpper ( ) , band . toUpper ( ) ) ) ;
2018-10-24 19:00:19 -04:00
}
else
{
// partial key lookup
return m_ - > worked_ . get < call_mode_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < call_mode_band > ( ) . find ( std : : make_tuple ( call . toUpper ( ) , mode . toUpper ( ) ) ) ;
2018-10-24 19:00:19 -04:00
}
}
else
{
if ( band . size ( ) )
{
return m_ - > worked_ . get < call_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < call_band > ( ) . find ( std : : make_tuple ( call . toUpper ( ) , band . toUpper ( ) ) ) ;
2018-10-24 19:00:19 -04:00
}
else
{
// partial key lookup
return m_ - > worked_ . get < call_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < call_band > ( ) . find ( std : : make_tuple ( call . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04: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-28 19:56:53 -05:00
! = m_ - > worked_ . get < continent_mode_band > ( ) . find ( std : : make_tuple ( continent , mode . toUpper ( ) , band . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04:00
}
else
{
// partial key lookup
return m_ - > worked_ . get < continent_mode_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < continent_mode_band > ( ) . find ( std : : make_tuple ( continent , mode . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04:00
}
}
else
{
if ( band . size ( ) )
{
return m_ - > worked_ . get < continent_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < continent_band > ( ) . find ( std : : make_tuple ( continent , band . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04: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-28 19:56:53 -05:00
! = m_ - > worked_ . get < CQ_zone_mode_band > ( ) . find ( std : : make_tuple ( CQ_zone , mode . toUpper ( ) , band . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04:00
}
else
{
// partial key lookup
return m_ - > worked_ . get < CQ_zone_mode_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < CQ_zone_mode_band > ( ) . find ( std : : make_tuple ( CQ_zone , mode . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04:00
}
}
else
{
if ( band . size ( ) )
{
return m_ - > worked_ . get < CQ_zone_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < CQ_zone_band > ( ) . find ( std : : make_tuple ( CQ_zone , band . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04: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-28 19:56:53 -05:00
! = m_ - > worked_ . get < ITU_zone_mode_band > ( ) . find ( std : : make_tuple ( ITU_zone , mode . toUpper ( ) , band . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04:00
}
else
{
// partial key lookup
return m_ - > worked_ . get < ITU_zone_mode_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < ITU_zone_mode_band > ( ) . find ( std : : make_tuple ( ITU_zone , mode . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04:00
}
}
else
{
if ( band . size ( ) )
{
return m_ - > worked_ . get < ITU_zone_band > ( ) . end ( )
2018-11-28 19:56:53 -05:00
! = m_ - > worked_ . get < ITU_zone_band > ( ) . find ( std : : make_tuple ( ITU_zone , band . toUpper ( ) ) ) ;
2018-10-25 22:24:36 -04:00
}
else
{
// partial key lookup
return m_ - > worked_ . get < ITU_zone_band > ( ) . end ( )
! = m_ - > worked_ . get < ITU_zone_band > ( ) . find ( ITU_zone ) ;
2018-10-24 19:00:19 -04:00
}
}
}