fix(import): "fill my station fields" fills the station callsign too
STATION_CALLSIGN was the one field the option deliberately skipped, on the grounds that stamping the active call could re-route a mixed-call log. That protected nothing. The same option already writes this profile's grid, rig, antenna, city and postal address onto every record it finds blank — it has assumed "this log is mine" long before it reaches the callsign. And the thing that actually keeps a multi-op log intact is that a record CARRYING a station callsign is never touched, which has always been true and still is. Withholding it only meant the option quietly failed on the one field an operator goes and checks afterwards, leaving imported QSOs with no station call at all — invisible in the ADIF they export, and unroutable for LoTW and Club Log. Counted and logged: "did it fill the callsign?" is the first question after an import, and the log is where it gets answered.
This commit is contained in:
@@ -3155,9 +3155,10 @@ func (a *App) applyStationDefaults(q *qso.QSO, includeIdentity bool) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// STATION_CALLSIGN drives upload routing, so only stamp it on NEW QSOs — on
|
// STATION_CALLSIGN drives upload routing, so it is filled only when the
|
||||||
// import backfill, stamping the active call onto a QSO that lacked one could
|
// caller asks for identity — and only when the record has none. A QSO that
|
||||||
// misroute it in a mixed-call log.
|
// already names its station keeps it, which is what stops a mixed-call log
|
||||||
|
// being re-routed; a QSO with the field blank has nothing to protect.
|
||||||
if includeIdentity && q.StationCallsign == "" {
|
if includeIdentity && q.StationCallsign == "" {
|
||||||
q.StationCallsign = p.Callsign
|
q.StationCallsign = p.Callsign
|
||||||
}
|
}
|
||||||
@@ -6811,6 +6812,9 @@ func (a *App) ImportADIF(path string, dupMode string, applyCty bool, applyStatio
|
|||||||
_ = a.clublog.EnsureLoaded()
|
_ = a.clublog.EnsureLoaded()
|
||||||
}
|
}
|
||||||
clLoaded := a.clublog != nil && a.clublog.Loaded()
|
clLoaded := a.clublog != nil && a.clublog.Loaded()
|
||||||
|
// Counted rather than assumed: "did it fill the callsign?" is the first
|
||||||
|
// question after an import, and the log is where it gets answered.
|
||||||
|
stationStamped := 0
|
||||||
if applyCty || applyStation {
|
if applyCty || applyStation {
|
||||||
im.Enrich = func(q *qso.QSO) {
|
im.Enrich = func(q *qso.QSO) {
|
||||||
if applyCty {
|
if applyCty {
|
||||||
@@ -6822,9 +6826,23 @@ func (a *App) ImportADIF(path string, dupMode string, applyCty bool, applyStatio
|
|||||||
// Unconditional: see fillDistance.
|
// Unconditional: see fillDistance.
|
||||||
fillDistance(q)
|
fillDistance(q)
|
||||||
if applyStation {
|
if applyStation {
|
||||||
// Backfill empty MY_* descriptive fields from the active profile
|
// Backfill every empty station field from the active profile,
|
||||||
// (identity fields left alone to keep mixed-call routing intact).
|
// STATION_CALLSIGN included.
|
||||||
a.applyStationDefaults(q, false)
|
//
|
||||||
|
// It used to be the one field held back, on the grounds that
|
||||||
|
// stamping the active call could re-route a mixed-call log. That
|
||||||
|
// protected nothing: the same option already writes this profile's
|
||||||
|
// grid, rig, antenna and postal address onto every record it finds
|
||||||
|
// blank, so it has assumed "this log is mine" long before reaching
|
||||||
|
// the callsign — and a record that CARRIES a call is never touched,
|
||||||
|
// which is what actually keeps a multi-op log intact. Withholding it
|
||||||
|
// only meant the option quietly failed the one field an operator
|
||||||
|
// checks afterwards.
|
||||||
|
hadStation := strings.TrimSpace(q.StationCallsign) != ""
|
||||||
|
a.applyStationDefaults(q, true)
|
||||||
|
if !hadStation && strings.TrimSpace(q.StationCallsign) != "" {
|
||||||
|
stationStamped++
|
||||||
|
}
|
||||||
// Also stamp the default QSL/LoTW/eQSL confirmation statuses on
|
// Also stamp the default QSL/LoTW/eQSL confirmation statuses on
|
||||||
// any that are still empty (same defaults new QSOs get).
|
// any that are still empty (same defaults new QSOs get).
|
||||||
a.applyQSLDefaults(q)
|
a.applyQSLDefaults(q)
|
||||||
@@ -6835,6 +6853,9 @@ func (a *App) ImportADIF(path string, dupMode string, applyCty bool, applyStatio
|
|||||||
wruntime.EventsEmit(a.ctx, "import:progress", map[string]int{"processed": processed, "total": total})
|
wruntime.EventsEmit(a.ctx, "import:progress", map[string]int{"processed": processed, "total": total})
|
||||||
}
|
}
|
||||||
res, err := im.ImportFile(a.ctx, path)
|
res, err := im.ImportFile(a.ctx, path)
|
||||||
|
if stationStamped > 0 {
|
||||||
|
applog.Printf("import: STATION_CALLSIGN filled from the active profile on %d record(s) that carried none", stationStamped)
|
||||||
|
}
|
||||||
if err == nil && (res.Imported > 0 || res.Updated > 0) {
|
if err == nil && (res.Imported > 0 || res.Updated > 0) {
|
||||||
a.recomputeAwardRefsAsync() // materialise award_refs for the imported rows
|
a.recomputeAwardRefsAsync() // materialise award_refs for the imported rows
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -3,10 +3,12 @@
|
|||||||
"version": "0.26.0",
|
"version": "0.26.0",
|
||||||
"date": "",
|
"date": "",
|
||||||
"en": [
|
"en": [
|
||||||
"Club Log uploads are now identified as OpsLog. They were credited to another station's application key, which took the blame for them."
|
"Club Log uploads are now identified as OpsLog. They were credited to another station's application key, which took the blame for them.",
|
||||||
|
"ADIF import: \"fill my station fields\" now fills the station callsign too, on records that carry none."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Les envois Club Log s’identifient désormais comme OpsLog. Ils étaient attribués à la clé applicative d’une autre station, qui en portait la responsabilité."
|
"Les envois Club Log s’identifient désormais comme OpsLog. Ils étaient attribués à la clé applicative d’une autre station, qui en portait la responsabilité.",
|
||||||
|
"Import ADIF : « remplir mes champs station » renseigne aussi l’indicatif de station, sur les enregistrements qui n’en portent pas."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ const en: Dict = {
|
|||||||
'imp.ctyTitle': 'Fix country & zones (cty.dat + ClubLog)',
|
'imp.ctyTitle': 'Fix country & zones (cty.dat + ClubLog)',
|
||||||
'imp.ctyDesc': "Recompute Country, DXCC & CQ/ITU zones from cty.dat, overriding the file — corrects what contest software exports wrong (e.g. RG2Y as Asiatic instead of European Russia). ClubLog's DXpedition overrides are applied on top per QSO date (e.g. TO974REF → Reunion, TO2A 2012 → French Guiana) whenever the ClubLog data is downloaded. Everything else in the ADIF is kept as-is. Tip: use Update duplicates to re-fix QSOs already in your log.",
|
'imp.ctyDesc': "Recompute Country, DXCC & CQ/ITU zones from cty.dat, overriding the file — corrects what contest software exports wrong (e.g. RG2Y as Asiatic instead of European Russia). ClubLog's DXpedition overrides are applied on top per QSO date (e.g. TO974REF → Reunion, TO2A 2012 → French Guiana) whenever the ClubLog data is downloaded. Everything else in the ADIF is kept as-is. Tip: use Update duplicates to re-fix QSOs already in your log.",
|
||||||
'imp.stationTitle': 'Fill my station fields from my profile',
|
'imp.stationTitle': 'Fill my station fields from my profile',
|
||||||
'imp.stationDesc': "Backfill empty MY_* fields (my grid, rig, antenna, address, city, state, county, SOTA/POTA ref, TX power…) plus Operator and Owner callsign from your active profile. Existing values are kept. Only STATION_CALLSIGN is left untouched so a mixed-call log isn't re-routed. It ALSO stamps your default confirmation statuses (paper QSL, LoTW, eQSL, Club Log, HRDLog, QRZ.com sent and received) on the ones the file leaves empty — a WSJT-X log carries almost none. Enable when importing your own log.",
|
'imp.stationDesc': "Backfill empty MY_* fields (my grid, rig, antenna, address, city, state, county, SOTA/POTA ref, TX power…) plus Operator and Owner callsign from your active profile. Existing values are kept. Station callsign included, but only where the record carries none — one that names its own station keeps it, so a multi-op log is not re-routed. It ALSO stamps your default confirmation statuses (paper QSL, LoTW, eQSL, Club Log, HRDLog, QRZ.com sent and received) on the ones the file leaves empty — a WSJT-X log carries almost none. Enable when importing your own log.",
|
||||||
'imp.cancel': 'Cancel', 'rec.manualStart': 'Record this contact. Automatic recording is off, so capture starts now \u2014 there is no pre-roll of what came before.', 'rec.stop': 'Stop the recording. The audio is kept and still saved with the QSO \u2014 stop it to play it back to the station you are working.', 'rec.resume': 'Carry on recording, appending to what is already captured.', 'rec.playOnAir': 'TRANSMIT the recording to the station you are working: keys the radio and sends it like a voice-keyer message.', 'rec.stopPlaying': 'Stop transmitting the recording', 'rec.manualFailed': 'Recording could not be started \u2014 check the audio devices in Settings.', 'imp.mapAdd': 'The file puts a field in the wrong place\u2026', 'imp.mapTitle': 'Move fields on import', 'imp.mapDesc': 'Contest software stores the exchange where its own module keeps it. The RSGB IOTA contest exports the island reference in STATE \u2014 imported as-is it becomes a US state and the IOTA award stays empty. The destination is only filled where the file left it blank.', 'imp.mapMore': 'Add another', 'imp.import': 'Import',
|
'imp.cancel': 'Cancel', 'rec.manualStart': 'Record this contact. Automatic recording is off, so capture starts now \u2014 there is no pre-roll of what came before.', 'rec.stop': 'Stop the recording. The audio is kept and still saved with the QSO \u2014 stop it to play it back to the station you are working.', 'rec.resume': 'Carry on recording, appending to what is already captured.', 'rec.playOnAir': 'TRANSMIT the recording to the station you are working: keys the radio and sends it like a voice-keyer message.', 'rec.stopPlaying': 'Stop transmitting the recording', 'rec.manualFailed': 'Recording could not be started \u2014 check the audio devices in Settings.', 'imp.mapAdd': 'The file puts a field in the wrong place\u2026', 'imp.mapTitle': 'Move fields on import', 'imp.mapDesc': 'Contest software stores the exchange where its own module keeps it. The RSGB IOTA contest exports the island reference in STATE \u2014 imported as-is it becomes a US state and the IOTA award stays empty. The destination is only filled where the file left it blank.', 'imp.mapMore': 'Add another', 'imp.import': 'Import',
|
||||||
'imp.progressTitle': 'Importing ADIF…', 'bulk.progressTitle': 'Updating the selected QSOs\u2026',
|
'imp.progressTitle': 'Importing ADIF…', 'bulk.progressTitle': 'Updating the selected QSOs\u2026',
|
||||||
'imp.progressCount': '{done} / {tot} records · {pct}%', 'imp.progressCountOnly': '{done} records…',
|
'imp.progressCount': '{done} / {tot} records · {pct}%', 'imp.progressCountOnly': '{done} records…',
|
||||||
@@ -601,7 +601,7 @@ const fr: Dict = {
|
|||||||
'imp.ctyTitle': 'Corriger pays & zones (cty.dat + ClubLog)',
|
'imp.ctyTitle': 'Corriger pays & zones (cty.dat + ClubLog)',
|
||||||
'imp.ctyDesc': "Recalcule Pays, DXCC & zones CQ/ITU depuis cty.dat, en écrasant le fichier — corrige ce que les logiciels de contest exportent mal (ex. RG2Y en Russie asiatique au lieu d'européenne). Les exceptions DXpédition de ClubLog s'appliquent par-dessus selon la date du QSO (ex. TO974REF → Réunion, TO2A 2012 → Guyane française) dès que les données ClubLog sont téléchargées. Tout le reste de l'ADIF est conservé tel quel. Astuce : utilise Mettre à jour les doublons pour re-corriger des QSO déjà dans le log.",
|
'imp.ctyDesc': "Recalcule Pays, DXCC & zones CQ/ITU depuis cty.dat, en écrasant le fichier — corrige ce que les logiciels de contest exportent mal (ex. RG2Y en Russie asiatique au lieu d'européenne). Les exceptions DXpédition de ClubLog s'appliquent par-dessus selon la date du QSO (ex. TO974REF → Réunion, TO2A 2012 → Guyane française) dès que les données ClubLog sont téléchargées. Tout le reste de l'ADIF est conservé tel quel. Astuce : utilise Mettre à jour les doublons pour re-corriger des QSO déjà dans le log.",
|
||||||
'imp.stationTitle': 'Remplir mes champs station depuis mon profil',
|
'imp.stationTitle': 'Remplir mes champs station depuis mon profil',
|
||||||
'imp.stationDesc': "Complète les champs MY_* vides (locator, rig, antenne, adresse, ville, état, comté, réf. SOTA/POTA, puissance TX…) plus Opérateur et Indicatif propriétaire depuis le profil actif. Les valeurs existantes sont conservées. Seul STATION_CALLSIGN n'est jamais touché pour ne pas re-router un log multi-indicatifs. Elle applique AUSSI tes statuts de confirmation par défaut (QSL papier, LoTW, eQSL, Club Log, HRDLog, QRZ.com envoyé et reçu) sur ceux que le fichier laisse vides — un log WSJT-X n'en contient pratiquement aucun. À activer quand tu importes ton propre log.",
|
'imp.stationDesc': "Complète les champs MY_* vides (locator, rig, antenne, adresse, ville, état, comté, réf. SOTA/POTA, puissance TX…) plus Opérateur et Indicatif propriétaire depuis le profil actif. Les valeurs existantes sont conservées. Indicatif de station compris, mais uniquement là où l’enregistrement n’en porte aucun — celui qui nomme déjà sa station le conserve, donc un log multi-op n’est pas réorienté. Elle applique AUSSI tes statuts de confirmation par défaut (QSL papier, LoTW, eQSL, Club Log, HRDLog, QRZ.com envoyé et reçu) sur ceux que le fichier laisse vides — un log WSJT-X n'en contient pratiquement aucun. À activer quand tu importes ton propre log.",
|
||||||
'imp.cancel': 'Annuler', 'rec.manualStart': 'Enregistrer ce contact. L\u2019enregistrement automatique est d\u00e9sactiv\u00e9 : la capture commence maintenant, sans les secondes qui pr\u00e9c\u00e8dent.', 'rec.stop': 'Arr\u00eater l\u2019enregistrement. L\u2019audio est conserv\u00e9 et sera enregistr\u00e9 avec le QSO \u2014 arr\u00eatez-le pour le repasser \u00e0 la station travaill\u00e9e.', 'rec.resume': 'Reprendre l\u2019enregistrement, \u00e0 la suite de ce qui est d\u00e9j\u00e0 captur\u00e9.', 'rec.playOnAir': '\u00c9METTRE l\u2019enregistrement vers la station travaill\u00e9e : passe la radio en \u00e9mission et l\u2019envoie comme un message du manipulateur vocal.', 'rec.stopPlaying': 'Arrêter l’émission de l’enregistrement', 'rec.manualFailed': 'L\u2019enregistrement n\u2019a pas pu d\u00e9marrer \u2014 v\u00e9rifiez les p\u00e9riph\u00e9riques audio dans les R\u00e9glages.', 'imp.mapAdd': 'Le fichier met un champ au mauvais endroit\u2026', 'imp.mapTitle': 'D\u00e9placer des champs \u00e0 l\u2019import', 'imp.mapDesc': 'Les logiciels de concours rangent l\u2019\u00e9change l\u00e0 o\u00f9 leur module le garde. Le contest IOTA de la RSGB exporte la r\u00e9f\u00e9rence d\u2019\u00eele dans STATE \u2014 import\u00e9e telle quelle elle devient un \u00e9tat am\u00e9ricain et le dipl\u00f4me IOTA reste vide. La destination n\u2019est remplie que l\u00e0 o\u00f9 le fichier l\u2019a laiss\u00e9e vide.', 'imp.mapMore': 'Ajouter une ligne', 'imp.import': 'Importer',
|
'imp.cancel': 'Annuler', 'rec.manualStart': 'Enregistrer ce contact. L\u2019enregistrement automatique est d\u00e9sactiv\u00e9 : la capture commence maintenant, sans les secondes qui pr\u00e9c\u00e8dent.', 'rec.stop': 'Arr\u00eater l\u2019enregistrement. L\u2019audio est conserv\u00e9 et sera enregistr\u00e9 avec le QSO \u2014 arr\u00eatez-le pour le repasser \u00e0 la station travaill\u00e9e.', 'rec.resume': 'Reprendre l\u2019enregistrement, \u00e0 la suite de ce qui est d\u00e9j\u00e0 captur\u00e9.', 'rec.playOnAir': '\u00c9METTRE l\u2019enregistrement vers la station travaill\u00e9e : passe la radio en \u00e9mission et l\u2019envoie comme un message du manipulateur vocal.', 'rec.stopPlaying': 'Arrêter l’émission de l’enregistrement', 'rec.manualFailed': 'L\u2019enregistrement n\u2019a pas pu d\u00e9marrer \u2014 v\u00e9rifiez les p\u00e9riph\u00e9riques audio dans les R\u00e9glages.', 'imp.mapAdd': 'Le fichier met un champ au mauvais endroit\u2026', 'imp.mapTitle': 'D\u00e9placer des champs \u00e0 l\u2019import', 'imp.mapDesc': 'Les logiciels de concours rangent l\u2019\u00e9change l\u00e0 o\u00f9 leur module le garde. Le contest IOTA de la RSGB exporte la r\u00e9f\u00e9rence d\u2019\u00eele dans STATE \u2014 import\u00e9e telle quelle elle devient un \u00e9tat am\u00e9ricain et le dipl\u00f4me IOTA reste vide. La destination n\u2019est remplie que l\u00e0 o\u00f9 le fichier l\u2019a laiss\u00e9e vide.', 'imp.mapMore': 'Ajouter une ligne', 'imp.import': 'Importer',
|
||||||
'imp.progressTitle': 'Import ADIF en cours…', 'bulk.progressTitle': 'Mise \u00e0 jour des QSO s\u00e9lectionn\u00e9s\u2026',
|
'imp.progressTitle': 'Import ADIF en cours…', 'bulk.progressTitle': 'Mise \u00e0 jour des QSO s\u00e9lectionn\u00e9s\u2026',
|
||||||
'imp.progressCount': '{done} / {tot} enregistrements · {pct}%', 'imp.progressCountOnly': '{done} enregistrements…',
|
'imp.progressCount': '{done} / {tot} enregistrements · {pct}%', 'imp.progressCountOnly': '{done} enregistrements…',
|
||||||
|
|||||||
Reference in New Issue
Block a user