Files
kst4contest/github_docs/en-Changelog.md
T
Rsclub2_2andClaude Opus 5.5 2a5c89b943 Next major release/version1.50 (#89)
* Make DBController work on one database file per instance

The controller was a static singleton: an eagerly created static instance
opened the root database during class initialization, and both the connection
and the path were static fields. A second operator profile in the same process
was therefore impossible, and ChatController's own "new DBController()" never
opened anything - it silently adopted the eagerly opened root connection.

- drop the eager static instance in favour of a lazily created default instance
- turn connection and path into instance state
- add a constructor taking a database file name relative to the application
  directory plus a flag whether a missing file is seeded from the bundled
  template
- create additional profile databases empty instead of seeding them: the
  bundled template carries 3452 foreign callsigns and user_version 0, which
  would show a new operator foreign data and trigger the full callsign
  normalization rebuild. The schema is created by the existing table setup.
- remember the shutdown hook so closeDBConnection can deregister it; otherwise
  every profile switch would leave another hook holding a dead connection

All SQL statements keep referencing the plain field and are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Allow preferences and chat controller to be bound to a file set

ChatPreferences gains a constructor taking a preferences file name relative to
the application directory, so "profiles/OP2/preferences.xml" is as valid as the
historic flat "preferences.xml". A missing file is still seeded from the
bundled template, which gives an additional operator the same clean defaults a
first installation gets.

ChatController gains a constructor that passes both relative file names and the
seed flag through to ChatPreferences and DBController. The existing
constructors delegate to the historic file names, so nothing changes yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Introduce the operator profile model and its registry

Adds the descriptor, the path derivation and the registry persistence for
operator profiles. Nothing calls them yet, so behaviour is unchanged.

The descriptor stores only a shared/own flag, never a path. All file names are
derived in OperatorProfilePaths, so a stored path can never drift apart from
the flag that produced it. A profile identifier is a stable, file system safe
slug assigned once, so renaming a profile never moves a directory.

The registry is created lazily. An installation that only has the historic flat
layout gets no registry file and no profiles directory; the root profile is
synthesised in memory instead. That keeps a single operator installation
byte for byte the one it was before, and it keeps a downgrade to an older
release a no-op. A missing, unreadable or malformed registry is logged and
treated like an installation without additional profiles, never as an error.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Select the operator profile at startup

Resolves the active operator profile before the chat controller is built and
passes its two file names on, so preferences, layout and worked data follow the
profile.

The resolution is deliberately quiet for existing installations. With no
registry or exactly one profile nothing is asked and nothing is written, so a
single operator start is unchanged. Only from two profiles on does a small
picker appear with the last used profile preselected, where Enter or a double
click starts immediately. A "--profile" argument, or the equivalent system
property, skips the picker; an unknown name warns and falls back to the normal
selection instead of refusing to start.

The startup decision itself lives in OperatorProfileBootstrap and contains no
user interface code, so it is covered by headless tests. The window title gains
the profile name only when a second profile exists.

Command line parsing happens in init() and is kept in a process wide holder,
because JavaFX only knows the parameters of the instance it launched itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Release the background resources a discarded runtime owns

Several resources outlived a disconnect on purpose, which was harmless while a
process ran exactly one session for its whole life. They are now released when
the controller itself is closed:

- the ON4KST connection supervisor thread, which stopByUser did not touch
- the sked reminder scheduler, which had no shutdown at all
- the reachability executor, whose shutdown method existed but was never called
- the PSTRotator retry scheduler and its pending retry
- the map tile proxy, whose stop method existed but was never called, leaving a
  server socket and a twelve thread pool behind
- the station map bridge listeners and its coalescing animation, which would
  otherwise keep firing into a dead user interface

These are real leaks today; they only become visible when a second runtime is
built in the same process.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Switch the operator profile while the application is running

Splits the teardown out of stop() into a reusable, idempotent shutdownRuntime()
and adds File - Switch operator profile..., which tears the current runtime
down and builds a fresh one for the selected profile.

The new runtime is a new application instance rather than a second start() on
the existing one. Many controls are instance fields created once, so reusing
the instance would re-parent mounted nodes and register every listener twice.
A fresh instance is safe because the class keeps no mutable static state.

Closing every window during a switch would end the process under the JavaFX
default, so the application takes over the exit decision: implicit exit is
turned off, the main window gets an explicit close handler, and every exit path
runs through the launcher. That also fixes losing the window layout on exit
after a switch, because JavaFX only calls stop() on the instance it launched.

The two view timers are now cancelled null-safe; stop() used to dereference
them unguarded, which would fail if shutdown happened before they were created.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Manage operator profiles from the settings window

Adds a "Profiles" tab, appended last so no established tab position shifts,
offering create, duplicate, rename, delete, a switch between shared and own
worked stations, and activation of another profile.

Duplicating copies the whole configuration except callsign and password. The
antenna, locator, layout and integration settings are exactly the work nobody
wants to enter twice, while the credentials belong to one operator only. The
root profile can neither be deleted nor moved off the common station database,
because its files are the installation itself.

The login callsign and its raw form now default to empty instead of a real
callsign. The XML reader treats an empty element as "not set" and falls back to
the field default, so without this change a profile created without credentials
would come up carrying the callsign compiled into the defaults - and an
operator could transmit under someone else's call.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Document operator profiles

Adds a manual section in both languages covering where profile files live, the
choice between shared and own worked stations, managing profiles, the startup
selection and the --profile argument, switching while running, and the fact
that passwords stay in clear text so profiles are not an access boundary.

Records the architecture in PROJECT_CONTEXT: lazy registry, derived paths, why
an additional profile database is created empty, why the login callsign default
is empty, and the constraints of rebuilding the runtime for a switch.

Adds a v1.50 changelog entry in both languages including the upgrade notes: no
file is moved, and going back to an older release stays possible.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Make the terrain profile cache multi operator safe

The cache stored a single owner identity in a meta table and dropped the whole
TerrainProfileCache table whenever the configured callsign or locator differed
from it. With several operator profiles that turns the cache into a permanent
miss: every switch between two operators with different locators would discard
every computed profile.

Entries are separated by owner identity through the primary key already, so the
wipe is replaced by an owner table that simply records which identities are in
use. A different owner now misses the cache instead of clearing everybody's.

The cache also moves out of the worked station database into its own global
terrainprofilecache.db. Terrain profiles are pure geometry derived from two
locators and a sample count; at a multi operator station both operators share
one location, so a per profile copy would only double the traffic against the
terrain service. No migration is needed, the new file refills itself, and the
old tables stay readable for older releases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Fail cleanly when the registry path has no directory

SpotBugs flagged a null passed to Files.createTempFile: the null check guarded
only createDirectories, while the temporary file creation would still have
dereferenced it. The path is resolved absolute so this is practically
unreachable, but bailing out with a log line is cheaper than the latent NPE.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm

* Code Version 1.50

* Add the in-app update concept for 1.50

Captures the agreed design so it can be handed over later: extended
update feed with per-artifact metadata, a build-time package-type
marker, a testable check service replacing the blocking call in the
ChatController constructor, a non-modal hint suppressed while connected
to ON4KST, verified downloads and platform-specific execution.

Concept only, nothing implemented yet. Line anchors were verified
against this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HT8R7zTMoQnmJj6dGbaqqf

* Use one base font size and a per-profile startup design

JavaFX picks a 13px default font on macOS and Linux but 12px on
Windows, so labels in fixed-size controls were cut off outside
Windows. Both stylesheets now set 12px on the root.

Each operator profile now chooses light or dark mode for startup on
the GUI settings tab. The Windows menu entries remain a quick switch
for the running session. All windows, including the update window
and the top candidates list, follow the design, and the main window
no longer starts light while the station map starts dark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Show a drag-to-install layout in the macOS DMG

The DMG window now has a background with an arrow from the app to
the Applications folder, in the KST4Contest colours. Finder applies
the layout through AppleScript; if that fails, e.g. on a headless
runner, the script warns and builds the plain DMG as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Use the macOS system menu bar in all windows

On macOS the main menus move into the system menu bar and are shared
with the secondary windows, so they stay available whichever window
has the focus. The connection state indicator becomes a read-only
LINK menu there instead of the status bar button. Other platforms
are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* List direct commits on main in the release notes

GitHub's generated release notes only cover merged pull requests, so
commits pushed straight to main were missing. The release job now
builds the notes itself: "What's Changed" holds "Commits on main"
(first-parent, without bot and squash-merge commits) and GitHub's PR
list as "Merged PRs".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Build with Gradle in two modules, and free core of JavaFX

Etappen 1 and 2 of the Compose migration (43 commits).

The Maven build, the single source tree and the JPMS module-info went together.
core now holds the domain and app-desktop the user interface, both built by
Gradle, packaged through jpackage from Gradle, with SpotBugs and PMD wired in.
JavaFX moves to the classpath, which is why the launcher is Main and not the
Application subclass. The PR check, the nightly artifacts, the release and the
AUR packages all build from Gradle; the macOS DMG points at its output.
Verified on Linux, macOS and Windows.

core then loses JavaFX entirely. It observes through kst4contest.observe --
ObservableValue, ObservableRoster, and UiDispatcher as the one boundary a
worker thread crosses to touch the interface. The controller collections become
rosters and the visible station list a pure derivation rather than a
FilteredList/SortedList chain, which is also what fixed two focus defects only
a load test had exposed: the keyboard focus stays where the operator put it,
and the send field keeps it after a row click.

The rule that outlives this commit: ObservableRoster is the store and the list
a view is bound to is a mirror of it, never the other way round.

* Draw the whole interface in Compose

Etappen 3 to 6a of the migration (129 commits). Every window the operator sees
is Compose; the JavaFX ones still exist beside them so the two could be
compared against a live session, which is the only way the differences came to
light.

The toolchain first, then the settings window with its eleven tabs and 72 real
preferences; then the multi-column table as a component, and with it the rules
it needs -- stable row identity, a selection that survives a refresh, column
order the operator can drag, and a repaint when the rows change rather than
when the list instance does. Then the update and monitor windows, and the main
window: 22 station columns, the filter bar, the selected-station panel, the
message tabs, the priority bar, the sked controls, the status indicators and
the timeline, assembled behind a splitter because Compose has none.

The map stops being a WebView. A Compose canvas projects WebMercator tiles
itself, with the clustering in core and an asynchronous fetcher in place of the
local tile proxy; derive() becomes a pure Kotlin reimplementation instead of a
reflection call into com.sun.javafx.

Most of the volume here is parity the operator would notice rather than new
behaviour: desktop density instead of Material's phone minimums, colours taken
from the JavaFX stylesheets instead of Material's palette, row dividers, band
columns, grid-square labels and their colours, the home marker and antenna
beam, pinch-to-zoom under Wayland, and layouts that survive a window narrower
than the chart they stack.

Two lessons are worth more than the diff. A control bound to a value Compose
cannot observe writes through and never redraws -- that one shipped repeatedly
with a green build, because no test drew anything. And a layout that clips
instead of wrapping is worse than one that is merely too narrow: half a word
is the worst available outcome.

* Remove JavaFX

The second half of Etappe 6 (61 commits). grep -rl "javafx\." over both main
source trees is empty, nothing imports javafx, neither classpath resolves it,
and org.openjfx is out of the build and the version catalog.

The finding that shaped the work: the JavaFX main window was built on every
start and never shown -- primaryStage's setScene and show were both commented
out. Most of those 11,655 lines were dead weight rather than a port. But not
all of them, and that is the trap this commit is really about: dead-looking
methods still fed live Compose sinks. They were cut at their seams instead of
deleted, and a sweep script that follows calls was written to find them,
because reading the code does not reveal them.

In order: the colour derivation frozen as checked-in test data, so the pin
survives JavaFX being removed instead of silently comparing against itself;
the live feeds lifted out of the never-shown window and given names and tests;
the dead scaffolding deleted in slices; then the lifecycle. UiDispatcher now
delivers to the AWT event dispatch thread, the ten Alerts are modal Compose
dialogs, HostServices gives way to java.awt.Desktop with the mailto/http split
JavaFX did not need, and extends Application, start(Stage), stop and launch are
gone -- main builds the runtime and a shutdown hook replaces stop().

An independent review found two deadlocks in that move, both the same failure
class, both invisible to the build: a blocking wait on the event thread for
work that can only advance on the event thread. The profile picker waited on a
latch and froze the client for good; ComposeWindowHost.close waited on
Thread.join and returned with the window still marked open, which made a
profile switch raise the dead runtime's window and leave the rebuilt profile
without its Connect button. A third came out of fixing them: a ComposeDialog
built off the event thread cannot create its GL context and never paints.

Three defects only a GUI run showed, never the build: an NPE on a deleted
field, a Compose menu still hanging on deleted MenuItems, and a category
bookkeeping field that looked dead but is read by the outgoing-message category
resolution -- deleting it would have sent messages in the wrong category.

The binding docs and the manual no longer describe a JavaFX client.

* Draw the menu bar in Compose, and give the drawing layer a net

What the removal left open (4 commits).

Compose's MenuBar is a javax.swing.JMenuBar set on the window, so Swing draws
it and no theme reaches it; with no look-and-feel configured that meant the
default Metal menu above a themed window. The bar is drawn in the window now,
except on macOS, where the system bar is where that platform expects it. Two
renderers read one description -- mainMenuModel is a plain function of the
state, which also gives the menus their first tests. Closing the main window
quits the application again, and the window writes its size back to the
profile; both had quietly stopped working when the last JavaFX stage went.

Then Etappe 7. Four faults shipped in the settings-window branch alongside a
green suite of 382 tests, because not one of those tests drew anything: a
control that never redrew, a tab strip that clipped mid-word, a form taller
than its window with no way down, and colours that came from Material rather
than the stylesheet. One regression test per class, and the spec's acceptance
criterion is met rather than assumed -- each fault was put back deliberately
and the matching test watched to fail.

The CI had never run the suite at all; it does now, headless. What that took
was not Xvfb: skiko's native library links against libGL and only has to be
loadable, since the drawing tests render in software. Without the package the
whole Compose half of the suite dies with a message that reads like a missing
display. Found by running the job under act rather than on GitHub.

The six tests that open a real window skip headless by their own guard. The
summary step counts from the result XML and fails on failures there, because
this project's rule is never to infer a green suite from an exit code.

* Make the colours adjustable per operator profile

Six colour roles per design, per profile: surface, window surface, field interior,
text, accent and separator line. A change applies at once in every open window and
survives a restart once the settings are saved, like any other preference.

Three sources, later wins role by role: the shipped stylesheet from the classpath,
then the profile's own stylesheet file if there is one, then the overrides stored in
the profile's preferences. resolvePalette is a pure function and reports where every
role's colour came from, which the tab shows per field -- with two sources able to
decide one colour, that is the only thing keeping "why is this colour what it is"
answerable, and the spec calls it mandatory rather than decorative.

Four things this had to get right, each learned the hard way and each pinned:

A role is a selector and a property, not a property alone. Three of the six are
stated outside .root -- text on .label, the separator on .separator *.line -- and
-fx-background-color alone appears a dozen times in the evening sheet. Measured: the
shipped daylight sheet states no colour at all, the evening sheet states five and
implies the sixth.

Kst4ContestTheme reads the palette from the store's state and not from remember.
That read is what makes a change repaint every open window; remember(darkMode) held
the palette until somebody toggled day/evening, so a change reached nothing.

A derived colour follows its source's value, never its provenance. The root
profile's own stylesheet is the one copyResourceIfRequired writes at every startup --
the shipped sheet itself -- so layer 2 declares the accent on every existing
installation with nobody having chosen anything. Keying textAccent on "does this come
from a file" repainted the evening accent from green to blue on upgrade and made
"reset to shipped" disagree with "discard my changes".

The contrast guard measures where colours are actually drawn, read off Theme.kt's
Material mapping rather than off the role names: background and surface are both the
window surface, and primary is textAccent, not accent. It reports a pair only when it
is both under WCAG AA and worse than the shipped sheet -- the shipped sheets have
three pairs under 4.5 themselves, so an absolute floor would warn on an untouched
client and teach the operator to ignore warnings.

The way back out of an unreadable palette is deliberately overbuilt, because it is
the one failure that locks itself in. "Reset to the shipped colours" takes the
shipped palette as a required parameter and reads no composition local, so there is
no path by which it could be drawn in the colours it exists to undo; it looks out of
place under a customised palette, and that is what makes it findable. Ctrl+Z, Ctrl+D
and Ctrl+R reach the three ways back even with the caret in a colour field. A
mistyped colour is refused and the field snaps back.

The profile's stylesheet is the hand-editing route the copy under ~/.praktiKST has
been promising since it was first written and never read. It is read now. A button
writes the shipped template as a starting point and never replaces a file that is
already there. An unreadable, truncated or non-CSS file does not prevent startup --
the role falls back to the shipped design. A sheet stating -fx-base and no
-fx-background states the derived window surface too, the way JavaFX does, or the
most natural hand edit would leave every window the shipped light grey.

101 new tests. All of it runs headless.

* Document the adjustable colours, and record the design and the plan

Both manuals get the Colours tab in full: the six roles, that a change applies at
once but survives a restart only after Save settings, the three ways back with their
keyboard shortcuts, what each provenance label means, and the readability notice that
warns without refusing.

Two things an operator would otherwise have to discover. The reset button is always
drawn in the shipped colours and works when nothing else can be read -- the risk
section of the design says plainly that a keyboard path only helps whoever knows it,
so the manual is where this has to be written down. And the root profile already has
both stylesheet files, because KST4Contest has been writing them at startup for
years, so most of its roles report "from file" rather than "shipped" with identical
values.

PROJECT_CONTEXT.md records the decisions that outlive this stage: the three sources
and their precedence, that a role is a selector and a property, that the theme must
read the store's state rather than remember, where the contrast pairs come from, why
the root profile's file layer always exists, and why the lifeline refuses the active
palette. Also corrects its claim that CSS stays global -- a profile now owns its
stylesheets.

The design document and the implementation plan are kept as they were written,
including the plan's own corrections where measuring the code contradicted it.

* Speak the operator's language

The interface is German or English, chosen per operator profile on the GUI tab, in force at
once in every open window, and remembered across restarts. 376 texts in both languages.

The texts are ordinary .properties files that nobody has to compile: a contributor copies the
English one, translates the values, and opens a pull request. A third module -- build tooling
that never ships -- turns them into Kotlin before anything compiles, which is what makes a
mistyped key and a wrong argument count compile errors rather than things an operator
discovers. It lives in the main build rather than buildSrc because buildSrc's tests do not run
on `./gradlew build`, measured, and a generator whose tests never run is the exact failure it
exists to prevent.

Incompleteness is allowed and incorrectness is not. A missing key warns and falls back to
English, so a partial contributed language can be submitted at all; an orphan key, a
placeholder the translation drops, a duplicate key or an unreadable file fail the build with
the generator's own message naming the file. The argument count always comes from the English
base. German is held complete by a test because it ships; a contributed language is not.

What is deliberately not translated is the harder half. Protocol frames and chat commands
would break the connection or go unread; the beacon texts, auto answers, snippets and
shortcuts go to other radio amateurs and sit in every operator's stored profile; the 273
println calls in core are diagnostics, and a German stack trace is worse for whoever reads the
bug report; and QRA, QRG, QTF, LOS, Fresnel and wkd read the same in either language. Three
tests guard the boundary by measuring behaviour rather than text: the protocol frames built
under three locales, every preference default compared by reflection, and no translation value
being a protocol command. The reflective one is the only one that covers what nobody thought
of.

One insight turned up three times. Anything built outside a composition freezes the language it
was built in: the window title, the settings tab strip and every column header are all
constructed once at startup -- the columns from Java -- so each now holds a function read when
it is drawn. That also fixed something older and unrelated to language: the main window's title
was a fixed "KST4Contest (Compose)" for the whole session, where the JavaFX window had carried
the live connection line. It carries it again.

A column's id is never translated. It is what the remembered widths and order are keyed on.

* Document the two languages, and how to contribute a third

Both manuals get the language picker in full: where it sits, that it applies per profile and
takes effect at once in every open window, and -- at more length -- what is deliberately left
alone and why. An operator who sees an English beacon text in a German client should be able
to read that it is meant that way.

The contribution route is written down in both, because plain text files are only useful if
somebody knows they are there: copy, translate, submit; a partial file is welcome; the build
reports mistakes by file name and writes a worksheet of what is still missing.

PROJECT_CONTEXT records the decisions that outlive this stage -- the four kinds of text and
the rule that the addressee decides, that core produces no display text, that incompleteness
is allowed and incorrectness is not, that anything built outside a composition needs its text
read inside one, and that a column id is never translated.

CLAUDE.md said two modules; there are three, and the third never ships. It also states the
German orthography now, which this session got wrong across a spec and two plans: ss after a
short vowel, so muss and dass.

* Remove the implementation plans now that every stage is executed

Thirteen plans, all of them step-by-step instructions for work that is committed. A plan left
behind reads to the next person like an open intention, and these describe a build that no
longer exists -- the first still explains how to introduce Gradle.

The specifications stay. They say why the architecture is what it is, which the code cannot,
and three of them are still argued from. The live-findings note stays too: CLAUDE.md sends
people to it, and its hardest lesson -- that a blocking wait on the AWT event thread deadlocks
the interface while the build stays green -- is written down nowhere else.

Its sweep script stays as well. The note argues explicitly that the script belongs beside the
finding so the next reader can measure rather than believe, and removing it would contradict
the reasoning it illustrates.

Two references in the note and one in the JavaFX-removal spec pointed at plans and now say
where the reasoning went instead.

* Point the JavaFX-removal spec at where its plan's reasoning went

* Remove the stray release-metadata patch from the working tree

A 416-line patch file that was applied long ago and has sat in the repository root since. It
predates this branch and stays in the shared history, where rewriting it would mean rewriting
commits that are already on main and on origin.

* Check the translation files in CI and say what they hold

classes already runs the generator, so an orphan key, a dropped placeholder
or a duplicate fails the compile job with the generator's own message naming
the file -- verified by breaking strings_de.properties on purpose.

A step summary counts each language against the base, so the author of a
translation PR sees what they covered without reading the build log.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Refuse a translation key that would not form a Kotlin name

The generator escaped every translation value but emitted the key verbatim as
the member identifier, and identifierFor strips only . _ - -- so a key carrying
a space, a brace, a quote or a newline from a \uXXXX escape broke out of
val <name>: String get() = lookup(...) into an init block or property
initializer that runs when Strings is instantiated. Translation files are the
contribution surface that arrives by pull request, so this was a path from a
merged .properties change to code in every client.

The generated identifier is now held to letters-then-letters-and-digits before
any source is written, alongside the existing orphan and collision refusals.
Proven by replaying a file-writing payload against the built generator: it now
throws and writes nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Port the rebased diagnostics and session logging onto the modules

origin/main landed replayable session logging (MessageHistoryRecorder), file
logging (ApplicationFileLogging) and a user-list refresh split on the old flat
layout. The rebase carried the new files, but three things needed the new
architecture:

- ChatController.fireUserListUpdate() used javafx Platform; core is toolkit-free
  now, so it dispatches through uiDispatcher like every other fire method.
- Two new tests were left in the old src/test/java; moved into core.
- ScoreServiceRefreshTest mocked javafx Platform statically; it now injects the
  DirectUiDispatcher the no-arg constructor installs.

The Leaflet map performance work was dropped with the HTML map it optimised.

classes testClasses and test are green: 1069 tests, 0 failures, 3 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Give the debug-to-file recording a home in the Compose settings

origin/main added a checkbox to the old JavaFX settings that recorded the whole
ON4KST session to file; the Compose redraw dropped the old settings UI, so the
toggle had no control left even though the preference and its wiring survived
the rebase.

It returns to the message-handling tab: the state writes the preference and asks
the application, through a new SettingsHost callback, to open or close the
error-log handler and the history recorder in the order the old checkbox kept.
The explanatory line and its German translation say that passwords are redacted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Fix Codex review findings on PR 89: station row key, map selection, sort after filter

- Station row key now includes the chat category, so the same callsign in two
  categories no longer collides.
- Map marker click and Reset view go through the central station selection.
- Sorting now operates on the filtered rows, so filters stay effective.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the map drawing test off the network and the user's tile cache

The test assumed no tile ever arrives, but it used the default TileFetcher,
which reads the real disk cache and the OSM tile server. On CI a tile now and
then landed before the frame was rendered and covered the background the
'unreachable tile source' test asserts on. An empty temporary cache and a
source that always fails make the assumption hold by construction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 23:22:11 +02:00

34 KiB
Raw Blame History

Changelog

🇬🇧 You are reading the English version | 🇩🇪 Deutsche Version

Version history of KST4Contest / PraktiKST.

Published Stable versions and their application packages are available under GitHub Releases. This page also lists changes from the current development version where they have already been implemented and tested.


v1.50 (in development)

Operator profiles

Several operators sharing one computer can now use their own callsigns, locators and layouts without overwriting each other's configuration. This implements Issue #57.

New

  • Operator profiles: every profile has its own preferences.xml, and therefore its own settings and its own window layout. Profiles are managed on the new Profiles tab of the settings window: create, duplicate, rename, delete and activate.

  • Shared or own worked stations: each profile decides whether it gets its own worked database or uses the common station database. A multi operator station with a single station log shares the worked state; two operators with different callsigns on one computer keep it apart.

  • Choosing a profile at startup: with only one profile, KST4Contest asks nothing at startup and behaves exactly as before. From two profiles on, a small selection appears with the last used profile preselected; Enter or a double click start immediately. The --profile=<name> argument skips the selection.

  • Switching profiles while running: File > Switch operator profile... closes the connection and rebuilds the user interface with the settings of the selected profile, without restarting the program.

Changed

  • The terrain profile cache is separate: computed terrain profiles now live in their own shared file terrainprofilecache.db and are stored per owner. Previously the whole cache was dropped whenever the callsign or locator changed, which would have discarded every computed profile on each profile switch.

  • The default login callsign is empty: if preferences.xml has no login callsign, the field now stays empty instead of falling back to a callsign compiled into the program. A newly created profile therefore deliberately starts without credentials.

  • Dark mode per profile: on the GUI tab each operator profile sets under Design whether KST4Contest starts light or dark. The entries in the Windows menu still switch quickly, but only for the running session. The colour scheme now also covers the update window and the top candidates list.

Fixed

  • Consistent font size: on macOS and Linux JavaFX uses a slightly larger default font than on Windows, which cut off labels in fixed-size controls. KST4Contest now uses the same base font size on all systems; nothing changes on Windows.

  • Dark mode after a restart: the main window always started light, even if dark mode had been active, while the station map stayed dark. All windows now start consistently with the profile's colour scheme.

  • Background resources are released: the ON4KST supervisor thread, the sked reminder scheduler, the reachability executor, the PSTRotator retry scheduler and the map tile proxy are released when the chat controller is closed. They used to keep running until the program ended.

Upgrade notes

  • Existing installations are not modified: preferences.xml and praktiKST.db stay exactly where they are and become the Default profile. No file is moved or copied.
  • A profile registry only appears when the second profile is created. Anyone using a single profile will not notice the change.
  • Going back to an older KST4Contest release stays possible; it finds its files unchanged.
  • Passwords are still stored in clear text in each profile's preferences.xml. Profiles separate configuration; they are not an access control mechanism.

v1.43.1 (2026-09-03)

Corrected version metadata

v1.43.1 contains the same functional changes as v1.43.0. It corrects the application and build metadata used for display, ON4KST identification and update comparison. Some metadata in the first v1.43.0 package set still identified the build as version 1.42.

Fixed

  • Consistent semantic version: The user-visible application version now uses the complete 1.43.1 form. The compact value 1.431 remains only in the deprecated numeric field required for compatibility with older update feeds.

  • Tagged-release update feed: The website build, version-feed validation and artifact upload now run as actual workflow steps after the GitHub Release has been published. They were previously indented into the release action's artifact list and therefore skipped.

Users of v1.43.0 should install v1.43.1. The functionality is unchanged; the update only corrects the version metadata and release workflow.

The corrected version is available as Release v1.43.1.


v1.43.0 (2026-09-03)

More reliable log synchronisation, persistent layouts and better DX Cluster compatibility

v1.43 concentrates on reliability around external log data and long-running contest operation. It also adds practical control over table layouts and station grouping on the map.

Added

  • Optional map clustering: Group nearby stations immediately enables or disables spatial grouping at lower zoom levels. The stored setting changes neither the viewport nor the selected station; aggregation of active variants sharing one base callsign remains independent. This implements Issue #79.

  • Automatic table-layout persistence: Tables receive useful widths when their first meaningful contents arrive. Manually changed column widths, window sizes and relevant dividers are written to preferences.xml after a short delay. The main and monitor windows keep separate DXCluster and QSO-of-the-other layouts.

  • Tooltips for truncated table values: Normal table cells expose their complete text when the visible column is too narrow, without replacing functional tooltips or clickable links.

  • Simplelogfile creation notice: When the selected file does not exist, KST4Contest creates it and displays a notice with the file path, a concrete test procedure and a link to the relevant manual section.

Changed

  • Robust Simplelogfile evaluation: The selected file is evaluated once per minute and closed after every pass so that the logging application can replace or rotate it. Detected callsigns apply the global Worked state to every active suffix variant of the base callsign. Disabling the function prevents any file access, while read or creation errors no longer terminate the periodic task.

  • Consistent external logger bands: UCXLog-compatible packets and Win-Test events use one shared band normalisation. Numeric values, metre and centimetre designators and the existing Win-Test IDs now set the same Worked flags and worked grid squares. Values including 2320, 5760 and 10368 are handled reliably; a missing or unknown band sets only the global Worked state.

  • Compact full-frequency recognition: Complete frequencies without a decimal separator are accepted across the supported bands, with the final three digits interpreted as the kHz part. Bare three-digit numbers still require recognisable frequency context so that signal reports and unrelated numbers are not treated as QRGs.

  • DXSpider-compatible spot format: Local DX Cluster spots use a fixed 75-character payload line with the DX callsign in column 27, a 30-character comment field and UTC time in column 71. The format remains stable up to 24 GHz. Overlong DX callsigns are rejected and logged instead of being silently truncated. This resolves Issue #86.

  • Active ON4KST connection probe: A quiet chat server is checked with an explicit session-wide probe before the connection is treated as dead. Heartbeats and probe frames retain the required CR/LF framing.

  • Reliable private-message age highlighting: Incoming private messages use the defined green age levels for up to five minutes. Locally sent messages retain their separate style, and empty or reused table rows return to the normal design instead of keeping an obsolete highlight.

Fixed

  • Worked state after login: Persisted SQLite Worked information is loaded and applied before each initial ON4KST user list is published. Reconnects, both categories and all active variants of a base callsign therefore start with the correct state. This resolves Issue #85.

  • False disconnect during quiet periods: A valid ON4KST connection is no longer closed merely because the server currently has no activity lines to send.

Documentation and packaging

  • The German and English manuals were revised against the implementation. A new contest-workflow chapter connects the individual functions into a practical operating sequence, while the sections on dual chat, private-message handling, QRG synchronisation, Simplelogfile evaluation and configuration were clarified.

  • The website feature pages now describe band and direction opportunities, the station map, QRG handling, filters, global message views, private-message handling and logger synchronisation in more detail.

  • The AUR package definitions were updated for v1.43.0.

The complete v1.43.0 functionality is available in Release v1.43.0. Because its embedded version metadata is inconsistent, v1.43.1 is the recommended package set.


v1.42.0 (2026-08-22)

Shared band context, session-based ON4KST connection and signed macOS packages

v1.42 brings several previously separate calculations together. Band information, Worked status, NOT-QRV marks, callsign suffixes and frequencies are now used more consistently by the user list, station map, priority calculation and external interfaces.

Added

  • Visible ON4KST connection state: A compact LINK indicator in the main window displays the actual state of the ON4KST connection. Green means fully authenticated and synchronised, yellow indicates connection setup or synchronisation, and red indicates a lost connection, an error or the delay before the next connection attempt.

  • Shared band-opportunity calculation: A central BandOpportunityResolver evaluates recent QRGs, band designators in station names, active callsign variants, Worked information and NOT-QRV marks. The user list, New bands, band-upgrade hint, Priority Score, station map and automatic band selection now use the same basis.

  • Extended band status display: The band columns now distinguish:

    • X for worked on this band,
    • a for an offered and unworked band of a completely new callsign,
    • B+ for an offered and unworked band of a callsign already worked elsewhere, and
    • o for a locator square already worked on this band.

    The codes can be combined, for example as ao or B+o. The additional a and o indicators can be hidden separately in the GUI settings.

  • 50 and 70 MHz support: Both bands are available in station settings, Worked and NOT-QRV handling, the user list, filters, the internal database, UCXLog processing and the Win-Test listener. Existing databases are extended with the required columns.

  • Global message tabs: Public messages, ON4KST DX cluster messages and directed messages between other stations can be displayed directly in the main window. The existing separate monitor window remains available and uses the same underlying message stores.

  • Manual QTF input: The current antenna direction can be changed directly in KST4Contest when PSTRotator is not being used.

  • MYQTF message variable: The current antenna direction can be inserted as a numeric angle in degrees into shortcuts, snippets and other supported message texts.

  • Filter reset: A dedicated reset button reliably removes the active user-list filter predicates.

  • Map clustering: Stations close to each other are grouped at lower zoom levels. The selected station and relevant direction opportunities remain individually visible.

  • Hideable path analysis: The terrain profile and analysis section of the station map can be hidden completely. The selected state is stored and restored at the next application start.

Changed

  • Session-based ON4KST connection lifecycle: Each socket, reader, writer, message bus and queue now belongs to an explicitly identified connection session. Delayed threads from an obsolete connection can therefore no longer process data or close its replacement. ONLINE is reported only after the login has been accepted and all requested user lists have been received. Connection setup, login and synchronisation use bounded timeouts, while heartbeats, missing inbound traffic, EOF and read or write failures trigger controlled reconnect attempts with backoff where appropriate.

  • Validated ON4KST protocol commands: Outgoing frames are built centrally and checked for valid categories, locators and prohibited frame delimiters. Because ON4KST maintains one locator per TCP session, the main locator is used for both chat categories and a conflicting secondary configuration is logged instead of sending contradictory commands to the server.

  • More precise QRG recognition: Complete and relative frequency references continue to be recognised. Bare three-digit numbers are treated as QRGs only when a frequency context is available. Signal reports, band designators and unrelated numbers therefore produce fewer false frequencies.

  • Station-specific frequency context: For relative QRGs, KST4Contest first uses a band context for the same station which is no more than 30 minutes old. The globally configured fallback band is used only when this context is unavailable.

  • Fallback band dropdown: The global fallback can only be selected from supported band values. It applies to the complete QRG parser, not merely to DX cluster spots.

  • Consistent QRG formatting: Frequencies are displayed with at least three decimal places in the user list and message tables.

  • Band-aware AirScout and path calculations: KST4Contest derives a realistic frequency for each station from its current QRG and known band information. AirScout receives canonical band values. The temporary 430 MHz fallback has been replaced with 432 MHz.

  • Shared propagation-frequency selection: AirScout, Calc selected and the station-map path analysis use the same PropagationFrequencyResolver. A band selected explicitly in the Reachability dropdown is respected for manual calculations.

  • Separate callsign variants: Active chat members are distinguished by their complete callsign, including suffix, and by chat category. DN9APW, DN9APW-2 and similar logins therefore remain separate message targets.

  • Shared base-callsign information: Worked flags, NOT-QRV information and Priority Scores continue to be evaluated across variants of the same base callsign. Separate message targets no longer result in contradictory Worked information.

  • Corrected Priority Score eligibility: Stations without a common available band, or with an overriding NOT-QRV mark, are no longer offered as priority candidates. An open band at a station already worked elsewhere can receive a separate Priority Boost.

  • Extended sked creation: The band is selected from those enabled locally. SSB or CW is selected explicitly for the Win-Test handover instead of attempting to infer the mode unreliably from the band.

  • More precise Win-Test sked handover: The QRG must belong to the selected band. Visible KST suffixes are removed for the logging target while portable callsign components are preserved. ADDSKED timestamps are generated correctly. A failed handover does not remove the internal KST4Contest sked.

  • Exact sked targets: The timeline and automatic reminders use the complete visible KST callsign. A sked for DN9APW-2 is not accidentally sent to another variant of the same base callsign.

  • Reworked beacon and automatic replies: Both chat categories use one shared timer while retaining separate enable switches and message texts. The minimum permitted interval is one minute and message texts are limited to 120 characters. The stored beacon state is restored from the configuration at startup.

  • Central variable resolution: Message variables used by beacons, shortcuts, snippets and other generated text are processed by one shared resolver.

  • Improved message tables: Truncated messages show their complete text in a tooltip. Recognised web addresses can be opened in the system browser.

  • More compact filter bar: Filters retain their compact arrangement at normal widths and wrap only when the available space is genuinely insufficient. This allows the centre divider to be moved further to the right.

  • DXLog full-log import: In addition to contactinfo, the UCXLog-compatible UDP listener processes contactreplace. This allows a complete log broadcast by DXLog.net to be imported.

  • Guarded automatic QRG updates: MYQRG is updated only by an enabled interface which actually supplies valid RadioInfo or Win-Test STATUS packets. An enabled source which provides no data does not remove the need for a functional check or manual QRG maintenance.

  • Improved version comparison: Versions are compared semantically so that patch releases and Nightly versions are not misclassified by conversion to a floating-point number.

Fixed

  • Reliable initial user list: Invalid or incomplete UA0 member records are rejected and logged individually without preventing alphabetically following members from being processed. Valid entries are staged per category and published as one complete snapshot when the first corresponding UE end marker is received.

  • User list disappearing after login: ON4KST may send additional UE frames for the same category after name, state or other live updates. Repeated end markers are now detected and ignored so that an already populated user list cannot be replaced by an empty snapshot.

  • Failed initial connection and lost sockets: An unavailable server during startup no longer sends KST4Contest into an endless or busy-wait loop. The user interface remains responsive and further attempts use bounded reconnect backoff. Sockets closed by the server, or connections without inbound traffic for an excessive period, are also detected reliably.

  • Message-bus diagnostics: Correctly processed ON4KST frames are no longer reported additionally as Critical, detected unhandled Chatmessage. Only genuinely unknown frames reach the fallback diagnostic branch.

  • Password in diagnostic output: The ON4KST password is no longer written in plain text to the console or error log during connection setup.

  • Long-running station-selection failure: Chat members managed by the message thread have been decoupled from the JavaFX view. Simultaneous data and table updates therefore no longer cause broken selection models or concurrent-modification problems after longer runtimes.

  • No phantom chat members from UM3: Historical or additional server messages no longer create user-list entries for stations which are not actually logged into the chat.

  • Messages to callsigns with suffixes: Several active variants of the same base callsign no longer overwrite each other. This resolves Issue #73.

  • DX cluster locators: The reporting and reported station no longer receive the same locator accidentally. This resolves Issue #48.

  • Worked state in “QSO of the other”: The Worked columns again use the correct transmitting and receiving station.

  • Missing SECONDAP data: A missing second aircraft-scatter opportunity no longer produces an invalid text selection and JavaFX exception when the field is edited.

  • Historical callsigns: Highlighting or selecting a callsign which is no longer present in the active user list no longer causes an exception.

  • Win-Test sked time and callsign handling: Timestamps, band-to-QRG assignment, KST suffixes and portable callsigns are handled correctly.

  • Filter reset: All filter predicates are actually removed, and the visible button state again matches the effective filter state.

Documentation and packaging

  • The German and English manuals have been systematically checked against the source code, extended and supplied with current screenshots. The documentation now describes not only the controls, but also how information is derived and where the limits of a result lie.

  • The AUR provides kst4contest-bin, kst4contest and kst4contest-git for Arch Linux.

  • The download page distinguishes between Stable, Beta and Nightly and offers only packages which actually belong to the corresponding channel.

  • Nightly packages are built automatically from the current main branch. Stable and Beta releases use predictable asset names for the supported platforms.

  • Signed and notarized macOS packages: The DMG files for Apple Silicon and Intel are signed with an Apple Developer ID and notarized by Apple, with the notarization ticket stapled into the DMG. The first launch now works by double-clicking, without the previous detour through Open in the context menu, and the check also succeeds without an internet connection. This applies to Nightly, Beta and Stable packages alike. The Windows packages remain unsigned.

  • Correct bundle identifier and version on macOS: The application now identifies itself as de.x08.KST4Contest rather than kst4contest.view, and carries its actual version number in the bundle. Previously every release reported version 1.0 in Finder's Get Info panel. Existing settings are unaffected, because KST4Contest stores its data in ~/.praktiKST/ rather than keying it to the bundle identifier.

Known limitations

  • The active terrain provider uses Open-Meteo with Copernicus GLO-90 data and no more than 100 elevation samples per path.

  • The atmospheric K factor is currently fixed at 4/3.

  • An antenna height of 10 metres above ground is assumed for the remote station.

  • Aircraft-scatter information from AirScout and the terrain analysis in the station map remain separate assessments.

  • More detailed configuration of station height, frequency and K factor is being tracked in Issue #74.

The published version is available as Release v1.42.0.


v1.41.1 (2026-07-08)

Hotfix for text input and focus handling

Fixed

  • The message input field was unexpectedly cleared after some time or during particular UI updates.
  • Filtering or selecting a station could move the input focus back to the send field unintentionally.

The corrected version is available as Release v1.41.1.


v1.41.0 (2026-07-01)

Station map, bounded message stores and screen-aware main window

Added

  • Station map: An interactive OpenStreetMap-based map displays active chat members for which a usable locator is available.

  • Antenna sector and connection line: The map shows the current local QTF, configured antenna beamwidth, maximum QRB and the path to the selected station.

  • Maidenhead grid: A locator grid adapted to the current zoom level provides geographical orientation.

  • Terrain profile: An elevation profile for a selected station can be requested from the Open-Meteo Elevation API. The active source uses Copernicus GLO-90 data and no more than 100 evenly distributed samples.

  • Geometrical path analysis: The calculation includes line of sight, Earth curvature using k = 4/3, radio and terrain horizons, the first Fresnel zone and a rough obstruction estimate.

  • Local map proxy: Leaflet is bundled with the application. Map tiles are loaded through a local proxy so that no external JavaScript library is required at runtime. An Internet connection is still required for OpenStreetMap tiles and online elevation data.

Changed

  • Bounded message stores: The global chat-message list is reduced from more than 30,000 entries to 25,000. The separate DX cluster store is reduced from more than 10,000 entries to 8,000.

  • Screen-aware startup size: The main window is checked against the visible area of the primary screen at startup and reduced or repositioned when necessary.

  • More compact user interface: Several UI sections were adapted for smaller displays and movable dividers.

Scope of the map function

The station map and AirScout may refer to the same remote station, but their calculations remain separate. Aircraft used by AirScout are not included in the terrain profile.

Classes for Copernicus GLO-30, offline DEM imports and additional terrain providers existed in the source tree but were not part of the active calculation chain in v1.41. The elevation source actually used was Open-Meteo based on Copernicus GLO-90.


v1.40 (2026-02-16)

Major Feature Release: Score System, AP Timeline, Win-Test, PSTRotator

New:

  • Chatmember Score System: Every chat member is automatically scored based on antenna direction, activity time, message count, active bands, frequencies, sked direction (degrees), and other factors. Top candidates are highlighted in a dedicated list.
  • AP Timeline: For each minute of possible aircraft arrival, up to 4 highly-scored stations are shown that should be workable. Aircraft with the highest potential are preferred over the fastest arrival. Chat members whose antenna is not pointing towards you are shown transparently.
  • Win-Test Support (Beta since v1.31, now fully configurable): Log synchronisation, frequency parsing and sked handover via UDP fully integrated. Can be enabled/disabled in Preferences.
  • PSTRotator Interface (Beta since v1.31, now fully configurable): Rotator position updates directly from KST4Contest. Can be enabled/disabled in Preferences.
  • QSO Sniffer: Messages from configurable callsign lists are automatically forwarded to the PM window.
  • Band Alert for logged stations: When a station is logged, a hint appears if that station has another active band that you are also QRV on.
  • Sked Reminder ALERT: A sked alarm with automatic messages in configurable intervals (2+1 / 5+2+1 / 10+5+2+1 minutes before the sked) can be set up for each chat member, plus acoustic and visual notification.
  • Load chat history on startup: Chat server history is loaded on connect to immediately see active members and recent messages.
  • Skedfail button: In the FurtherInfo panel, a sked failure can be marked for a chat member, which lowers their priority score.

Changed:

  • AP notes added to internal DX cluster spots.
  • Chat member table scrolling follows the current message selection automatically.
  • Generic auto-reply and QRG auto-reply now fire a maximum of once every 45 seconds per callsign (prevents spam and message ping-pong).
  • New saveable settings: ServerDNS/Port, PSTRotator interface, Win-Test interface, callsign sniffer, Dark Mode on by default.
  • Date column removed from chat table (time only – saves space).

Fixed:

  • User list now automatically sorted on every new member sign-on.
  • Posonpill messages now terminate exactly one client instance (no longer affects all instances or wtKST).
  • wtKST: crash on KST4Contest disconnection fixed.
  • Multiple issues with callsign suffixes like /p, -2, etc. fixed throughout.
  • QTFDefault was not saved correctly → fixed.
  • AirScout watchlist (ASWATCHLIST) was not being updated → fixed.
  • Dark Mode: QRG fields not displayed at full size → fixed.
  • Version number display corrected.

v1.31 (2025-12-13)

Win-Test + PSTRotator Beta, QSO Sniffer, DNS Hotfix

New:

  • Win-Test support (Beta, not yet deactivatable): Log synchronisation and frequency parsing.
  • PSTRotator support (Beta, not yet deactivatable).
  • QSO Sniffer: Messages from configurable callsigns are forwarded to the PM window.

Changed:

  • DNS server changed: From www.on4kst.info to www.on4kst.org (hotfix). The DNS server is now configurable in Preferences.

Fixed:

  • Endless loop in error case freezes the client → fixed.

v1.266 (2025-10-03)

AirScout Fix for Callsigns with Suffix

Fixed:

  • AirScout interface did not work when the login callsign contained a suffix (e.g. 9A1W-2). AirScout cannot handle this format – only the base callsign without suffix is now passed to AirScout.

(Bug reported and tested by 9A2HM / Kreso – many thanks!)


v1.265 (2025-09-28)

Direction Buttons Stay Coloured When Active

Fixed:

  • Direction buttons (N / NE / E etc.) now keep their highlight colour when activated, making the active state immediately visible.

v1.264 (2025-08-02)

Simplelogfile: Improved Callsign Recognition

Fixed:

  • Callsigns like S53CC, S51A, etc. were not being marked as worked in the SimpleLogFile interpreter → recognition pattern improved.

(Bug reported by Boris, S53CC – thank you!)


v1.263 (2025-06-08)

AirScout Communication and Login Name

Changed:

  • AirScout communication fundamentally revised: Only stations with QRB < max-QRB are now sent to AirScout.
  • Query interval extended from 12 seconds to 60 seconds.
  • Significantly less computation load and message traffic → more stable AirScout tracking.
  • Name of the AS client and AS server is now configurable from the Preferences (was previously hardcoded to "KST" / "AS").

Fixed:

  • "Track in AirScout" button was very sluggish → greatly improved by new communication logic.
  • Name in chat is now saveable (bug fixed).
  • Visual corrections before and after login.
  • Bug fixed that was reported by 9A2HM (Kreso).

v1.262 (2025-05-21)

Freeze Fix for Early Message Delivery

Fixed:

  • ON4KST sometimes delivers messages before login is complete. This caused errors in the message processing engine → now fixed.

v1.26 (2025-05)

Multi-Channel Login and Dark Mode

New:

  • Dark Mode: Toggle via Window → Use Dark Mode.
  • Multi-channel login: Simultaneous login to two chat categories.
  • Opposite station multi-callsign login tagging: Support for stations with multiple callsigns.

Changed:

  • Colouring mechanism revised: Colours can now be customised via CSS.

Fixed:

  • Station tagging completely revised and corrected.

v1.251 (2025-02)

Bugfix for UDP Broadcast Spot Info

Fixed:

  • Problem reading UDP broadcast spot information fixed (reported by Steve Clements – thank you!).
  • Station tagging (further improved).

v1.25 (2025-02)

Wishlist Time

New:

  • New settings tab: Messagehandling
    • Auto-reply to incoming messages configurable.
    • Automatic reply with own CQ QRG when someone asks for it.
    • Configurable default filter for the userinfo window (for Gianluca :-) ).
  • Coloured PM rows: New private messages appear red and fade every 30 seconds from yellow to white (idea by IU3OAR, Gianluca).

