diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 00000000..945c9b46 --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/src/database.cpp b/src/database.cpp index d766af15..95a65861 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -80,7 +80,7 @@ DataBase::DataBase(const QString &_parentClass, const QString &_softVersion, con return; } qDebug() << Q_FUNC_INFO << " - - connection Name: " << dbConnectionName ; - qDebug() << Q_FUNC_INFO << " - END"; - DB Name: " << db.databaseName() ; + qDebug() << Q_FUNC_INFO << " - END - DB Name: " << db.databaseName() ; insertPreparedQueries.clear(); insertQueryFields.clear(); qDebug() << Q_FUNC_INFO << " - END"; @@ -1650,7 +1650,7 @@ bool DataBase::recreatePropModes() qDebug() << Q_FUNC_INFO << " - Start"; if (isTheTableExisting("prop_mode_enumeration")) { - f Table Exist" ; + qDebug() << Q_FUNC_INFO << " - Table Exist" ; bool sqlOk = false; sqlOk = execQuery(Q_FUNC_INFO, "DROP TABLE prop_mode_enumeration"); diff --git a/src/qso.cpp b/src/qso.cpp index ba069475..04a70e3e 100644 --- a/src/qso.cpp +++ b/src/qso.cpp @@ -590,6 +590,480 @@ bool QSO::copy(const QSO& other) return true; } +bool QSO::completeWith(const QSO& q2) +{ // Complete the calling QSO with values from q2 where the calling QSO has empty values + // If the calling QSO has a value in a variable and q2 too, q2 value is never overwriting the value of the calling QSO + + // Helper macros for checking empty values + #define IS_EMPTY_STRING(s) ((s).isEmpty()) + #define IS_EMPTY_INT(i, empty_val) ((i) == (empty_val)) + #define IS_EMPTY_DOUBLE(d, empty_val) ((d) == (empty_val)) + #define IS_EMPTY_BOOL(b, empty_val) ((b) == (empty_val)) + #define IS_EMPTY_DATE(d) (!(d).isValid()) + #define IS_EMPTY_DATETIME(dt) (!(dt).isValid()) + + // Complete LogId if empty + if (IS_EMPTY_INT(logId, -1) && !IS_EMPTY_INT(q2.logId, -1)) + setLogId(q2.logId); + + // Complete StationCallsign if empty + if (IS_EMPTY_STRING(stationCallsign) && !IS_EMPTY_STRING(q2.stationCallsign)) + setStationCallsign(q2.stationCallsign); + + // Complete ADIF fields if empty + if (IS_EMPTY_STRING(address) && !IS_EMPTY_STRING(q2.address)) + setAddress(q2.address); + + if (IS_EMPTY_DOUBLE(age, -1.0) && !IS_EMPTY_DOUBLE(q2.age, -1.0)) + setAge(q2.age); + + if (IS_EMPTY_DOUBLE(altitude, 0.0) && !IS_EMPTY_DOUBLE(q2.altitude, 0.0)) + setAltitude(q2.altitude); + + if (IS_EMPTY_DOUBLE(a_index, -1.0) && !IS_EMPTY_DOUBLE(q2.a_index, -1.0)) + setA_Index(q2.a_index); + + if (IS_EMPTY_DOUBLE(ant_az, -91.0) && !IS_EMPTY_DOUBLE(q2.ant_az, -91.0)) + setAnt_az(q2.ant_az); + + if (IS_EMPTY_DOUBLE(ant_el, -91.0) && !IS_EMPTY_DOUBLE(q2.ant_el, -91.0)) + setAnt_el(q2.ant_el); + + if (IS_EMPTY_STRING(ant_path) && !IS_EMPTY_STRING(q2.ant_path)) + setAnt_Path(q2.ant_path); + + if (IS_EMPTY_STRING(arrl_sect) && !IS_EMPTY_STRING(q2.arrl_sect)) + setARRL_Sect(q2.arrl_sect); + + if (IS_EMPTY_STRING(award_submitted) && !IS_EMPTY_STRING(q2.award_submitted)) + setAwardSubmitted(q2.award_submitted); + + if (IS_EMPTY_STRING(award_granted) && !IS_EMPTY_STRING(q2.award_granted)) + setAwardGranted(q2.award_granted); + + if (IS_EMPTY_STRING(band) && !IS_EMPTY_STRING(q2.band)) + setBand(q2.band); + + if (IS_EMPTY_STRING(band_rx) && !IS_EMPTY_STRING(q2.band_rx)) + setBandRX(q2.band_rx); + + if (IS_EMPTY_STRING(callsign) && !IS_EMPTY_STRING(q2.callsign)) + setCall(q2.callsign); + + if (IS_EMPTY_STRING(check) && !IS_EMPTY_STRING(q2.check)) + setCheck(q2.check); + + if (IS_EMPTY_STRING(clase) && !IS_EMPTY_STRING(q2.clase)) + setClass(q2.clase); + + if (IS_EMPTY_DATE(clublogQSOUpdateDate) && !IS_EMPTY_DATE(q2.clublogQSOUpdateDate)) + setClubLogDate(q2.clublogQSOUpdateDate); + + if (IS_EMPTY_STRING(clublog_status) && !IS_EMPTY_STRING(q2.clublog_status)) + setClubLogStatus(q2.clublog_status); + + if (IS_EMPTY_STRING(county) && !IS_EMPTY_STRING(q2.county)) + setCounty(q2.county); + + if (IS_EMPTY_STRING(comment) && !IS_EMPTY_STRING(q2.comment)) + setComment(q2.comment); + + if (IS_EMPTY_STRING(continent) && !IS_EMPTY_STRING(q2.continent)) + setContinent(q2.continent); + + if (IS_EMPTY_STRING(contacted_op) && !IS_EMPTY_STRING(q2.contacted_op)) + setContactedOperator(q2.contacted_op); + + if (IS_EMPTY_STRING(contest_id) && !IS_EMPTY_STRING(q2.contest_id)) + setContestID(q2.contest_id); + + if (IS_EMPTY_STRING(country) && !IS_EMPTY_STRING(q2.country)) + setCountry(q2.country); + + if (IS_EMPTY_INT(cqz, 0) && !IS_EMPTY_INT(q2.cqz, 0)) + setCQZone(q2.cqz); + + if (IS_EMPTY_STRING(credit_granted) && !IS_EMPTY_STRING(q2.credit_granted)) + setCreditGranted(q2.credit_granted); + + if (IS_EMPTY_STRING(credit_submitted) && !IS_EMPTY_STRING(q2.credit_submitted)) + setCreditSubmitted(q2.credit_submitted); + + if (IS_EMPTY_STRING(darc_dok) && !IS_EMPTY_STRING(q2.darc_dok)) + setDarcDok(q2.darc_dok); + + if (IS_EMPTY_DOUBLE(distance, -1.0) && !IS_EMPTY_DOUBLE(q2.distance, -1.0)) + setDistance(q2.distance); + + if (IS_EMPTY_INT(dxcc, 0) && !IS_EMPTY_INT(q2.dxcc, 0)) + setDXCC(q2.dxcc); + + if (IS_EMPTY_STRING(email) && !IS_EMPTY_STRING(q2.email)) + setEmail(q2.email); + + if (IS_EMPTY_STRING(ownerCall) && !IS_EMPTY_STRING(q2.ownerCall)) + setOwnerCallsign(q2.ownerCall); + + if (IS_EMPTY_STRING(contacted_owner) && !IS_EMPTY_STRING(q2.contacted_owner)) + setEQ_Call(q2.contacted_owner); + + if (IS_EMPTY_DATE(eQSLRDate) && !IS_EMPTY_DATE(q2.eQSLRDate)) + setEQSLQSLRDate(q2.eQSLRDate); + + if (IS_EMPTY_DATE(eQSLSDate) && !IS_EMPTY_DATE(q2.eQSLSDate)) + setEQSLQSLSDate(q2.eQSLSDate); + + if (IS_EMPTY_STRING(eqsl_qsl_rcvd) && !IS_EMPTY_STRING(q2.eqsl_qsl_rcvd)) + setEQSLQSL_RCVD(q2.eqsl_qsl_rcvd); + + if (IS_EMPTY_STRING(eqsl_qsl_sent) && !IS_EMPTY_STRING(q2.eqsl_qsl_sent)) + setEQSLQSL_SENT(q2.eqsl_qsl_sent); + + if (IS_EMPTY_INT(fists, -1) && !IS_EMPTY_INT(q2.fists, -1)) + setFists(q2.fists); + + if (IS_EMPTY_INT(fists_cc, -1) && !IS_EMPTY_INT(q2.fists_cc, -1)) + setFistsCC(q2.fists_cc); + + if (IS_EMPTY_BOOL(forceInit, false) && !IS_EMPTY_BOOL(q2.forceInit, false)) + setForceInit(q2.forceInit); + + // For Frequency objects, we can't call isValid() on const references because + // Frequency::isValid() is not declared const. We create temporary copies to check validity. + // Direct assignment is used (not setters) because setFreq/setFreqRX take doubles, not Frequency objects, + // and Frequency::toDouble() is also non-const. This is consistent with the copy() method. + Frequency temp_freq_tx = freq_tx; + Frequency temp_freq_rx = freq_rx; + Frequency temp_q2_freq_tx = q2.freq_tx; + Frequency temp_q2_freq_rx = q2.freq_rx; + + if (!temp_freq_tx.isValid() && temp_q2_freq_tx.isValid()) + freq_tx = q2.freq_tx; + + if (!temp_freq_rx.isValid() && temp_q2_freq_rx.isValid()) + freq_rx = q2.freq_rx; + + if (IS_EMPTY_STRING(gridsquare) && !IS_EMPTY_STRING(q2.gridsquare)) + setGridSquare(q2.gridsquare); + + if (IS_EMPTY_STRING(gridsquare_ext) && !IS_EMPTY_STRING(q2.gridsquare_ext)) + setGridSquare_ext(q2.gridsquare_ext); + + if (IS_EMPTY_STRING(operatorCall) && !IS_EMPTY_STRING(q2.operatorCall)) + setOperatorCallsign(q2.operatorCall); + + if (IS_EMPTY_DATE(hrdlogUploadDate) && !IS_EMPTY_DATE(q2.hrdlogUploadDate)) + setHRDUpdateDate(q2.hrdlogUploadDate); + + if (IS_EMPTY_STRING(hrdlog_status) && !IS_EMPTY_STRING(q2.hrdlog_status)) + setHRDLogStatus(q2.hrdlog_status); + + if (IS_EMPTY_DATE(hamlogeuUpdateDate) && !IS_EMPTY_DATE(q2.hamlogeuUpdateDate)) + setHamLogEUUpdateDate(q2.hamlogeuUpdateDate); + + if (IS_EMPTY_STRING(hamlogeu_status) && !IS_EMPTY_STRING(q2.hamlogeu_status)) + setHamLogEUStatus(q2.hamlogeu_status); + + if (IS_EMPTY_DATE(hamqthUpdateDate) && !IS_EMPTY_DATE(q2.hamqthUpdateDate)) + setHamQTHUpdateDate(q2.hamqthUpdateDate); + + if (IS_EMPTY_STRING(hamqth_status) && !IS_EMPTY_STRING(q2.hamqth_status)) + setHamQTHStatus(q2.hamqth_status); + + if (IS_EMPTY_STRING(iota) && !IS_EMPTY_STRING(q2.iota)) + setIOTA(q2.iota); + + if (IS_EMPTY_INT(iota_ID, -1) && !IS_EMPTY_INT(q2.iota_ID, -1)) + setIotaID(q2.iota_ID); + + if (IS_EMPTY_INT(itu_zone, 0) && !IS_EMPTY_INT(q2.itu_zone, 0)) + setItuZone(q2.itu_zone); + + if (IS_EMPTY_INT(k_index, -1) && !IS_EMPTY_INT(q2.k_index, -1)) + setK_Index(q2.k_index); + + if (IS_EMPTY_STRING(latitude) && !IS_EMPTY_STRING(q2.latitude)) + setLatitude(q2.latitude); + + if (IS_EMPTY_STRING(longitude) && !IS_EMPTY_STRING(q2.longitude)) + setLongitude(q2.longitude); + + if (IS_EMPTY_DATE(QSLLoTWRDate) && !IS_EMPTY_DATE(q2.QSLLoTWRDate)) + setLoTWQSLRDate(q2.QSLLoTWRDate); + + if (IS_EMPTY_DATE(QSLLoTWSDate) && !IS_EMPTY_DATE(q2.QSLLoTWSDate)) + setLoTWQSLSDate(q2.QSLLoTWSDate); + + if (IS_EMPTY_STRING(lotw_qsl_rcvd) && !IS_EMPTY_STRING(q2.lotw_qsl_rcvd)) + setLoTWQSL_RCVD(q2.lotw_qsl_rcvd); + + if (IS_EMPTY_STRING(lotw_qsl_sent) && !IS_EMPTY_STRING(q2.lotw_qsl_sent)) + setLoTWQSL_SENT(q2.lotw_qsl_sent); + + if (IS_EMPTY_INT(max_bursts, 0) && !IS_EMPTY_INT(q2.max_bursts, 0)) + setMaxBursts(q2.max_bursts); + + if (IS_EMPTY_STRING(mode) && !IS_EMPTY_STRING(q2.mode)) + setMode(q2.mode); + + if (IS_EMPTY_STRING(ms_shower) && !IS_EMPTY_STRING(q2.ms_shower)) + setMsShower(q2.ms_shower); + + if (IS_EMPTY_DOUBLE(my_altitude, 0.0) && !IS_EMPTY_DOUBLE(q2.my_altitude, 0.0)) + setMyAltitude(q2.my_altitude); + + if (IS_EMPTY_STRING(my_antenna) && !IS_EMPTY_STRING(q2.my_antenna)) + setMyAntenna(q2.my_antenna); + + if (IS_EMPTY_STRING(my_arrl_sect) && !IS_EMPTY_STRING(q2.my_arrl_sect)) + setMyARRL_Sect(q2.my_arrl_sect); + + if (IS_EMPTY_STRING(my_city) && !IS_EMPTY_STRING(q2.my_city)) + setMyCity(q2.my_city); + + if (IS_EMPTY_STRING(my_county) && !IS_EMPTY_STRING(q2.my_county)) + setMyCounty(q2.my_county); + + if (IS_EMPTY_STRING(my_country) && !IS_EMPTY_STRING(q2.my_country)) + setMyCountry(q2.my_country); + + if (IS_EMPTY_INT(my_cqz, 0) && !IS_EMPTY_INT(q2.my_cqz, 0)) + setMyCQZone(q2.my_cqz); + + if (IS_EMPTY_INT(my_dxcc, 0) && !IS_EMPTY_INT(q2.my_dxcc, 0)) + setMyDXCC(q2.my_dxcc); + + if (IS_EMPTY_INT(my_fists, -1) && !IS_EMPTY_INT(q2.my_fists, -1)) + setMyFists(q2.my_fists); + + if (IS_EMPTY_STRING(my_gridsquare) && !IS_EMPTY_STRING(q2.my_gridsquare)) + setMyGridSquare(q2.my_gridsquare); + + if (IS_EMPTY_STRING(my_gridsquare_ext) && !IS_EMPTY_STRING(q2.my_gridsquare_ext)) + setMyGridSquare_ext(q2.my_gridsquare_ext); + + if (IS_EMPTY_STRING(my_iota) && !IS_EMPTY_STRING(q2.my_iota)) + setMyIOTA(q2.my_iota); + + if (IS_EMPTY_INT(my_iota_ID, -1) && !IS_EMPTY_INT(q2.my_iota_ID, -1)) + setMyIotaID(q2.my_iota_ID); + + if (IS_EMPTY_INT(my_itu_zone, 0) && !IS_EMPTY_INT(q2.my_itu_zone, 0)) + setMyITUZone(q2.my_itu_zone); + + if (IS_EMPTY_STRING(my_latitude) && !IS_EMPTY_STRING(q2.my_latitude)) + setMyLatitude(q2.my_latitude); + + if (IS_EMPTY_STRING(my_longitude) && !IS_EMPTY_STRING(q2.my_longitude)) + setMyLongitude(q2.my_longitude); + + if (IS_EMPTY_STRING(my_name) && !IS_EMPTY_STRING(q2.my_name)) + setMyName(q2.my_name); + + if (IS_EMPTY_STRING(my_pota_ref) && !IS_EMPTY_STRING(q2.my_pota_ref)) + setMyPOTA_Ref(q2.my_pota_ref); + + if (IS_EMPTY_STRING(my_postal_code) && !IS_EMPTY_STRING(q2.my_postal_code)) + setMyPostalCode(q2.my_postal_code); + + if (IS_EMPTY_STRING(my_rig) && !IS_EMPTY_STRING(q2.my_rig)) + setMyRig(q2.my_rig); + + if (IS_EMPTY_STRING(my_sig) && !IS_EMPTY_STRING(q2.my_sig)) + setMySig(q2.my_sig); + + if (IS_EMPTY_STRING(my_sig_info) && !IS_EMPTY_STRING(q2.my_sig_info)) + setMySigInfo(q2.my_sig_info); + + if (IS_EMPTY_STRING(my_sota_ref) && !IS_EMPTY_STRING(q2.my_sota_ref)) + setMySOTA_REF(q2.my_sota_ref); + + if (IS_EMPTY_STRING(my_state) && !IS_EMPTY_STRING(q2.my_state)) + setMyState(q2.my_state); + + if (IS_EMPTY_STRING(my_street) && !IS_EMPTY_STRING(q2.my_street)) + setMyStreet(q2.my_street); + + if (IS_EMPTY_STRING(my_usaca_counties) && !IS_EMPTY_STRING(q2.my_usaca_counties)) + setMyUsacaCounties(q2.my_usaca_counties); + + if (IS_EMPTY_STRING(my_vucc_grids) && !IS_EMPTY_STRING(q2.my_vucc_grids)) + setMyVUCCGrids(q2.my_vucc_grids); + + if (IS_EMPTY_STRING(my_wwff_ref) && !IS_EMPTY_STRING(q2.my_wwff_ref)) + setMyWWFF_Ref(q2.my_wwff_ref); + + if (IS_EMPTY_STRING(name) && !IS_EMPTY_STRING(q2.name)) + setName(q2.name); + + if (IS_EMPTY_STRING(notes) && !IS_EMPTY_STRING(q2.notes)) + setNotes(q2.notes); + + if (IS_EMPTY_INT(nr_bursts, 0) && !IS_EMPTY_INT(q2.nr_bursts, 0)) + setNrBursts(q2.nr_bursts); + + if (IS_EMPTY_INT(nr_pings, 0) && !IS_EMPTY_INT(q2.nr_pings, 0)) + setNrPings(q2.nr_pings); + + if (IS_EMPTY_STRING(prefix) && !IS_EMPTY_STRING(q2.prefix)) + setPrefix(q2.prefix); + + if (IS_EMPTY_STRING(pota_ref) && !IS_EMPTY_STRING(q2.pota_ref)) + setPOTA_Ref(q2.pota_ref); + + if (IS_EMPTY_STRING(precedence) && !IS_EMPTY_STRING(q2.precedence)) + setPrecedence(q2.precedence); + + if (IS_EMPTY_STRING(propMode) && !IS_EMPTY_STRING(q2.propMode)) + setPropMode(q2.propMode); + + if (IS_EMPTY_STRING(public_key) && !IS_EMPTY_STRING(q2.public_key)) + setPublicKey(q2.public_key); + + if (IS_EMPTY_DATE(QRZComDate) && !IS_EMPTY_DATE(q2.QRZComDate)) + setQRZCOMDate(q2.QRZComDate); + + if (IS_EMPTY_STRING(QRZCom_status) && !IS_EMPTY_STRING(q2.QRZCom_status)) + setQRZCOMStatus(q2.QRZCom_status); + + if (IS_EMPTY_STRING(qslmsg) && !IS_EMPTY_STRING(q2.qslmsg)) + setQSLMsg(q2.qslmsg); + + if (IS_EMPTY_DATE(QSLRDate) && !IS_EMPTY_DATE(q2.QSLRDate)) + setQSLRDate(q2.QSLRDate); + + if (IS_EMPTY_DATE(QSLSDate) && !IS_EMPTY_DATE(q2.QSLSDate)) + setQSLSDate(q2.QSLSDate); + + if (IS_EMPTY_STRING(qsl_rcvd) && !IS_EMPTY_STRING(q2.qsl_rcvd)) + setQSL_RCVD(q2.qsl_rcvd); + + if (IS_EMPTY_STRING(qsl_sent) && !IS_EMPTY_STRING(q2.qsl_sent)) + setQSL_SENT(q2.qsl_sent); + + if (IS_EMPTY_STRING(qslSenVia) && !IS_EMPTY_STRING(q2.qslSenVia)) + setQSLSenVia(q2.qslSenVia); + + if (IS_EMPTY_STRING(qslRecVia) && !IS_EMPTY_STRING(q2.qslRecVia)) + setQSLRecVia(q2.qslRecVia); + + if (IS_EMPTY_STRING(qslVia) && !IS_EMPTY_STRING(q2.qslVia)) + setQSLVia(q2.qslVia); + + // qso_complete has default "Y", only complete if current is empty string + if (IS_EMPTY_STRING(qso_complete) && !IS_EMPTY_STRING(q2.qso_complete)) + setQSOComplete(q2.qso_complete); + + if (IS_EMPTY_DATETIME(qso_dateTime) && !IS_EMPTY_DATETIME(q2.qso_dateTime)) + setDateTimeOn(q2.qso_dateTime); + + if (IS_EMPTY_DATETIME(qso_dateTime_off) && !IS_EMPTY_DATETIME(q2.qso_dateTime_off)) + setDateTimeOff(q2.qso_dateTime_off); + + // qso_random has default true, only complete if current is false + if (IS_EMPTY_BOOL(qso_random, false) && !IS_EMPTY_BOOL(q2.qso_random, false)) + setQSORandom(q2.qso_random); + + if (IS_EMPTY_STRING(qth) && !IS_EMPTY_STRING(q2.qth)) + setQTH(q2.qth); + + if (IS_EMPTY_STRING(region) && !IS_EMPTY_STRING(q2.region)) + setRegion(q2.region); + + if (IS_EMPTY_STRING(rig) && !IS_EMPTY_STRING(q2.rig)) + setRig(q2.rig); + + if (IS_EMPTY_STRING(RST_rx) && !IS_EMPTY_STRING(q2.RST_rx)) + setRSTRX(q2.RST_rx); + + if (IS_EMPTY_STRING(RST_tx) && !IS_EMPTY_STRING(q2.RST_tx)) + setRSTTX(q2.RST_tx); + + if (IS_EMPTY_DOUBLE(pwr_rx, 0.0) && !IS_EMPTY_DOUBLE(q2.pwr_rx, 0.0)) + setRXPwr(q2.pwr_rx); + + if (IS_EMPTY_STRING(satMode) && !IS_EMPTY_STRING(q2.satMode)) + setSatMode(q2.satMode); + + if (IS_EMPTY_STRING(satName) && !IS_EMPTY_STRING(q2.satName)) + setSatName(q2.satName); + + if (IS_EMPTY_INT(sfi, -1) && !IS_EMPTY_INT(q2.sfi, -1)) + setSFI(q2.sfi); + + if (IS_EMPTY_STRING(sig) && !IS_EMPTY_STRING(q2.sig)) + setSIG(q2.sig); + + if (IS_EMPTY_STRING(sig_info) && !IS_EMPTY_STRING(q2.sig_info)) + setSIG_INFO(q2.sig_info); + + // silent_key has default false, only complete if current is false + if (IS_EMPTY_BOOL(silent_key, false) && !IS_EMPTY_BOOL(q2.silent_key, false)) + setSilentKey(q2.silent_key); + + if (IS_EMPTY_STRING(skcc) && !IS_EMPTY_STRING(q2.skcc)) + setSkcc(q2.skcc); + + if (IS_EMPTY_STRING(sota_ref) && !IS_EMPTY_STRING(q2.sota_ref)) + setSOTA_REF(q2.sota_ref); + + if (IS_EMPTY_INT(srx, -1) && !IS_EMPTY_INT(q2.srx, -1)) + setSrx(q2.srx); + + if (IS_EMPTY_STRING(srx_string) && !IS_EMPTY_STRING(q2.srx_string)) + setSrxString(q2.srx_string); + + if (IS_EMPTY_STRING(state) && !IS_EMPTY_STRING(q2.state)) + setState(q2.state); + + if (IS_EMPTY_INT(stx, -1) && !IS_EMPTY_INT(q2.stx, -1)) + setStx(q2.stx); + + if (IS_EMPTY_STRING(stx_string) && !IS_EMPTY_STRING(q2.stx_string)) + setStxString(q2.stx_string); + + if (IS_EMPTY_STRING(submode) && !IS_EMPTY_STRING(q2.submode)) + setSubmode(q2.submode); + + // swl has default false, only complete if current is false + if (IS_EMPTY_BOOL(swl, false) && !IS_EMPTY_BOOL(q2.swl, false)) + setSwl(q2.swl); + + if (IS_EMPTY_INT(ten_ten, 0) && !IS_EMPTY_INT(q2.ten_ten, 0)) + setTenTen(q2.ten_ten); + + if (IS_EMPTY_DOUBLE(pwr_tx, 0.0) && !IS_EMPTY_DOUBLE(q2.pwr_tx, 0.0)) + setTXPwr(q2.pwr_tx); + + if (IS_EMPTY_INT(uksmg, 0) && !IS_EMPTY_INT(q2.uksmg, 0)) + setUksmg(q2.uksmg); + + if (IS_EMPTY_STRING(usaca_counties) && !IS_EMPTY_STRING(q2.usaca_counties)) + setUsacaCounties(q2.usaca_counties); + + if (IS_EMPTY_STRING(ve_prov) && !IS_EMPTY_STRING(q2.ve_prov)) + setVeProv(q2.ve_prov); + + if (IS_EMPTY_STRING(vucc_grids) && !IS_EMPTY_STRING(q2.vucc_grids)) + setVUCCGrids(q2.vucc_grids); + + if (IS_EMPTY_STRING(web) && !IS_EMPTY_STRING(q2.web)) + setWeb(q2.web); + + if (IS_EMPTY_STRING(wwff_ref) && !IS_EMPTY_STRING(q2.wwff_ref)) + setWWFF_Ref(q2.wwff_ref); + + // Clean up macros + #undef IS_EMPTY_STRING + #undef IS_EMPTY_INT + #undef IS_EMPTY_DOUBLE + #undef IS_EMPTY_BOOL + #undef IS_EMPTY_DATE + #undef IS_EMPTY_DATETIME + + return true; +} + void QSO::setLogLevel (const DebugLogLevel _b) { logEvent (Q_FUNC_INFO, "Start", Debug); diff --git a/src/qso.h b/src/qso.h index b7c1c402..e1bda4bf 100644 --- a/src/qso.h +++ b/src/qso.h @@ -50,6 +50,7 @@ class QSO : public QObject void operator=(QSO const &_other); bool copy(const QSO& other); + bool completeWith(const QSO& q2); void setLogLevel (const DebugLogLevel _b); void setRealTime(const bool _rt); // Not QSO info but KLog status bool getRealTime() const; diff --git a/tests/tst_qso/CMakeLists.txt b/tests/tst_qso/CMakeLists.txt index f437c99d..932aea45 100644 --- a/tests/tst_qso/CMakeLists.txt +++ b/tests/tst_qso/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Find Qt6 Core and Test modules -find_package(Qt6 REQUIRED COMPONENTS Core Test Sql) +find_package(Qt6 REQUIRED COMPONENTS Core Test Sql Widgets) # Enable AUTOMOC before add_executable set(CMAKE_AUTOMOC ON) @@ -24,6 +24,7 @@ add_executable(tst_qso ../../src/frequency.cpp ../../src/locator.cpp ../../src/qso.cpp + ../../src/qsodatacache.cpp ../../src/adif.cpp ${TEST_HEADERS} diff --git a/tests/tst_qso/tst_qso.cpp b/tests/tst_qso/tst_qso.cpp index 91106d70..763c6bba 100644 --- a/tests/tst_qso/tst_qso.cpp +++ b/tests/tst_qso/tst_qso.cpp @@ -54,6 +54,10 @@ private slots: //TODO: void test_LoTWImport(); void test_Copy(); void test_ModeManagement(); + void test_CompleteWith(); + void test_CompleteWith_EmptyQSO(); + void test_CompleteWith_NumericFields(); + void test_CompleteWith_DateFields(); private: QSO *qso; @@ -452,6 +456,155 @@ void tst_QSO::test_Copy() QVERIFY2(qso3.getComment() == "QSO1-comment", "Wrong Comment in copy"); } +void tst_QSO::test_CompleteWith() +{ + // Test the completeWith method + QSO qso1, qso2; + + // Setup qso1 with some values + qso1.setCall("EA4K"); + qso1.setBand("20M"); + qso1.setMode("SSB"); + qso1.setDateTimeOn(QDateTime::currentDateTimeUtc()); + qso1.setRSTTX("59"); + qso1.setName("John"); + qso1.setQTH("Madrid"); + + // Setup qso2 with some overlapping and some different values + qso2.setCall("EA4K"); // Same call + qso2.setBand("20M"); // Same band + qso2.setRSTRX("58"); // Different field (qso1 doesn't have this) + qso2.setGridSquare("IN80"); // Different field (qso1 doesn't have this) + qso2.setComment("Test comment"); // Different field (qso1 doesn't have this) + qso2.setQTH("Barcelona"); // Different value (qso1 has "Madrid") + qso2.setName("Jane"); // Different value (qso1 has "John") + + // Call completeWith - qso1 should get values from qso2 only where qso1 is empty + qso1.completeWith(qso2); + + // Verify that qso1's existing values are NOT overwritten + QVERIFY2(qso1.getCall() == "EA4K", "Call should remain unchanged"); + QVERIFY2(qso1.getBand() == "20M", "Band should remain unchanged"); + QVERIFY2(qso1.getMode() == "SSB", "Mode should remain unchanged"); + QVERIFY2(qso1.getRSTTX() == "59", "RSTTX should remain unchanged"); + QVERIFY2(qso1.getName() == "John", "Name should NOT be overwritten"); + QVERIFY2(qso1.getQTH() == "Madrid", "QTH should NOT be overwritten"); + + // Verify that qso1's empty values ARE filled from qso2 + QVERIFY2(qso1.getRSTRX() == "58", "RSTRX should be filled from qso2"); + QVERIFY2(qso1.getGridSquare() == "IN80", "GridSquare should be filled from qso2"); + QVERIFY2(qso1.getComment() == "Test comment", "Comment should be filled from qso2"); +} + +void tst_QSO::test_CompleteWith_EmptyQSO() +{ + // Test completeWith when the calling QSO is empty + QSO qso1, qso2; + + // qso1 is empty, qso2 has values + qso2.setCall("EA4K"); + qso2.setBand("40M"); + qso2.setMode("CW"); + qso2.setDateTimeOn(QDateTime::currentDateTimeUtc()); + qso2.setRSTTX("599"); + qso2.setRSTRX("579"); + qso2.setName("Alice"); + qso2.setQTH("London"); + qso2.setGridSquare("IO91"); + qso2.setComment("Nice QSO"); + qso2.setMyGridSquare("IN80"); + qso2.setOperatorCallsign("EA4X"); + + // Call completeWith + qso1.completeWith(qso2); + + // Verify that all values from qso2 are copied to qso1 + QVERIFY2(qso1.getCall() == "EA4K", "Call should be filled from qso2"); + QVERIFY2(qso1.getBand() == "40M", "Band should be filled from qso2"); + QVERIFY2(qso1.getMode() == "CW", "Mode should be filled from qso2"); + QVERIFY2(qso1.getRSTTX() == "599", "RSTTX should be filled from qso2"); + QVERIFY2(qso1.getRSTRX() == "579", "RSTRX should be filled from qso2"); + QVERIFY2(qso1.getName() == "Alice", "Name should be filled from qso2"); + QVERIFY2(qso1.getQTH() == "London", "QTH should be filled from qso2"); + QVERIFY2(qso1.getGridSquare() == "IO91", "GridSquare should be filled from qso2"); + QVERIFY2(qso1.getComment() == "Nice QSO", "Comment should be filled from qso2"); + QVERIFY2(qso1.getMyGridSquare() == "IN80", "MyGridSquare should be filled from qso2"); + QVERIFY2(qso1.getOperatorCallsign() == "EA4X", "OperatorCallsign should be filled from qso2"); +} + +void tst_QSO::test_CompleteWith_NumericFields() +{ + // Test completeWith with numeric fields + QSO qso1, qso2; + + // Setup qso1 with some numeric values + qso1.setCall("EA4K"); + qso1.setBand("20M"); + qso1.setMode("SSB"); + qso1.setDateTimeOn(QDateTime::currentDateTimeUtc()); + qso1.setDXCC(280); // Spain + qso1.setCQZone(14); + qso1.setTXPwr(100.0); + + // Setup qso2 with overlapping and different numeric values + qso2.setDXCC(280); // Same DXCC + qso2.setItuZone(37); // Different field + qso2.setRXPwr(50.0); // Different field + qso2.setA_Index(5.0); // Different field + qso2.setK_Index(2); // Different field + qso2.setTXPwr(200.0); // Different value (qso1 has 100.0) + qso2.setCQZone(15); // Different value (qso1 has 14) + + // Call completeWith + qso1.completeWith(qso2); + + // Verify that qso1's existing numeric values are NOT overwritten + QVERIFY2(qso1.getDXCC() == 280, "DXCC should remain unchanged"); + QVERIFY2(qso1.getCQZone() == 14, "CQZone should NOT be overwritten"); + QVERIFY2(qso1.getTXPwr() == 100.0, "TXPwr should NOT be overwritten"); + + // Verify that qso1's empty numeric values ARE filled from qso2 + QVERIFY2(qso1.getItuZone() == 37, "ItuZone should be filled from qso2"); + QVERIFY2(qso1.getRXPwr() == 50.0, "RXPwr should be filled from qso2"); + QVERIFY2(qso1.getA_Index() == 5.0, "A_Index should be filled from qso2"); + QVERIFY2(qso1.getK_Index() == 2, "K_Index should be filled from qso2"); +} + +void tst_QSO::test_CompleteWith_DateFields() +{ + // Test completeWith with date fields + QSO qso1, qso2; + + QDate date1(2024, 1, 15); + QDate date2(2024, 2, 20); + QDate date3(2024, 3, 25); + + // Setup qso1 with some date values + qso1.setCall("EA4K"); + qso1.setBand("20M"); + qso1.setMode("SSB"); + qso1.setDateTimeOn(QDateTime::currentDateTimeUtc()); + qso1.setQSLSDate(date1); + qso1.setLoTWQSLRDate(date2); + + // Setup qso2 with overlapping and different date values + qso2.setQSLSDate(date3); // Different value (qso1 has date1) + qso2.setQSLRDate(date2); // Different field + qso2.setEQSLQSLSDate(date1); // Different field + qso2.setLoTWQSLRDate(date3); // Different value (qso1 has date2) + + // Call completeWith + qso1.completeWith(qso2); + + // Verify that qso1's existing date values are NOT overwritten + QVERIFY2(qso1.getQSLSDate() == date1, "QSLSDate should NOT be overwritten"); + QVERIFY2(qso1.getLoTWQSLRDate() == date2, "LoTWQSLRDate should NOT be overwritten"); + + // Verify that qso1's empty date values ARE filled from qso2 + QVERIFY2(qso1.getQSLRDate() == date2, "QSLRDate should be filled from qso2"); + QVERIFY2(qso1.getEQSLQSLSDate() == date1, "EQSLQSLSDate should be filled from qso2"); +} + //QTEST_APPLESS_MAIN(tst_QSO) QTEST_GUILESS_MAIN(tst_QSO)