* 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>
37 KiB
Changelog
🇬🇧 English version | 🇩🇪 Du liest gerade die deutsche Version
Versionsverlauf von KST4Contest / PraktiKST.
Die veröffentlichten Stable-Versionen und ihre Programmpakete stehen unter GitHub Releases. Zusätzlich enthält diese Seite die Änderungen des aktuellen Entwicklungsstands, soweit sie bereits implementiert und geprüft wurden.
v1.50 (in Entwicklung)
Operator-Profile
Mehrere Operateure an einem Rechner können jetzt eigene Rufzeichen, Locators und Layouts verwenden, ohne sich gegenseitig die Konfiguration zu überschreiben. Damit ist Issue #57 umgesetzt.
Neu
-
Operator-Profile: Jedes Profil hat seine eigene
preferences.xmlund damit eigene fachliche Einstellungen und einen eigenen Layoutstand. Verwaltet werden Profile im neuen Reiter Profiles des Einstellungsfensters: anlegen, duplizieren, umbenennen, löschen und aktivieren. -
Gemeinsame oder eigene gearbeitete Stationen: Pro Profil wird entschieden, ob es eine eigene Worked-Datenbank bekommt oder die gemeinsame Stationsdatenbank benutzt. Eine Multi-OP-Station mit einem einzigen Stationslog teilt den Worked-Status, zwei OMs mit verschiedenen Rufzeichen an einem Rechner trennen ihn.
-
Profilwahl beim Start: Mit nur einem Profil fragt KST4Contest beim Start nichts und verhält sich unverändert. Ab zwei Profilen erscheint eine kleine Auswahl mit vorausgewähltem letzten Profil; Enter oder Doppelklick starten sofort. Der Aufrufparameter
--profile=<Name>überspringt die Auswahl. -
Profilwechsel im laufenden Betrieb: File → Switch operator profile... trennt die Verbindung und baut die Oberfläche mit den Einstellungen des gewählten Profils neu auf, ohne Programmneustart.
Geändert
-
Zwischenspeicher der Geländeprofile getrennt: Berechnete Geländeprofile liegen jetzt in der eigenen, gemeinsam genutzten Datei
terrainprofilecache.dbund werden nach Besitzer getrennt gespeichert. Bisher wurde der gesamte Zwischenspeicher gelöscht, sobald sich Rufzeichen oder Locator änderten; bei einem Profilwechsel wäre damit jedes berechnete Profil verloren gegangen. -
Rufzeichen-Vorgabe ist leer: Fehlt in der
preferences.xmlein Login-Rufzeichen, bleibt das Feld jetzt leer, statt auf ein im Programm hinterlegtes Rufzeichen zurückzufallen. Ein neu angelegtes Profil startet damit bewusst ohne Anmeldedaten. -
Dark Mode pro Profil: Im Reiter GUI legt jedes Operator-Profil unter Design fest, ob KST4Contest hell oder dunkel startet. Die Menüeinträge unter Windows schalten weiterhin schnell um, gelten aber nur für die laufende Sitzung. Das Farbschema erfasst jetzt auch das Update-Fenster und die Liste der Top-Kandidaten.
Behoben
-
Einheitliche Schriftgröße: Unter macOS und Linux verwendet JavaFX eine etwas größere Standardschrift als unter Windows. Dadurch wurden Beschriftungen in fest bemessenen Bedienelementen abgeschnitten. KST4Contest verwendet jetzt auf allen Systemen dieselbe Grundschriftgröße; unter Windows ändert sich nichts.
-
Dark Mode nach dem Neustart: Das Hauptfenster startete immer hell, auch wenn zuletzt der Dark Mode aktiv war, während die Stationskarte dunkel blieb. Jetzt starten alle Fenster einheitlich mit dem Farbschema des Profils.
-
Freigegebene Hintergrundressourcen: Der ON4KST-Überwachungsthread, der Sked-Erinnerungs-Scheduler, der Reachability-Executor, der PSTRotator-Wiederholungs-Scheduler und der Kachel-Proxy der Karte werden beim Schließen des Chatcontrollers freigegeben. Bisher liefen sie bis zum Programmende weiter.
Hinweise zur Aktualisierung
- Bestehende Installationen werden nicht verändert:
preferences.xmlundpraktiKST.dbbleiben genau dort liegen, wo sie sind, und werden zum Profil Default. Es wird keine Datei verschoben oder kopiert. - Eine Profil-Registry entsteht erst beim Anlegen des zweiten Profils. Wer nur ein Profil benutzt, merkt von der Änderung nichts.
- Eine Rückkehr zu einer älteren KST4Contest-Version bleibt möglich; sie findet ihre Dateien unverändert vor.
- Passwörter stehen weiterhin im Klartext in der
preferences.xmldes jeweiligen Profils. Profile trennen die Konfiguration, sie sind kein Zugriffsschutz.
v1.43.1 (2026-09-03)
Korrigierte Versionsmetadaten
v1.43.1 enthält dieselben funktionalen Änderungen wie v1.43.0. Korrigiert wurden die Anwendungs- und Build-Metadaten für Anzeige, ON4KST-Kennung und Update-Vergleich. Ein Teil der Metadaten des ersten v1.43.0-Pakets wies den Build noch als Version 1.42 aus.
Behoben
-
Einheitliche semantische Version: Die sichtbare Anwendungsversion verwendet jetzt vollständig
1.43.1. Der kompakte Wert1.431bleibt ausschließlich im veralteten numerischen Feld für die Kompatibilität mit älteren Update-Feeds erhalten. -
Update-Feed im Tagged-Release-Workflow: Website-Build, Prüfung des Versionsfeeds und Upload der Artefakte laufen jetzt tatsächlich nach der Veröffentlichung des GitHub Releases. Diese Schritte waren zuvor versehentlich in die Artefaktliste der Release-Action eingerückt und wurden deshalb übersprungen.
Wer v1.43.0 installiert hat, sollte v1.43.1 verwenden. Die Funktionen bleiben unverändert; korrigiert werden nur die Versionsmetadaten und der Release-Workflow.
Die korrigierte Version ist als Release v1.43.1 verfügbar.
v1.43.0 (2026-09-03)
Zuverlässigere Log-Synchronisation, gespeicherte Tabellenlayouts und bessere DX-Cluster-Kompatibilität
v1.43 konzentriert sich auf die zuverlässige Verarbeitung externer Logdaten und den stabilen Betrieb während längerer Conteste. Hinzu kommen praktische Einstellmöglichkeiten für Tabellenlayouts und die Stationsgruppierung auf der Karte.
Neu
-
Optionale Kartencluster: Group nearby stations schaltet die räumliche Gruppierung bei niedrigen Zoomstufen unmittelbar ein oder aus. Die gespeicherte Auswahl verändert weder Kartenausschnitt noch Stationsauswahl; die Zusammenfassung aktiver Varianten desselben Basisrufzeichens bleibt davon unabhängig. Damit ist Issue #79 umgesetzt.
-
Tabellenlayout automatisch gesichert: Tabellen erhalten beim ersten brauchbaren Inhalt sinnvolle Breiten. Manuell geänderte Spaltenbreiten, Fenstergrößen und relevante Divider werden nach kurzer Verzögerung in
preferences.xmlgeschrieben. Haupt- und Monitorfenster behalten getrennte Layouts für DXCluster und QSO of the other. -
Tooltips für gekürzte Tabellenwerte: Normale Tabellenzellen zeigen ihren vollständigen Inhalt, wenn die sichtbare Spalte zu schmal ist. Funktionale Tooltips und anklickbare Links bleiben davon unberührt.
-
Hinweis bei neu angelegtem Simplelogfile: Fehlt die ausgewählte Datei, legt KST4Contest sie an und zeigt einen Hinweis mit Dateipfad, konkretem Testablauf und Link zum passenden Abschnitt des Handbuchs.
Geändert
-
Robuste Simplelogfile-Auswertung: Die ausgewählte Datei wird einmal pro Minute ausgewertet und nach jedem Durchlauf geschlossen, damit das Logprogramm sie ersetzen oder rotieren kann. Erkannte Rufzeichen setzen den globalen Worked-Status für alle aktiven Suffixvarianten des Basisrufzeichens. Bei deaktivierter Funktion findet kein Dateizugriff statt; Lese- oder Erstellungsfehler beenden die periodische Aufgabe nicht mehr.
-
Einheitliche Bandwerte externer Logger: UCXLog-kompatible Pakete und Win-Test-Ereignisse verwenden eine gemeinsame Bandnormalisierung. Numerische Werte, Meter- und Zentimeterangaben sowie die vorhandenen Win-Test-IDs setzen damit dieselben Worked-Markierungen und Worked-Großfelder. Insbesondere
2320,5760und10368werden zuverlässig verarbeitet; bei fehlendem oder unbekanntem Band wird nur der globale Worked-Status gesetzt. -
Kompakte vollständige Frequenzen erkannt: Vollständige Frequenzangaben ohne Dezimaltrenner werden auf allen unterstützten Bändern akzeptiert; die letzten drei Ziffern bilden den kHz-Anteil. Nackte dreistellige Zahlen benötigen weiterhin einen erkennbaren Frequenzkontext, damit Signalrapporte und andere Zahlen nicht als QRG behandelt werden.
-
DXSpider-kompatibles Spotformat: Lokale DX-Cluster-Spots verwenden eine feste 75-Zeichen-Nutzzeile mit dem DX-Rufzeichen ab Spalte 27, einem 30 Zeichen breiten Kommentarfeld und der UTC-Zeit ab Spalte 71. Das Format bleibt bis 24 GHz stabil. Überlange DX-Rufzeichen werden verworfen und protokolliert, statt unbemerkt abgeschnitten zu werden. Damit ist Issue #86 behoben.
-
Aktive ON4KST-Verbindungsprüfung: Ein ruhiger Chatserver wird mit einer expliziten, sitzungsweiten Abfrage geprüft, bevor die Verbindung als unterbrochen gilt. Heartbeat und Prüftelegramme behalten das erforderliche CR/LF-Framing.
-
Zuverlässige Altersmarkierung privater Nachrichten: Eingehende Privatnachrichten verwenden bis zu fünf Minuten lang die definierten grünen Altersstufen. Eigene Nachrichten behalten ihre separate Darstellung; leere oder wiederverwendete Tabellenzeilen kehren zum normalen Design zurück und behalten keine veraltete Hervorhebung.
Behoben
-
Worked-Status nach dem Login: Persistierte SQLite-Informationen werden vor der Veröffentlichung jeder initialen ON4KST-Benutzerliste geladen und angewendet. Erneute Verbindungen, beide Kategorien und alle aktiven Varianten eines Basisrufzeichens starten dadurch mit dem richtigen Status. Damit ist Issue #85 behoben.
-
Fehlerhafte Trennung bei ruhigem Server: Eine gültige ON4KST-Verbindung wird nicht mehr beendet, nur weil der Server gerade keine Aktivitätszeilen überträgt.
Dokumentation und Auslieferung
-
Das deutsche und englische Handbuch wurden mit der Implementierung abgeglichen und überarbeitet. Ein neues Kapitel zum Contest-Workflow verbindet die einzelnen Funktionen zu einem praktischen Betriebsablauf; außerdem wurden die Abschnitte zu Dual Chat, Privatnachrichten, QRG-Synchronisation, Simplelogfile-Auswertung und Konfiguration präzisiert.
-
Die Website beschreibt Band- und Richtungsgelegenheiten, Stationskarte, QRG-Verarbeitung, Filter, globale Nachrichtenansichten, Privatnachrichten und Log-Synchronisation jetzt ausführlicher.
-
Die AUR-Paketdefinitionen wurden auf v1.43.0 aktualisiert.
Die vollständige Funktionalität von v1.43.0 steht im Release v1.43.0 bereit. Wegen der inkonsistenten eingebetteten Versionsmetadaten ist v1.43.1 der empfohlene Paketstand.
v1.42.0 (2026-08-22)
Gemeinsamer Bandkontext, sitzungsbasierte ON4KST-Verbindung und signierte macOS-Pakete
v1.42 führt mehrere bisher getrennte Auswertungen zusammen. Bandinformationen, Worked-Status, NOT-QRV-Markierungen, Rufzeichensuffixe und Frequenzen werden dadurch konsistenter in der Benutzerliste, der Stationskarte, der Prioritätsberechnung und den externen Schnittstellen verwendet.
Neu
-
Sichtbarer ON4KST-Verbindungsstatus: Ein kompakter
LINK-Indicator im Hauptfenster zeigt den tatsächlichen Zustand der ON4KST-Verbindung an. Grün bedeutet vollständig angemeldet und synchronisiert, Gelb kennzeichnet Verbindungsaufbau und Synchronisation, Rot eine unterbrochene Verbindung, einen Fehler oder die Wartezeit vor dem nächsten Verbindungsversuch. -
Gemeinsame Herleitung verfügbarer Bänder: Ein zentraler
BandOpportunityResolverwertet aktuelle QRGs, Bandangaben im Namensfeld, aktive Rufzeichenvarianten, Worked-Informationen und NOT-QRV-Markierungen gemeinsam aus. Benutzerliste, New bands, Band-Upgrade-Hinweis, Priority Score, Stationskarte und automatische Bandauswahl verwenden damit dieselbe Grundlage. -
Erweiterte Bandanzeige: Die Bandspalten unterscheiden jetzt:
Xfür auf diesem Band gearbeitet,afür ein angebotenes, noch nicht gearbeitetes Band einer insgesamt neuen Station,B+für ein angebotenes, noch nicht gearbeitetes Band einer bereits auf einem anderen Band gearbeiteten Station undofür ein auf diesem Band bereits gearbeitetes Locator-Großfeld.
Die Anzeigen können kombiniert werden, beispielsweise als
aooderB+o. Die zusätzlichen Kennzeichnungenaundolassen sich in den GUI-Einstellungen separat ausblenden. -
Unterstützung für 50 und 70 MHz: Beide Bänder stehen in der Stationskonfiguration, den Worked- und NOT-QRV-Funktionen, der Benutzerliste, den Filtern, der internen Datenbank, der UCXLog-Auswertung und dem Win-Test-Listener zur Verfügung. Bereits gespeicherte Datenbanken werden um die benötigten Spalten ergänzt.
-
Globale Nachrichtentabs: Öffentliche Nachrichten, ON4KST-DX-Cluster-Meldungen und gerichtete Nachrichten zwischen anderen Stationen können direkt im Hauptfenster angezeigt werden. Das bisherige separate Monitorfenster bleibt zusätzlich verfügbar und verwendet dieselben Nachrichtenspeicher.
-
Manuelle QTF-Eingabe: Die aktuelle Antennenrichtung kann auch ohne PSTRotator direkt in KST4Contest geändert werden.
-
Nachrichtenvariable
MYQTF: Die aktuelle Antennenrichtung kann als numerischer Winkel in Grad in Shortcuts, Snippets und andere unterstützte Nachrichtentexte eingesetzt werden. -
Filter zurücksetzen: Ein eigener Reset-Button entfernt die aktiven Filterprädikate der Benutzerliste zuverlässig.
-
Kartencluster: Räumlich dicht beieinanderliegende Stationen werden bei niedrigen Zoomstufen zusammengefasst. Die ausgewählte Station und relevante Richtungsgelegenheiten bleiben einzeln sichtbar.
-
Ausblendbare Streckenanalyse: Geländeprofil und Analysebereich der Stationskarte können vollständig ausgeblendet werden. Die Auswahl wird gespeichert und beim nächsten Programmstart wiederhergestellt.
Geändert
-
Sessionbezogene ON4KST-Verbindungssteuerung: Socket, Reader, Writer, Messagebus und Warteschlangen gehören jetzt zu einer eindeutig identifizierten Verbindungssession. Veraltete Threads einer abgelösten Verbindung können dadurch keine Daten mehr verarbeiten oder die neue Verbindung schließen.
ONLINEwird erst nach bestätigtem Login und vollständig empfangenen Benutzerlisten gemeldet. Verbindungsaufbau, Login und Synchronisation besitzen feste Zeitlimits; Heartbeats, ausbleibende Eingangsdaten, EOF sowie Lese- und Schreibfehler werden überwacht und lösen bei Bedarf einen kontrollierten Neuaufbau mit Backoff aus. -
ON4KST-Protokollbefehle abgesichert: Ausgehende Befehle werden zentral aufgebaut und auf gültige Kategorien, Locatoren und unerlaubte Frame-Trennzeichen geprüft. Da ON4KST pro TCP-Session nur einen Locator verwaltet, wird für beide Chat-Kategorien der Hauptlocator verwendet und eine abweichende zweite Konfiguration protokolliert, statt widersprüchliche Befehle an den Server zu senden.
-
QRG-Erkennung präzisiert: Vollständige und relative Frequenzangaben werden weiterhin erkannt. Nackte dreistellige Zahlen gelten nur noch bei erkennbarem Frequenzkontext als QRG. Signalrapporte, Bandangaben und andere Zahlen erzeugen dadurch seltener falsche Frequenzen.
-
Stationsbezogener Frequenzkontext: Bei relativen QRGs verwendet KST4Contest zuerst einen höchstens 30 Minuten alten Bandkontext derselben Station. Erst wenn dieser fehlt, wird das global konfigurierte Fallback-Band verwendet.
-
Fallback-Band als Dropdown: Das globale Fallback kann nur noch aus unterstützten Bandwerten ausgewählt werden. Es betrifft die gesamte QRG-Erkennung und nicht nur DX-Cluster-Spots.
-
Einheitliche QRG-Darstellung: Frequenzen werden in Benutzer- und Nachrichtentabellen mit mindestens drei Nachkommastellen dargestellt.
-
Bandabhängige AirScout- und Streckenberechnung: KST4Contest leitet für jede Station eine möglichst realistische Frequenz aus der aktuellen QRG und den bekannten Bandinformationen ab. AirScout erhält kanonische Bandwerte. Die frühere Zwischenlösung mit 430 MHz wurde durch 432 MHz ersetzt.
-
Gemeinsame Frequenzherleitung: AirScout, Calc selected und die Pfadanalyse der Stationskarte verwenden denselben
PropagationFrequencyResolver. Ein im Reachability-Dropdown ausdrücklich gewähltes Band wird bei manuellen Berechnungen berücksichtigt. -
Rufzeichenvarianten getrennt verarbeitet: Aktive Chatmember werden durch das vollständige Rufzeichen einschließlich Suffix und die Chat-Kategorie unterschieden.
DN9APW,DN9APW-2oder vergleichbare Logins bleiben dadurch getrennte Nachrichtenziele. -
Gemeinsame Basisinformationen: Worked-Flags, NOT-QRV-Informationen und der Priority Score werden weiterhin für Varianten desselben Basisrufzeichens gemeinsam ausgewertet. Getrennte Nachrichtenziele führen damit nicht zu widersprüchlichen Worked-Daten.
-
Priority Score korrigiert: Stationen ohne gemeinsames verfügbares Band oder mit übersteuernder NOT-QRV-Markierung werden nicht mehr als Prioritätskandidaten angeboten. Bandgelegenheiten bereits gearbeiteter Stationen können einen eigenen Priority Boost erhalten.
-
Sked-Erstellung erweitert: Das Band wird aus den lokal aktivierten Bändern gewählt. Für die Win-Test-Übergabe wird
SSBoderCWausdrücklich ausgewählt, statt den Mode unzuverlässig aus dem Band abzuleiten. -
Win-Test-Sked-Übergabe präzisiert: Die QRG muss zum gewählten Band passen. Sichtbare KST-Suffixe werden für das Logziel entfernt, portable Bestandteile bleiben erhalten und die Zeitangaben der
ADDSKED-Pakete werden korrekt erzeugt. Ein Fehler bei der Übergabe entfernt den internen KST4Contest-Sked nicht. -
Exakte Sked-Ziele: Timeline und automatische Erinnerungen verwenden das vollständige sichtbare KST-Rufzeichen. Ein Sked für
DN9APW-2wird nicht versehentlich an eine andere Variante desselben Basisrufzeichens gesendet. -
Beacon und Autoantwort überarbeitet: Beide Chat-Kategorien verwenden einen gemeinsamen Timer, behalten aber getrennte Aktivierungsschalter und Texte. Das zulässige Mindestintervall beträgt eine Minute; Nachrichtentexte sind auf 120 Zeichen begrenzt. Die gespeicherte Beacon-Aktivierung wird beim Start aus der Konfiguration übernommen.
-
Variablen zentral aufgelöst: Nachrichtenvariablen für Beacons, Shortcuts, Snippets und andere automatisch erzeugte Texte werden über einen gemeinsamen Resolver verarbeitet.
-
Nachrichtentabellen verbessert: Abgeschnittene Nachrichtentexte erhalten einen Tooltip mit dem vollständigen Inhalt. Erkannte Webadressen können im Systembrowser geöffnet werden.
-
Kompaktere Filterleiste: Die Filter bleiben bei normaler Breite in einer kompakten Anordnung und werden erst dann umgebrochen, wenn der tatsächlich verfügbare Platz nicht mehr ausreicht. Der mittlere Divider kann dadurch weiter verschoben werden.
-
DXLog-Gesamtlog übernommen: Der UCXLog-kompatible UDP-Listener verarbeitet neben
contactinfoauchcontactreplace. Dadurch kann ein von DXLog.net als vollständiges Log ausgesendeter Datenbestand eingelesen werden. -
Automatische QRG-Übernahme abgesichert:
MYQRGwird nur von einer aktivierten Schnittstelle aktualisiert, die tatsächlich gültigeRadioInfo- beziehungsweise Win-Test-STATUS-Pakete liefert. Eine aktivierte, aber nicht liefernde Quelle ersetzt die notwendige Funktionsprüfung oder manuelle QRG-Pflege nicht. -
Versionserkennung verbessert: Versionsnummern werden semantisch verglichen, damit beispielsweise Patch-Versionen und Nightly-Stände nicht mehr durch eine einfache Fließkommazahl falsch eingeordnet werden.
Behoben
-
Zuverlässige Benutzerliste beim Login: Ungültige oder unvollständige
UA0-Teilnehmerdatensätze werden einzeln verworfen und protokolliert, ohne die Verarbeitung der alphabetisch folgenden Teilnehmer abzubrechen. Die gültigen Einträge werden zunächst pro Kategorie gesammelt und erst mit dem ersten zugehörigenUE-Abschlussframe vollständig veröffentlicht. -
Benutzerliste verschwindet nach dem Login: ON4KST kann nach Namens-, Status- oder anderen Live-Änderungen weitere
UE-Frames für dieselbe Kategorie senden. Wiederholte Abschlussframes werden jetzt erkannt und ignoriert, damit eine bereits gefüllte Benutzerliste nicht durch eine leere Momentaufnahme ersetzt wird. -
Fehlgeschlagener Erstaufbau und Verbindungsverlust: Wenn beim Programmstart keine Verbindung zum Server hergestellt werden kann, läuft KST4Contest nicht mehr in eine Endlos- oder Busy-Wait-Schleife. Die Oberfläche bleibt bedienbar und weitere Versuche erfolgen mit begrenztem Backoff. Auch ein vom Server geschlossener oder über längere Zeit stummer Socket wird zuverlässig erkannt.
-
Messagebus-Protokollierung: Bereits korrekt verarbeitete ON4KST-Frames werden nicht mehr zusätzlich als
Critical, detected unhandled Chatmessagegemeldet. Nur tatsächlich unbekannte Telegramme erreichen noch diesen Logzweig. -
Passwort im Fehlerlog: Das ON4KST-Passwort wird beim Verbindungsaufbau nicht mehr im Klartext in die Konsole oder Logdatei geschrieben.
-
Langzeitfehler der Stationsauswahl: Die vom Message-Thread verwalteten Chatmember wurden von der JavaFX-Ansicht entkoppelt. Gleichzeitige Änderungen der Daten und Tabellenansicht führen dadurch nicht mehr nach längerer Laufzeit zu fehlerhaften Auswahlmodellen oder Concurrent-Modification-Problemen.
-
Keine Phantom-Chatmember durch UM3: Historische oder zusätzliche Servermeldungen erzeugen keine Benutzerlisteneinträge für Stationen, die nicht tatsächlich im Chat angemeldet sind.
-
Nachrichten an Rufzeichen mit Suffix: Mehrere gleichzeitig angemeldete Varianten desselben Basisrufzeichens überschreiben sich nicht mehr gegenseitig. Damit wurde Issue #73 behoben.
-
DX-Cluster-Locatoren: Sender und gemeldete Station erhalten nicht mehr versehentlich denselben Locator. Damit wurde Issue #48 behoben.
-
Worked-Anzeige in „QSO of the other“: Die Worked-Spalten verwenden wieder die jeweils richtige sendende beziehungsweise empfangende Station.
-
Fehlende SECONDAP-Daten: Eine nicht vorhandene zweite Aircraft-Scatter-Gelegenheit führt beim Bearbeiten der Anzeige nicht mehr zu einer ungültigen Textauswahl und JavaFX-Exception.
-
Historische Rufzeichen: Das Hervorheben oder Anklicken eines Rufzeichens, das nicht mehr in der aktuellen Benutzerliste vorhanden ist, läuft nicht mehr in eine Exception.
-
Win-Test-Sked-Zeit und Rufzeichen: Zeitstempel, Band-QRG-Zuordnung sowie die Behandlung von KST-Suffixen und portablen Rufzeichen wurden korrigiert.
-
Filter-Reset: Alle Filterprädikate werden tatsächlich entfernt; der sichtbare Zustand des Buttons entspricht wieder dem wirksamen Filterzustand.
Dokumentation und Auslieferung
-
Das deutsche und englische Handbuch wurde systematisch mit dem Quellcode abgeglichen, erweitert und mit aktuellen Screenshots versehen. Die Dokumentation erklärt nicht nur die Bedienelemente, sondern auch Herleitung, Datenquellen und Grenzen der Funktionen.
-
Für Arch Linux stehen
kst4contest-bin,kst4contestundkst4contest-gitim AUR zur Verfügung. -
Die Downloadseite unterscheidet Stable, Beta und Nightly und bietet die jeweils tatsächlich vorhandenen Pakete für Windows, Linux und macOS an.
-
Nightly-Pakete werden automatisiert aus dem aktuellen
main-Branch gebaut. Stable- und Beta-Releases verwenden reproduzierbare Paketnamen für die unterstützten Plattformen. -
Signierte und notarisierte macOS-Pakete: Die DMG-Dateien für Apple Silicon und Intel sind mit einer Apple Developer ID signiert und von Apple notarisiert; das Notarisierungsticket ist in der DMG hinterlegt. Der erste Start funktioniert damit per Doppelklick, ohne den bisherigen Umweg über Öffnen im Kontextmenü, und die Prüfung gelingt auch ohne Internetverbindung. Betroffen sind Nightly-, Beta- und Stable-Pakete gleichermaßen. Die Windows-Pakete sind weiterhin nicht signiert.
-
Korrekte Bundle-Kennung und Version unter macOS: Die Anwendung meldet sich jetzt als
de.x08.KST4Conteststatt alskst4contest.viewund trägt die tatsächliche Versionsnummer im Bundle. Bisher wies jedes Release im Finder unter Informationen die Version1.0aus. Bestehende Einstellungen sind davon nicht betroffen, da KST4Contest seine Daten in~/.praktiKST/ablegt und nicht an der Bundle-Kennung festmacht.
Bekannte Grenzen
-
Die aktive Geländedatenquelle verwendet Open-Meteo mit Copernicus-GLO-90-Daten und höchstens 100 Höhenpunkten pro Strecke.
-
Der atmosphärische K-Faktor ist derzeit fest auf
4/3eingestellt. -
Für die Gegenstation wird eine Antennenhöhe von 10 Metern über Grund angenommen.
-
Aircraft-Scatter-Daten aus AirScout und die Geländeanalyse der Stationskarte sind weiterhin getrennte Bewertungen.
-
Eine genauere Konfiguration von Stationshöhe, Frequenz und K-Faktor wird in Issue #74 weiterverfolgt.
Die veröffentlichte Version ist als Release v1.42.0 verfügbar.
v1.41.1 (2026-07-08)
Hotfix für Texteingabe und Fokusverhalten
Behoben
- Das Nachrichteneingabefeld wurde nach einiger Zeit beziehungsweise bei bestimmten UI-Aktualisierungen unerwartet geleert.
- Beim Filtern oder Auswählen einer Station wurde der Eingabefokus unbeabsichtigt wieder in das Sendefeld verschoben.
Die korrigierte Version ist als Release v1.41.1 verfügbar.
v1.41.0 (2026-07-01)
Stationskarte, begrenzte Nachrichtenspeicher und bildschirmgerechtes Hauptfenster
Neu
-
Stationskarte: Eine interaktive OpenStreetMap-Karte stellt aktive Chatmember mit brauchbarem Locator geografisch dar.
-
Antennensektor und Verbindungslinie: Die Karte zeigt den aktuellen eigenen QTF, den konfigurierten Antennen-Öffnungswinkel, das maximale QRB und die Verbindung zur ausgewählten Station.
-
Maidenhead-Raster: Ein an die Zoomstufe angepasstes Locator-Raster erleichtert die geografische Einordnung.
-
Geländeprofil: Für ausgewählte Stationen kann ein Höhenprofil über die Open-Meteo Elevation API berechnet werden. Die aktive Datenquelle verwendet Copernicus GLO-90 und höchstens 100 gleichmäßig verteilte Abfragepunkte.
-
Geometrische Streckenanalyse: Die Auswertung berücksichtigt Sichtlinie, Erdkrümmung mit
k = 4/3, Radio- und Geländehorizont, erste Fresnel-Zone und eine grobe Hindernisabschätzung. -
Lokaler Karten-Proxy: Leaflet wird mit der Anwendung ausgeliefert. Kartenkacheln werden über einen lokalen Proxy geladen, damit keine externe JavaScript-Bibliothek zur Laufzeit nachgeladen werden muss. Für die OpenStreetMap-Kacheln und die Online-Höhendaten ist weiterhin eine Internetverbindung erforderlich.
Geändert
-
Begrenzte Nachrichtenspeicher: Die globale Chatnachrichtenliste wird oberhalb von 30.000 Einträgen auf 25.000 verkleinert. Der getrennte DX-Cluster-Speicher wird oberhalb von 10.000 Einträgen auf 8.000 verkleinert.
-
Bildschirmgerechte Startgröße: Das Hauptfenster wird beim Start gegen den sichtbaren Bereich des primären Bildschirms geprüft und bei Bedarf verkleinert oder verschoben.
-
Kompaktere Benutzeroberfläche: Mehrere Bereiche wurden für kleinere Bildschirme und verstellbare Divider angepasst.
Einordnung der Kartenfunktion
Die Stationskarte und AirScout können dieselbe Gegenstation betreffen, führen aber getrennte Berechnungen durch. Aircraft-Scatter-Flugzeuge werden nicht in das Geländeprofil eingerechnet.
Im Quellcode vorhandene Klassen für Copernicus GLO-30, Offline-DEM-Import und weitere Terrain-Provider waren in v1.41 nicht Bestandteil der aktiv verwendeten Berechnungskette. Die tatsächlich verwendete Online-Höhenquelle ist Open-Meteo auf Basis von Copernicus GLO-90.
v1.40 (2026-02-16)
Großes Feature-Release: Score-System, AP-Timeline, Win-Test, PSTRotator
Neu:
- Chatmember Score-System: Jeder Chatmember erhält automatisch eine Prioritätsbewertung anhand von Antennenrichtung, Aktivitätszeit, Nachrichtenanzahl, aktiven Bändern, Frequenzen, Sked-Richtung und anderen Faktoren. Die Top-Kandidaten werden in einer eigenen Liste hervorgehoben.
- AP-Timeline: Für jeden möglichen AP-Ankunftsminuten-Slot werden bis zu 4 hochbewertete Stationen angezeigt, die erreichbar wären. Bevorzugt werden APs mit dem höchsten Potenzial, nicht die schnellste Ankunft. Stationen, auf die die eigene Antenne nicht zeigt, werden transparent dargestellt.
- Win-Test-Unterstützung (ab v1.31 als Beta, jetzt vollständig konfigurierbar): Log-Synchronisation, Frequenzauswertung und Sked-Übergabe via UDP vollständig integriert. In den Preferences aktivier-/deaktivierbar.
- PSTRotator-Interface (ab v1.31 als Beta, jetzt vollständig konfigurierbar): Aktualisierung der Rotatorposition direkt aus KST4Contest. In den Preferences aktivier-/deaktivierbar.
- QSO-Sniffer: Nachrichten von konfigurierbaren Rufzeichen-Listen werden automatisch in das PM-Fenster weitergeleitet.
- Band-Alert bei gearbeiteten Stationen: Wenn eine Station geloggt wird, erscheint ein Hinweis, wenn diese Station ein weiteres Band aktiv hat, auf dem man selbst ebenfalls QRV ist.
- Sked-Erinnerungs-ALERT: Pro Chatmember kann ein Sked-Alarm mit automatischen Nachrichten in konfigurierbaren Intervallen (2+1 / 5+2+1 / 10+5+2+1 Minuten vor dem Sked) eingerichtet werden, plus akustische und optische Benachrichtigung.
- Chat-Historie beim Start laden: Beim Verbindungsaufbau wird die Serverhistorie geladen, um aktive Chatmember und letzte Nachrichten sofort sichtbar zu machen.
- Skedfail-Button: Im FurtherInfo-Panel kann ein Sked-Misserfolg für einen Chatmember markiert werden, was dessen Score senkt.
Geändert:
- AP-Notizen in DX-Cluster-Spots integriert.
- Scrolling der Chatmember-Tabelle folgt automatisch der aktuellen Nachrichtenauswahl.
- Generic Auto-Antwort und QRG-Auto-Antwort senden max. einmal pro 45 Sekunden pro Rufzeichen (verhindert Spam-Schleifen).
- Speicherbare Einstellungen erweitert: ServerDNS/Port, PSTRotator-Interface, Win-Test-Interface, Callsign-Sniffer, Dark-Mode-Standard.
- Datum in der Chat-Tabelle entfernt (nur Uhrzeit verbleibt – spart Platz).
Behoben:
- Benutzerliste wird jetzt bei jedem Neu-Login automatisch sortiert.
- Posonpill-Nachrichten beenden jetzt nur genau eine Client-Instanz (nicht alle und nicht wtKST).
- wtKST: Absturz bei KST4Contest-Trennung behoben.
- Mehrere Probleme mit Rufzeichen-Suffixen wie
/p,-2etc. behoben. QTFDefaultwurde nicht korrekt gespeichert → behoben.- AirScout-Watchlist (ASWATCHLIST) wurde nicht korrekt aktualisiert → behoben.
- Dark Mode: QRG-Felder wurden nicht vollständig angezeigt → behoben.
- Versionsnummer-Anzeige korrigiert.
v1.31 (2025-12-13)
Win-Test + PSTRotator Beta, QSO-Sniffer, DNS-Hotfix
Neu:
- Win-Test-Unterstützung (Beta, noch nicht deaktivierbar): Log-Synchronisation und Frequenzauswertung.
- PSTRotator-Unterstützung (Beta, noch nicht deaktivierbar).
- QSO-Sniffer: Nachrichten von konfigurierbaren Rufzeichen werden ins PM-Fenster weitergeleitet.
Geändert:
- DNS-Server geändert: Von
www.on4kst.infoaufwww.on4kst.org(Hotfix). Der DNS-Server ist ab sofort in den Preferences änderbar.
Behoben:
- Endlosschleife im Fehlerfall friert den Client ein → behoben.
v1.266 (2025-10-03)
AirScout-Fix für Rufzeichen mit Suffix
Behoben:
- AirScout-Interface funktionierte nicht, wenn das Login-Rufzeichen einen Suffix enthielt (z. B.
9A1W-2). AirScout kann mit diesem Format nicht umgehen – es wird jetzt nur noch das Basis-Rufzeichen ohne Suffix an AirScout übergeben.
(Fehler gemeldet und getestet von 9A2HM / Kreso – herzlichen Dank!)
v1.265 (2025-09-28)
Richtungs-Buttons bleiben aktiviert eingefärbt
Behoben:
- Richtungs-Buttons (N / NE / E usw.) behalten jetzt ihre Farbe, wenn sie aktiviert sind, sodass der Aktivierungsstatus auf einen Blick erkennbar ist.
v1.264 (2025-08-02)
Simplelogfile: Rufzeichen-Erkennung verbessert
Behoben:
- Rufzeichen wie
S53CC,S51Ausw. wurden in der SimpleLogFile-Auswertung nicht als gearbeitet markiert → Erkennungsmuster verbessert.
(Fehler gemeldet von Boris, S53CC – danke!)
v1.263 (2025-06-08)
AirScout-Kommunikation und Login-Name
Geändert:
- AirScout-Kommunikation grundlegend überarbeitet: Nur noch Stationen mit QRB < max-QRB werden an AirScout gesendet.
- Abfrage-Intervall von 12 Sekunden auf 60 Sekunden erhöht.
- Deutlich weniger Berechnungsaufwand und Nachrichtenverkehr → Stabileres AirScout-Tracking.
- Name des AS-Clients und AS-Servers ist jetzt aus den Preferences konfigurierbar (war vorher hartcodiert auf „KST" / „AS").
Behoben:
- „Track in AirScout"-Button war sehr träge → durch neue Kommunikationslogik deutlich verbessert.
- Name im Chat ist jetzt speicherbar (Fehler behoben).
- Visuelle Korrekturen vor und nach dem Login.
- Fehler behoben, der von 9A2HM (Kreso) gemeldet wurde.
v1.262 (2025-05-21)
Freeze-Fix bei vorzeitiger Nachrichtenlieferung
Behoben:
- ON4KST liefert manchmal Nachrichten, bevor der Login abgeschlossen ist. Das verursachte Fehler in der Nachrichtenverarbeitung → jetzt behoben.
v1.26 (2025-05)
Multi-Channel-Login und Dark Mode
Neu:
- Dark Mode: Umschaltbar über
Window → Use Dark Mode. - Multi-Channel-Login: Gleichzeitiger Login in zwei Chat-Kategorien.
- Opposite Station Multi-Callsign Login-Tagging: Unterstützung für Stationen mit mehreren Rufzeichen.
Geändert:
- Farbgebungs-Mechanismus überarbeitet: Farben können jetzt über CSS angepasst werden.
Behoben:
- Stationsmarkierung komplett überarbeitet und korrekt gestellt.
v1.251 (2025-02)
Bugfix für UDP-Broadcast-Spot-Info
Behoben:
- Problem beim Lesen von UDP-Broadcast-Spot-Informationen behoben (gemeldet von Steve Clements – danke!).
- Stationsmarkierung (erneut verbessert).
v1.25 (2025-02)
Wunschliste umgesetzt
Neu:
- Neuer Einstellungs-Tab: Messagehandling
- Auto-Antwort auf eingehende Nachrichten konfigurierbar.
- Automatische Antwort mit eigener CQ-QRG, wenn jemand danach fragt.
- Konfigurierbarer Standard-Filter für das Userinfo-Fenster (für Gianluca :-) ).
- Farbige PM-Zeilen: Neue Privatnachrichten erscheinen rot und faden alle 30 Sekunden über Gelb bis Weiß ab (Idee von IU3OAR, Gianluca).
Behoben:
- Stationen mit Suffixen wie „-2" und „-70" wurden nicht als gearbeitet markiert → werden jetzt ignoriert, Station wird korrekt markiert.
v1.24 (2024-11)
Wunschliste + DX-Cluster-Spots
Neu:
- Button zum Öffnen des QRZ.com-Profils der ausgewählten Station.
- Button zum Öffnen des QRZ-CQ-Profils der ausgewählten Station.
- DX-Cluster-Server-Integration: Richtungs-Warnungen werden als Spots an das Logprogramm gesendet (wenn QRG bekannt).
(Zusätzlich wurden Farbgebungen der PM-Zeilen hinzugefügt – tnx Gianluca)
v1.23 (2024-10)
Integrierter DX-Cluster-Server
Neu:
- KST4Contest enthält jetzt einen integrierten DX-Cluster-Server.
- Generiert DX-Cluster-Spots und sendet sie an das Logprogramm, wenn eine Richtungs-Warnung ausgelöst und eine QRG bekannt ist.
- Spotter-Rufzeichen muss sich vom Contest-Rufzeichen unterscheiden (für korrekte Filterung im Logprogramm).
(Idee von OM0AAO, Viliam Petrik – danke!)
v1.22 (2024-05)
Usability-Verbesserungen und AirScout-Button-Fix
Neu:
- Neue Variablen (tnx OM0AAO, Viliam Petrik):
MYLOCATORSHORTMYQRGSHORTQRZNAME
Geändert:
- Sendfeld-Fokus: Nach Klick auf Rufzeichen in der Benutzerliste erhält das Sendfeld sofort den Fokus – kein Doppelklick notwendig (tnx Gianluca).
Behoben:
- Worked-Station-Filter ist jetzt live-aktiv: Gearbeitete Stationen verschwinden sofort nach Aktivierung des Filters (tnx Gianluca).
- QRB-Sortierung war lexikografisch → jetzt numerisch (tnx Alessandro Murador).
- AirScout-„Show Path"-Button: Klick maximiert AirScout und zeigt den Pfad korrekt an.
v1.21 (2024-04)
Usability-Verbesserungen
Geändert:
- Fenstergrößen und Divider-Positionen werden beim Klick auf „Save Settings" in der Konfigurationsdatei gespeichert und beim Start wiederhergestellt.
- Filter-Bereich als Flowpane → bessere Darstellung auf kleineren Bildschirmen.
v1.2 (2024-04)
Bandselektion und NOT-QRV-Tags
Neu:
- Bandselektion: In den Preferences auswählbar, welche Bänder aktiv sind. Nur für gewählte Bänder erscheinen Buttons und Felder in der UI. Speichern und Neustart erforderlich.
- NOT-QRV-Tags pro Station und Band: Stationen können für jedes Band als „nicht QRV" markiert werden. Kombinierbar mit dem Userlist-Filter.
- QTF-Pfeil: Der „Show path in AS"-Button zeigt jetzt einen Pfeil mit dem QTF der ausgewählten Station an.
Frühere Versionen
v1.1
Erste öffentlich veröffentlichte Version. Grundfunktionen:
- Worked-Markierung via Simplelogfile und UDP
- Sked-Richtungs-Hervorhebung
- QRG-Erkennung
- Text-Snippets und Shortcuts
- AirScout-Interface (erste Version)
- Intervall-Beacon
- PM-Abfang für öffentliche Nachrichten mit eigenem Rufzeichen
- Update-Hinweis-Dienst
Geplante Features
Lebensdauer für den Worked-Status (automatisches Zurücksetzen)✅ Umgesetzt in v1.40 (3-Tage-Lebensdauer, kein manuelles Zurücksetzen mehr nötig)- Filterung des „Cluster & QSO der anderen"-Fensters auf eigenes QTF
- Weitere Topografie-basierte Berechnungen für die Richtungswarnung