Fixed:

  • Stations with suffixes like "-2" and "-70" were not being marked as worked → now ignored, station is correctly marked.

v1.24 (2024-11)

Wishlist + DX Cluster Spots

New:

  • Button to open the QRZ.com profile of the selected station.
  • Button to open the QRZ-CQ profile of the selected station.
  • DX Cluster Server integration: Direction warnings are sent as spots to the logging software (when QRG is known).

(Coloured PM row feature also added – tnx Gianluca)


v1.23 (2024-10)

Built-in DX Cluster Server

New:

  • KST4Contest now contains a built-in DX cluster server.
  • Generates DX cluster spots and sends them to the logging software when a direction warning is triggered and a QRG is known.
  • Spotter callsign must differ from the contest callsign (for correct filtering in the logging software).

(Idea by OM0AAO, Viliam Petrik – thank you!)


v1.22 (2024-05)

Usability Improvements and AirScout Button Fix

New:

  • New variables (tnx OM0AAO, Viliam Petrik):
    • MYLOCATORSHORT
    • MYQRGSHORT
    • QRZNAME

Changed:

  • Send field focus: After clicking a callsign in the user list, the send field immediately receives focus – no double-click needed (tnx Gianluca).

Fixed:

  • Worked-station filter is now live: Worked stations disappear immediately when the filter is activated (tnx Gianluca).
  • QRB sorting was lexicographic → now numeric (tnx Alessandro Murador).
  • AirScout "Show Path" button: Click now maximises AirScout and correctly shows the path.

v1.21 (2024-04)

Usability Improvements

Changed:

  • Window sizes and divider positions are saved in the configuration file when clicking "Save Settings" and restored on startup.
  • Filter section as flowpane → better display on smaller screens.

v1.2 (2024-04)

Band Selection and NOT-QRV Tags

New:

  • Band selection: Selectable in Preferences which bands are active. Only buttons and fields for selected bands appear in the UI. Save and restart required.
  • NOT-QRV tags per station and band: Stations can be marked as "not QRV" for each band. Combinable with the user list filter.
  • QTF arrow: The "Show path in AS" button now shows an arrow with the QTF of the selected station.

Earlier Versions

v1.1

First publicly released version. Core features:

  • Worked marking via Simplelogfile and UDP
  • Sked direction highlighting
  • QRG detection
  • Text snippets and shortcuts
  • AirScout interface (first version)
  • Interval beacon
  • PM catching for public messages containing your own callsign
  • Update notification service

Planned Features

  • Lifetime for worked status (automatic reset) ✅ Implemented in v1.40 (3-day lifetime, no manual reset needed anymore)
  • Filtering the "Cluster & QSO of others" window to own QTF
  • Further topography-based calculations for direction warnings