diff --git a/app.go b/app.go index f5847d4..7cb9f9a 100644 --- a/app.go +++ b/app.go @@ -3712,7 +3712,7 @@ type CabrilloResult struct { } // cabrilloHeader fills the Cabrillo header from the active profile (callsign, -// operator, grid) plus the contest name the user supplied. +// operator, grid) plus the contest name (taken from the QSOs' ADIF CONTEST_ID). func (a *App) cabrilloHeader(contest string) cabrillo.Header { h := cabrillo.Header{Contest: contest} if a.profiles != nil { @@ -3727,8 +3727,9 @@ func (a *App) cabrilloHeader(contest string) cabrillo.Header { } // writeCabrillo collects the QSOs via the given iterator and writes a Cabrillo -// document to path. -func (a *App) writeCabrillo(path, contest string, iterate func(func(qso.QSO) error) error) (CabrilloResult, error) { +// document to path. The contest name is taken from the QSOs' ADIF CONTEST_ID +// (the most common one), so no separate prompt is needed. +func (a *App) writeCabrillo(path string, iterate func(func(qso.QSO) error) error) (CabrilloResult, error) { if a.qso == nil { return CabrilloResult{}, fmt.Errorf("db not initialized") } @@ -3736,9 +3737,24 @@ func (a *App) writeCabrillo(path, contest string, iterate func(func(qso.QSO) err return CabrilloResult{}, fmt.Errorf("empty path") } var qsos []qso.QSO - if err := iterate(func(q qso.QSO) error { qsos = append(qsos, q); return nil }); err != nil { + contests := map[string]int{} + if err := iterate(func(q qso.QSO) error { + qsos = append(qsos, q) + if c := strings.TrimSpace(q.ContestID); c != "" { + contests[c]++ + } + return nil + }); err != nil { return CabrilloResult{}, err } + // Pick the most-used CONTEST_ID across the exported QSOs. + contest := "" + best := 0 + for c, n := range contests { + if n > best { + contest, best = c, n + } + } f, err := os.Create(path) if err != nil { return CabrilloResult{}, err @@ -3752,31 +3768,31 @@ func (a *App) writeCabrillo(path, contest string, iterate func(func(qso.QSO) err } // ExportCabrillo writes every QSO to a Cabrillo file. -func (a *App) ExportCabrillo(path, contest string) (CabrilloResult, error) { - return a.writeCabrillo(path, contest, func(fn func(qso.QSO) error) error { return a.qso.IterateAll(a.ctx, fn) }) +func (a *App) ExportCabrillo(path string) (CabrilloResult, error) { + return a.writeCabrillo(path, func(fn func(qso.QSO) error) error { return a.qso.IterateAll(a.ctx, fn) }) } // ExportCabrilloFiltered writes the QSOs matching the current filter. -func (a *App) ExportCabrilloFiltered(path, contest string, f qso.QueryFilter) (CabrilloResult, error) { - return a.writeCabrillo(path, contest, func(fn func(qso.QSO) error) error { return a.qso.IterateFiltered(a.ctx, f, fn) }) +func (a *App) ExportCabrilloFiltered(path string, f qso.QueryFilter) (CabrilloResult, error) { + return a.writeCabrillo(path, func(fn func(qso.QSO) error) error { return a.qso.IterateFiltered(a.ctx, f, fn) }) } // ExportCabrilloSelected writes only the highlighted QSOs. -func (a *App) ExportCabrilloSelected(path, contest string, ids []int64) (CabrilloResult, error) { +func (a *App) ExportCabrilloSelected(path string, ids []int64) (CabrilloResult, error) { if len(ids) == 0 { return CabrilloResult{}, fmt.Errorf("no QSOs selected") } - return a.writeCabrillo(path, contest, func(fn func(qso.QSO) error) error { return a.qso.IterateByIDs(a.ctx, ids, fn) }) + return a.writeCabrillo(path, func(fn func(qso.QSO) error) error { return a.qso.IterateByIDs(a.ctx, ids, fn) }) } -// SaveCabrilloFile opens a save dialog for a Cabrillo (.cbr / .log) file. +// SaveCabrilloFile opens a save dialog for a Cabrillo (.log) file. func (a *App) SaveCabrilloFile() (string, error) { - suggested := "OpsLog_" + time.Now().UTC().Format("20060102_150405") + ".cbr" + suggested := "OpsLog_" + time.Now().UTC().Format("20060102_150405") + ".log" return wruntime.SaveFileDialog(a.ctx, wruntime.SaveDialogOptions{ Title: "Export Cabrillo", DefaultFilename: suggested, Filters: []wruntime.FileFilter{ - {DisplayName: "Cabrillo files (*.cbr, *.log)", Pattern: "*.cbr;*.log"}, + {DisplayName: "Cabrillo log (*.log, *.cbr)", Pattern: "*.log;*.cbr"}, {DisplayName: "All files (*.*)", Pattern: "*.*"}, }, }) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d2e0947..8ecdebf 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1981,37 +1981,31 @@ export default function App() { showToast(`Exported ${r.count} selected QSO${r.count > 1 ? 's' : ''} → ${r.path}`); } catch (e: any) { setError(String(e?.message ?? e)); } } - // Cabrillo (contest log) export — prompts for the contest name, then writes a - // .cbr file. All / filtered / selected variants mirror the ADIF ones. + // Cabrillo (contest log) export → a .log file. The contest name comes from the + // QSOs' ADIF CONTEST_ID (no prompt). All / filtered / selected mirror the ADIF ones. async function exportCabrillo() { - const contest = window.prompt('Contest name for Cabrillo (e.g. CQ-WW-SSB):', ''); - if (contest === null) return; try { const path = await SaveCabrilloFile(); if (!path) return; - const r = await ExportCabrillo(path, contest); + const r = await ExportCabrillo(path); showToast(`Cabrillo: ${r.count} QSO${r.count > 1 ? 's' : ''} → ${r.path}`); } catch (e: any) { setError(String(e?.message ?? e)); } } async function exportFilteredCabrillo() { - const contest = window.prompt('Contest name for Cabrillo (e.g. CQ-WW-SSB):', ''); - if (contest === null) return; try { const path = await SaveCabrilloFile(); if (!path) return; const f = buildActiveFilter(); - const r = await ExportCabrilloFiltered(path, contest, { ...f, limit: 0, offset: 0 } as any); + const r = await ExportCabrilloFiltered(path, { ...f, limit: 0, offset: 0 } as any); showToast(`Cabrillo: ${r.count} QSO${r.count > 1 ? 's' : ''} → ${r.path}`); } catch (e: any) { setError(String(e?.message ?? e)); } } async function exportSelectedCabrillo(ids: number[]) { if (ids.length === 0) return; - const contest = window.prompt('Contest name for Cabrillo (e.g. CQ-WW-SSB):', ''); - if (contest === null) return; try { const path = await SaveCabrilloFile(); if (!path) return; - const r = await ExportCabrilloSelected(path, contest, ids as any); + const r = await ExportCabrilloSelected(path, ids as any); showToast(`Cabrillo: ${r.count} selected QSO${r.count > 1 ? 's' : ''} → ${r.path}`); } catch (e: any) { setError(String(e?.message ?? e)); } } diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index 5f00f58..43147d9 100644 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -131,11 +131,11 @@ export function ExportADIFSelected(arg1:string,arg2:boolean,arg3:Array): export function ExportAwards():Promise; -export function ExportCabrillo(arg1:string,arg2:string):Promise; +export function ExportCabrillo(arg1:string):Promise; -export function ExportCabrilloFiltered(arg1:string,arg2:string,arg3:qso.QueryFilter):Promise; +export function ExportCabrilloFiltered(arg1:string,arg2:qso.QueryFilter):Promise; -export function ExportCabrilloSelected(arg1:string,arg2:string,arg3:Array):Promise; +export function ExportCabrilloSelected(arg1:string,arg2:Array):Promise; export function FilterFields():Promise>; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index 9533836..5a5460a 100644 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -226,16 +226,16 @@ export function ExportAwards() { return window['go']['main']['App']['ExportAwards'](); } -export function ExportCabrillo(arg1, arg2) { - return window['go']['main']['App']['ExportCabrillo'](arg1, arg2); +export function ExportCabrillo(arg1) { + return window['go']['main']['App']['ExportCabrillo'](arg1); } -export function ExportCabrilloFiltered(arg1, arg2, arg3) { - return window['go']['main']['App']['ExportCabrilloFiltered'](arg1, arg2, arg3); +export function ExportCabrilloFiltered(arg1, arg2) { + return window['go']['main']['App']['ExportCabrilloFiltered'](arg1, arg2); } -export function ExportCabrilloSelected(arg1, arg2, arg3) { - return window['go']['main']['App']['ExportCabrilloSelected'](arg1, arg2, arg3); +export function ExportCabrilloSelected(arg1, arg2) { + return window['go']['main']['App']['ExportCabrilloSelected'](arg1, arg2); } export function FilterFields() {