diff --git a/core/app/app.go b/core/app/app.go index d7508bd..1be6be1 100644 --- a/core/app/app.go +++ b/core/app/app.go @@ -133,20 +133,22 @@ func (c *Controller) Startup() { c.session = session.NewDefaultSession() } + c.ServiceStatus = newServiceStatus(c.asyncRunner) + + c.callHistoryFinder = callhistory.New(c.ServiceStatus.StatusChanged) c.Settings = settings.New( c.OpenConfigurationFile, c.openWithExternalApplication, + c.callHistoryFinder, c.configuration.Station(), c.configuration.Contest(), ) + c.callHistoryFinder.Notify(c.Settings) c.NewContest = newcontest.NewController(c.Settings, c.configuration.LogDirectory()) - c.ServiceStatus = newServiceStatus(c.asyncRunner) - c.bandplan = bandplan.IARURegion1 // TODO: make the bandplan configurable c.dxccFinder = dxcc.New() c.scpFinder = scp.New() - c.callHistoryFinder = callhistory.New(c.Settings, c.ServiceStatus.StatusChanged) c.hamDXMap = hamdxmap.NewHamDXMap(c.configuration.HamDXMapPort()) c.Score = score.NewCounter(c.Settings, c.dxccFinder) diff --git a/core/callhistory/callhistory.go b/core/callhistory/callhistory.go index ba058d4..b08fd22 100644 --- a/core/callhistory/callhistory.go +++ b/core/callhistory/callhistory.go @@ -21,58 +21,84 @@ const ( Exch1Field = "Exch1" ) -func New(settings core.Settings, callback AvailabilityCallback) *Finder { - result := &Finder{ - callback: callback, - filename: settings.Contest().CallHistoryFilename, - fieldNames: settings.Contest().CallHistoryFieldNames, +func New(availabilityCallback AvailabilityCallback) *Finder { + return &Finder{ + availabilityCallback: availabilityCallback, } - - result.database = loadCallHistory(result.filename) - result.cache = make(map[string][]scp.Match) - result.callback(core.CallHistoryService, result.Available()) - if result.Available() { - log.Printf("Using call history from %s", result.filename) - } - - return result } type Finder struct { - database *scp.Database - cache map[string][]scp.Match - callback AvailabilityCallback + database *scp.Database + cache map[string][]scp.Match + availabilityCallback AvailabilityCallback + + listeners []any filename string fieldNames []string } +type Settings interface { + core.Settings +} + type AvailabilityCallback func(service core.Service, available bool) +type AvailableFieldNamesListener interface { + SetAvailableCallHistoryFieldNames(fieldNames []string) +} + +func (f *Finder) Notify(listener any) { + f.listeners = append(f.listeners, listener) +} + func (f *Finder) Available() bool { return f.database != nil } -func (f *Finder) ContestChanged(contest core.Contest) { - if contest.CallHistoryFilename == f.filename { +func (f *Finder) Activate(filename string) { + if f.filename == filename { return } + f.filename = filename + f.activateCallHistory() +} - f.filename = contest.CallHistoryFilename - f.fieldNames = contest.CallHistoryFieldNames +func (f *Finder) Deactivate() { + f.filename = "" + clear(f.fieldNames) +} +func (f *Finder) activateCallHistory() { f.database = loadCallHistory(f.filename) f.cache = make(map[string][]scp.Match) - f.callback(core.CallHistoryService, f.Available()) + f.availabilityCallback(core.CallHistoryService, f.Available()) if f.Available() { - log.Printf("Using call history from %s", f.filename) + log.Printf("Using call history from %s with available field names %v", f.filename, f.database.FieldSet().UsableNames()) + f.emitAvailableCallHistoryFieldNames(toFieldNames(f.database.FieldSet().UsableNames())) + } else { + log.Printf("No call history available from %s", f.filename) + f.emitAvailableCallHistoryFieldNames([]string{}) + } +} + +func (f *Finder) emitAvailableCallHistoryFieldNames(fieldNames []string) { + for _, listener := range f.listeners { + if stationListener, ok := listener.(AvailableFieldNamesListener); ok { + stationListener.SetAvailableCallHistoryFieldNames(fieldNames) + } } } +func (f *Finder) SelectFieldNames(fieldNames []string) { + f.fieldNames = fieldNames +} + func (f *Finder) FindEntry(s string) (core.AnnotatedCallsign, bool) { if !f.Available() { return core.AnnotatedCallsign{}, false } + searchCallsign, err := callsign.Parse(s) if err != nil { log.Print(err) @@ -177,6 +203,14 @@ func toMatchingAssembly(match scp.Match) core.MatchingAssembly { return result } +func toFieldNames(fieldSet scp.FieldSet) []string { + result := make([]string, len(fieldSet)) + for i, fieldName := range fieldSet { + result[i] = string(fieldName) + } + return result +} + func loadCallHistory(filename string) *scp.Database { file, err := os.Open(filename) if err != nil { diff --git a/core/settings/settings.go b/core/settings/settings.go index ab70512..26bc7ef 100644 --- a/core/settings/settings.go +++ b/core/settings/settings.go @@ -69,6 +69,12 @@ type ConfigurationFileOpener func() type BrowserOpener func(string) +type CallHistory interface { + Activate(filename string) + Deactivate() + SelectFieldNames(fieldNames []string) +} + type XchangeRegexpMatcher func(*regexp.Regexp, string) (string, bool) type View interface { @@ -101,12 +107,13 @@ type View interface { SetMultisGoal(string) } -func New(configurationFileOpener ConfigurationFileOpener, browserOpener BrowserOpener, station core.Station, contest core.Contest) *Settings { +func New(configurationFileOpener ConfigurationFileOpener, browserOpener BrowserOpener, callHistory CallHistory, station core.Station, contest core.Contest) *Settings { result := &Settings{ writer: new(nullWriter), view: new(nullView), configurationFileOpener: configurationFileOpener, browserOpener: browserOpener, + callHistory: callHistory, station: station, contest: contest, defaultStation: station, @@ -128,6 +135,7 @@ type Settings struct { view View configurationFileOpener ConfigurationFileOpener browserOpener BrowserOpener + callHistory CallHistory reportFieldIndex int serialExchangeFieldIndex int availableCallHistoryFieldNames []string @@ -161,6 +169,12 @@ func (s *Settings) SetView(view View) { s.showSettings() } +func (s *Settings) SetAvailableCallHistoryFieldNames(fieldNames []string) { + s.availableCallHistoryFieldNames = fieldNames + + s.updateExchangeFields() +} + func (s *Settings) Notify(listener interface{}) { s.listeners = append(s.listeners, listener) @@ -197,6 +211,8 @@ func (s *Settings) SetContest(contest core.Contest) { s.contest = contest s.savedContest = deepCopyContest(contest) s.contest.UpdateExchangeFields() + s.callHistory.Activate(s.contest.CallHistoryFilename) + s.callHistory.SelectFieldNames(s.contest.CallHistoryFieldNames) s.emitContestChanged() } @@ -532,7 +548,8 @@ func (s *Settings) OpenCallHistoryArchivePage() { func (s *Settings) ClearCallHistory() { s.contest.CallHistoryFilename = "" - s.contest.CallHistoryFieldNames = make([]string, len(s.contest.ExchangeValues)) + clear(s.contest.CallHistoryFieldNames) + s.callHistory.Deactivate() s.view.SetContestCallHistoryFile(s.contest.CallHistoryFilename) for i := range s.contest.CallHistoryFieldNames { @@ -627,6 +644,7 @@ func (s *Settings) SetOperationModeSprint(value bool) { func (s *Settings) EnterContestCallHistoryFile(value string) { s.contest.CallHistoryFilename = value + s.callHistory.Activate(s.contest.CallHistoryFilename) } func (s *Settings) EnterContestCallHistoryFieldName(field core.EntryField, value string) { @@ -637,6 +655,7 @@ func (s *Settings) EnterContestCallHistoryFieldName(field core.EntryField, value } s.contest.CallHistoryFieldNames[i] = value + s.callHistory.SelectFieldNames(s.contest.CallHistoryFieldNames) } func (s *Settings) EnterQSOsGoal(value string) { diff --git a/go.mod b/go.mod index 484286b..2f5b9f8 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/ftl/conval v0.7.7 github.com/ftl/gmtry v0.0.0-20201120192810-fa4a1b99fc04 github.com/ftl/godxmap v1.0.0 - github.com/ftl/hamradio v0.2.10 + github.com/ftl/hamradio v0.2.11 github.com/ftl/rigproxy v0.2.6 github.com/ftl/tci v0.3.2 github.com/golang/protobuf v1.5.2 diff --git a/go.sum b/go.sum index cb113b1..7bb2ac7 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/ftl/gmtry v0.0.0-20201120192810-fa4a1b99fc04 h1:S7z3LXqDYk4avXKj+B2or github.com/ftl/gmtry v0.0.0-20201120192810-fa4a1b99fc04/go.mod h1:AQpbHYBSPV1Bc1nqG8vv8BK3qxXMZIn32OQBi/4A7Sc= github.com/ftl/godxmap v1.0.0 h1:5T1SYRtTd49AoISdFGvvRWcqJ9kFA1fzdx6yWJT54zM= github.com/ftl/godxmap v1.0.0/go.mod h1:Cl5gtnJFMPtVktcghGTaGeVSFQ1tlZFzkI3p/LylrdI= -github.com/ftl/hamradio v0.2.10 h1:3PpmNpYPkap4z6sbYJjXpL++ZOV4/Xu6aUYlcbclj1w= -github.com/ftl/hamradio v0.2.10/go.mod h1:BvA+ni3sOKmrIJpLt6f2sYK9vc3VfihZm4x0h8kzOPw= +github.com/ftl/hamradio v0.2.11 h1:pUll2s4mW+XgxeXhDtrQxKSUjILvNMd1rbV1r3osdZY= +github.com/ftl/hamradio v0.2.11/go.mod h1:BvA+ni3sOKmrIJpLt6f2sYK9vc3VfihZm4x0h8kzOPw= github.com/ftl/localcopy v0.0.0-20190616142648-8915fb81f0d9 h1:ORI3EUKpLTsfA372C6xpuZFDXw+ckmCzLaCcJvakG24= github.com/ftl/localcopy v0.0.0-20190616142648-8915fb81f0d9/go.mod h1:4sZLCxjgn++exy5u0muVzlvnahfanPuiHLQo0GJQnPA= github.com/ftl/rigproxy v0.2.6 h1:umsoOET+VWpWc3jSXz+FoZq5zwuodrigiOiwZyafr3o=