mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-08-03 17:05:20 +02:00
Refactored QRG recognition (added some band context to increase the quality of the values + changed cluster fallback-band-value to dropdown switch + normalizing qrg values)
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 84 KiB |
@@ -31,10 +31,14 @@ Die zentrale Tabelle aller aktuell aktiven Chat-Nutzer. Spalten (je nach Konfigu
|
||||
| Loc | Maidenhead-Locator |
|
||||
| QRB | Entfernung in km |
|
||||
| QTF | Richtung in Grad |
|
||||
| QRG | Automatisch erkannte Frequenz |
|
||||
| QRG | Zuletzt aus einer Chat-Nachricht erkannte Frequenz |
|
||||
| AP | AirScout-Flugzeugdaten (wenn aktiv) |
|
||||
| Band-Farben | Worked/NOT-QRV-Status pro Band |
|
||||
|
||||
Die QRG-Spalte zeigt die zuletzt für eine Station erkannte Frequenz. Fehlende Nullen werden für die Anzeige ergänzt, sodass beispielsweise `144.21` als `144.210` erscheint. Erkennt KST4Contest nacheinander Frequenzen auf mehreren Bändern, zeigt die Spalte den letzten Treffer; die internen Bandinformationen können trotzdem mehrere aktuelle Bänder der Station enthalten.
|
||||
|
||||
Relative Angaben werden zunächst mit einem höchstens 30 Minuten alten Bandkontext desselben Absenders kombiniert. Nur wenn dieser fehlt, verwendet KST4Contest das globale Fallback-Band. Erkennungsregeln, Beispiele und Grenzen: [QRG-Erkennung](de-Funktionen#qrg-erkennung).
|
||||
|
||||
**Sortierung**: Klick auf Spaltenköpfe. QRB-Sortierung arbeitet numerisch (ab v1.22 korrigiert).
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,12 @@ Versionsverlauf von KST4Contest / PraktiKST.
|
||||
|
||||
letzter Changelog bitte aus GitHub entnehmen. Der bisherige Changelog
|
||||
|
||||
## v1.42 (2026-08)
|
||||
- **QRG-Erkennung präzisiert**: Vollständige und relative Frequenzangaben werden weiterhin erkannt. Nackte dreistellige Zahlen werden nur noch mit erkennbarem Frequenzkontext ausgewertet, damit Signalrapporte, Bandangaben und andere Zahlen keine falsche QRG erzeugen.
|
||||
- **Stationsbezogener Bandkontext**: Bei relativen Frequenzen verwendet KST4Contest zuerst einen höchstens 30 Minuten alten Bandkontext desselben Absenders. Erst danach greift das globale Fallback-Band.
|
||||
- **Fallback-Band als Dropdown**: Das globale Fallback kann nur noch aus den tatsächlich unterstützten Bändern ausgewählt werden und gilt für die gesamte QRG-Erkennung, nicht nur für DX-Cluster-Spots.
|
||||
- **QRG-Anzeige vereinheitlicht**: Frequenzen werden in der Benutzerliste und den Nachrichtentabellen mit mindestens drei Nachkommastellen dargestellt.
|
||||
|
||||
## v1.41
|
||||
**Stationskarte, Performance, Reaktionsfähiges UI**
|
||||
|
||||
|
||||
@@ -53,35 +53,51 @@ Das Verfahren berücksichtigt weder Gelände noch aktuelle Ausbreitungsbedingung
|
||||
|
||||
## Welche Frequenz wird verwendet?
|
||||
|
||||
Vollständige Frequenzangaben können direkt verarbeitet werden, beispielsweise:
|
||||
Ein DX-Cluster-Spot benötigt eine eindeutige Frequenz. KST4Contest verwendet dafür dieselbe QRG-Erkennung wie die Benutzerliste und die übrigen bandbezogenen Funktionen.
|
||||
|
||||
Vollständige Frequenzen bestimmen ihr Band direkt:
|
||||
|
||||
```text
|
||||
144.205
|
||||
432.088
|
||||
432,088
|
||||
1296.338
|
||||
10368.100
|
||||
```
|
||||
|
||||
Im Chat werden jedoch häufig nur relative Angaben geschrieben:
|
||||
Relative Angaben enthalten dagegen nur den Frequenzanteil innerhalb eines Bandes:
|
||||
|
||||
```text
|
||||
205
|
||||
.205
|
||||
338
|
||||
,205
|
||||
qrg 205
|
||||
freq is 205
|
||||
on 205
|
||||
205 MHz
|
||||
```
|
||||
|
||||
In diesem Fall fehlt das Band. KST4Contest ergänzt deshalb das unter **Fallback band in MHz** konfigurierte Bandpräfix.
|
||||
Eine nackte dreistellige Zahl wie `205` wird ohne Frequenzkontext nicht ausgewertet. Dasselbe gilt für `599`, `144` oder Formulierungen wie `worked 210 stations`. So verhindert KST4Contest, dass Signalrapporte, Bandnamen oder Zählwerte als scheinbar plausible QRG gespeichert und später an den Logger weitergegeben werden.
|
||||
|
||||
Bei einer relativen QRG wird das Band in dieser Reihenfolge bestimmt:
|
||||
|
||||
1. KST4Contest prüft, ob für denselben Absender innerhalb der letzten 30 Minuten bereits ein passender Bandkontext bekannt wurde.
|
||||
2. Sind mehrere aktuelle Bänder bekannt, wird der zuletzt aktualisierte plausible Kontext verwendet.
|
||||
3. Erst wenn kein geeigneter Stationskontext vorhanden ist, verwendet KST4Contest das unter **Fallback band for relative QRG detection** ausgewählte Band.
|
||||
|
||||
Beispiel:
|
||||
|
||||
```text
|
||||
Fallback-Band: 144
|
||||
Chat-Frequenz: .205
|
||||
DX-Cluster-Frequenz: 144205.0 kHz
|
||||
Globales Fallback: 144 MHz
|
||||
Letzte vollständige QRG der Station: 432.088 MHz
|
||||
Neue Chat-Angabe derselben Station: .100
|
||||
Erkannte QRG: 432.100 MHz
|
||||
DX-Cluster-Frequenz: 432100.0 kHz
|
||||
```
|
||||
|
||||
Bei einem Einband-Contest ist diese Annahme normalerweise eindeutig. Bei gleichzeitigem Betrieb mehrerer Bänder kann sie falsch sein. Das Fallback-Band sollte deshalb zu dem Band passen, das in der betreffenden Chat-Kategorie überwiegend verwendet wird.
|
||||
Ohne den aktuellen 432-MHz-Kontext würde dieselbe Angabe mit dem globalen Fallback zu `144.100 MHz` ergänzt.
|
||||
|
||||
Die weitergehende Frage, ob sich das Band künftig aus der konkreten Arbeitsfrequenz oder dem Stationskontext ableiten lässt, wird nach Abschluss des Manuals gesondert geprüft.
|
||||
Die QRG-Erkennung läuft vor der Richtungs- und Spotprüfung. Nennt eine Station ihre Frequenz erstmals in der gerichteten Nachricht, die zugleich eine Richtungsgelegenheit auslöst, kann bereits der daraus erzeugte Spot diese Frequenz enthalten. War zuvor eine andere QRG der Station bekannt, wird sie durch die neu erkannte Angabe aktualisiert.
|
||||
|
||||
Das Fallback-Band ist eine globale Einstellung der QRG-Erkennung. Seine Wirkung ist nicht auf den DX-Cluster beschränkt. Konfiguration, unterstützte Bänder und weitere Folgen sind unter [Fallback-Band für relative QRG-Erkennung](de-Konfiguration#fallback-band-für-relative-qrg-erkennung) beschrieben.
|
||||
|
||||
---
|
||||
|
||||
@@ -95,7 +111,7 @@ Konfiguriere anschließend:
|
||||
|
||||
1. **Enable the local DX Cluster server …** aktivieren.
|
||||
2. Einen freien **TCP port** eintragen. Standard ist `8000`.
|
||||
3. Das passende **Fallback band in MHz** eintragen.
|
||||
3. Unter **Fallback band for relative QRG detection** das passende Band auswählen.
|
||||
4. Ein **Spotter callsign** festlegen.
|
||||
|
||||
Für das Spotter-Rufzeichen sollte nach Möglichkeit ein anderes Rufzeichen als das Contest-Rufzeichen verwendet werden. Einige Logger filtern Spots, die scheinbar von der eigenen Station stammen. Das Ergebnis wäre technisch korrekt erzeugt, aber in der Bandmap trotzdem unsichtbar – eine besonders unproduktive Art von Erfolg.
|
||||
@@ -189,7 +205,9 @@ KST4Contest sendet absichtlich nicht jede gefundene Frequenz an den Logger. Ande
|
||||
|
||||
### Der Spot erscheint auf dem falschen Band
|
||||
|
||||
Prüfe zuerst das konfigurierte **Fallback band in MHz**. Es wird nur benötigt, wenn im Chat keine vollständige Frequenz angegeben wurde.
|
||||
Prüfe zuerst, welche Frequenzen für die betreffende Station innerhalb der letzten 30 Minuten erkannt wurden. Bei einer relativen Angabe hat dieser Stationskontext Vorrang vor dem globalen Fallback.
|
||||
|
||||
Ist kein aktueller Stationskontext vorhanden, prüfe die Auswahl unter **Fallback band for relative QRG detection**. Das Fallback wird nur benötigt, wenn sich das Band weder aus einer vollständigen Frequenz noch aus dem aktuellen Kontext des Absenders ergibt.
|
||||
|
||||
### Der Spot wird vom Logger ausgeblendet
|
||||
|
||||
|
||||
@@ -70,16 +70,54 @@ Einrichtung, Frequenzbehandlung und Grenzen: [Integrierter DX-Cluster-Server](de
|
||||
|
||||
---
|
||||
|
||||
## QRG-Erkennung (QRG Reading)
|
||||
## QRG-Erkennung
|
||||
|
||||
KST4Contest verarbeitet jede Chat-Nachricht und extrahiert automatisch **Frequenzangaben**. Diese werden in der Benutzerliste in der **QRG-Spalte** angezeigt.
|
||||
Im ON4KST-Chat werden Frequenzen selten einheitlich geschrieben. Eine Station nennt beispielsweise zuerst `432.088`, später nur noch `.100` und in einer weiteren Nachricht `qrg 120`. Für einen Menschen ist der Zusammenhang meistens klar. Ein Programm muss dagegen unterscheiden, ob `120` eine Frequenz, eine Zeitangabe, eine Entfernung oder etwas völlig anderes bedeutet.
|
||||
|
||||
Erkannte Formate: `144.205`, `432.088`, `.205` (mit konfigurierter Bandannahme), etc.
|
||||
KST4Contest wertet deshalb den Text jeder öffentlichen und gerichteten Chat-Nachricht aus. Eine erkannte QRG wird dem Absender zugeordnet und in der **QRG-Spalte** der Benutzerliste angezeigt. Die Spalte enthält die zuletzt erkannte Frequenz und stellt mindestens drei Nachkommastellen dar. Ein intern als `144.21` gespeicherter Wert erscheint damit als `144.210`.
|
||||
|
||||
**Nutzen**: Ohne nachzufragen kann man direkt auf die QRG einer Station schauen und entscheiden, ob eine Verbindung möglich ist.
|
||||
### Welche Angaben werden erkannt?
|
||||
|
||||
| Schreibweise | Beispiel | Verarbeitung |
|
||||
|---|---|---|
|
||||
| Vollständige Frequenz | `144.210`, `432,088`, `10368.100` | Das Band ergibt sich direkt aus der Frequenz. |
|
||||
| Relative Frequenz mit Punkt oder Komma | `.210`, `,088` | Das Band wird aus dem Stationskontext oder dem konfigurierten Fallback ergänzt. |
|
||||
| Dreistellige Frequenz mit Textkontext | `qrg 210`, `freq is 210`, `on 210`, `210 MHz` | Die Zahl wird als relative Frequenz behandelt. |
|
||||
| Dreistellige Zahl ohne Frequenzkontext | `210`, `599`, `144` | Die Zahl wird absichtlich nicht als QRG übernommen. |
|
||||
|
||||
Die letzte Einschränkung verhindert plausible, aber falsche Ergebnisse. Mit einem Fallback von `144 MHz` ließe sich ein Signalrapport `599` technisch problemlos zu `144.599 MHz` zusammensetzen. Das Ergebnis wäre formal gültig und fachlich trotzdem Unsinn.
|
||||
|
||||
### Wie wird das Band einer relativen QRG bestimmt?
|
||||
|
||||
KST4Contest verwendet folgende Reihenfolge:
|
||||
|
||||
1. Wurde für denselben Absender innerhalb der letzten 30 Minuten bereits eine passende vollständige Frequenz erkannt, verwendet KST4Contest deren Band.
|
||||
2. Sind mehrere aktuelle Bänder bekannt, wird der zuletzt aktualisierte plausible Bandkontext verwendet.
|
||||
3. Fehlt ein geeigneter Stationskontext, verwendet KST4Contest das unter **Fallback band for relative QRG detection** ausgewählte Band.
|
||||
|
||||
Beispiel: Das globale Fallback steht auf `144 MHz`. Eine Station nennt zunächst `432.088` und schreibt wenige Minuten später `.100`. KST4Contest ergänzt nicht das globale Fallback, sondern den aktuelleren Stationskontext. Das Ergebnis ist `432.100 MHz`. Schreibt eine andere Station ohne vorherige Bandinformation `.100`, wird daraus `144.100 MHz`.
|
||||
|
||||
Das Fallback-Band ist damit tatsächlich nur der letzte Ausweg. Es wird aus den von KST4Contest unterstützten Bandwerten ausgewählt und wirkt auf die gesamte QRG-Erkennung – nicht nur auf den integrierten DX-Cluster.
|
||||
|
||||
### Wofür wird die erkannte QRG verwendet?
|
||||
|
||||
Die zuletzt erkannte Frequenz erscheint in der Benutzerliste. Der zugehörige Bandkontext kann außerdem in weitere Funktionen einfließen, beispielsweise in:
|
||||
|
||||
- die Erkennung aktiver Bänder einer Station,
|
||||
- den Chatmember-Score und die Prioritätslisten,
|
||||
- Band-Upgrade-Hinweise nach einem Logeintrag,
|
||||
- die Frequenzwahl bei Skeds,
|
||||
- einen DX-Cluster-Spot aus einer erkannten Richtungsgelegenheit.
|
||||
|
||||
Steht die QRG erstmals in der Nachricht, die zugleich eine Richtungsgelegenheit auslöst, wird sie vor der Richtungs- und Spotprüfung verarbeitet. Der daraus erzeugte Spot kann deshalb bereits die Frequenz dieser Nachricht verwenden.
|
||||
|
||||
Die Erkennung bleibt eine Textauswertung. KST4Contest kann nicht beweisen, dass die Station noch auf der genannten Frequenz arbeitet oder ob sich eine mehrdeutige Angabe auf einen anderen Zusammenhang bezieht. Genau deshalb werden nackte dreistellige Zahlen ohne Frequenzkontext nicht mehr übernommen.
|
||||
|
||||
Konfiguration und unterstützte Fallback-Bänder: [Fallback-Band für relative QRG-Erkennung](de-Konfiguration#fallback-band-für-relative-qrg-erkennung).
|
||||
|
||||
Verwendung in der Bandmap eines Logprogramms: [Integrierter DX-Cluster-Server](de-DX-Cluster-Server).
|
||||
|
||||
---
|
||||
|
||||
## Worked-Markierung
|
||||
|
||||
Gearbeitete Stationen werden in der Benutzerliste visuell markiert – pro Band. Grundlage ist die [Log-Synchronisation](de-Log-Synchronisation) via UDP oder Simplelogfile.
|
||||
|
||||
@@ -113,23 +113,47 @@ Die drei Audiofunktionen arbeiten unabhängig voneinander:
|
||||
|
||||
CW- und Sprachausgabe können gleichzeitig aktiviert werden. Das ist technisch möglich, im Contest aber nicht zwingend hilfreich. In der Praxis sollte nur die Ausgabe eingeschaltet werden, die im eigenen Stationsbetrieb tatsächlich wahrgenommen werden kann, ohne den Operator dauerhaft zu beschäftigen.
|
||||
|
||||
### Fallback-Band für relative QRG-Erkennung
|
||||
|
||||
Das Dropdown **Fallback band for relative QRG detection** legt fest, welches Band KST4Contest verwendet, wenn eine relative QRG keinem aktuellen Stationskontext zugeordnet werden kann.
|
||||
|
||||
Zur Auswahl stehen ausschließlich die vom Frequenzparser unterstützten Bandpräfixe:
|
||||
|
||||
```text
|
||||
144 MHz
|
||||
432 MHz
|
||||
1296 MHz
|
||||
2320 MHz
|
||||
3400 MHz
|
||||
5760 MHz
|
||||
10368 MHz (10G)
|
||||
24048 MHz (24G)
|
||||
```
|
||||
|
||||
Das Dropdown ist kein Filter und keine Vorgabe für vollständig angegebene Frequenzen. `432.088` wird unabhängig von der Auswahl als Frequenz im 432-MHz-Band erkannt. Benötigt wird das Fallback bei relativen Angaben wie `.205`, `,205` oder `qrg 205`.
|
||||
|
||||
Bevor KST4Contest auf das Fallback zurückgreift, prüft es den Bandkontext des Absenders. Wurde für dieselbe Station innerhalb der letzten 30 Minuten bereits eine passende vollständige Frequenz erkannt, hat dieses Band Vorrang. Ein Fallback von `144 MHz` macht aus `.100` daher `432.100 MHz`, wenn die Station kurz zuvor beispielsweise `432.088` genannt hat.
|
||||
|
||||
Die Einstellung befindet sich im Notification-Bereich, wirkt aber auf die gesamte QRG-Erkennung. Damit beeinflusst sie nicht nur mögliche DX-Cluster-Spots, sondern auch die QRG-Spalte, erkannte aktive Bänder, Priorisierung, Band-Upgrade-Hinweise und Funktionen, die eine bekannte Stationsfrequenz verwenden.
|
||||
|
||||
Mehr zur Erkennungslogik und zu absichtlich ignorierten Zahlen: [QRG-Erkennung](de-Funktionen#qrg-erkennung).
|
||||
|
||||
### Local DX Cluster output
|
||||
|
||||
KST4Contest kann erkannte Richtungsgelegenheiten als DX-Cluster-Spots an ein Logprogramm weitergeben. Der praktische Nutzen liegt auf der Hand: Eine im Chat erkannte Frequenz erscheint direkt in der Bandmap des Logprogramms und muss nicht erst von Hand übertragen werden.
|
||||
KST4Contest kann erkannte Richtungsgelegenheiten als DX-Cluster-Spots an ein Logprogramm weitergeben. Eine im Chat erkannte Frequenz erscheint dadurch direkt in der Bandmap des Logprogramms und muss nicht erst von Hand übertragen werden.
|
||||
|
||||
Die Checkbox **Enable the local DX Cluster server …** startet beziehungsweise beendet den lokalen TCP-Server. Bei einer laufenden Chat-Verbindung wird die Änderung sofort wirksam.
|
||||
|
||||
Folgende Einstellungen sind erforderlich:
|
||||
Folgende Einstellungen und Schaltflächen gehören zur lokalen DX-Cluster-Ausgabe:
|
||||
|
||||
- **TCP port**: Port, auf dem KST4Contest Verbindungen von DX-Cluster-Clients annimmt. Der Standardwert ist `8000`. Wird der Port während einer laufenden Verbindung geändert, startet KST4Contest den Server auf dem neuen Port neu. Der Logger muss sich anschließend ebenfalls mit dem neuen Port verbinden.
|
||||
- **Fallback band in MHz**: Bandpräfix für relative Frequenzangaben. Aus `205` oder `.205` wird bei einem Fallback-Band von `144` die Frequenz `144.205 MHz`. Vollständige Angaben wie `432.205` oder `1296.338` benötigen diesen Fallback nicht.
|
||||
- **Fallback band for relative QRG detection**: Das oben beschriebene globale Fallback-Band. Der Testspot verwendet `.300` dieses Bandes. Reale Spots verwenden dagegen die für den jeweiligen Absender erkannte QRG.
|
||||
- **Spotter callsign**: Rufzeichen, das im erzeugten DX-Cluster-Spot als Spotter erscheint. Hier sollte ein anderes Rufzeichen als das im Contest verwendete Stationsrufzeichen eingetragen werden. Einige Logprogramme filtern Spots des eigenen Rufzeichens oder behandeln sie anders als fremde Spots.
|
||||
- **Send test spot**: Sendet einen Testspot für `DL0TEST` auf `.300` des eingestellten Fallback-Bandes. Der Test funktioniert nur, wenn KST4Contest mit dem Chat verbunden, der lokale DX-Cluster-Server aktiviert und mindestens ein DX-Cluster-Client verbunden ist.
|
||||
- **Send test spot**: Sendet einen Testspot für `DL0TEST` auf `.300` des ausgewählten Fallback-Bandes. Der Test funktioniert nur, wenn KST4Contest mit dem Chat verbunden, der lokale DX-Cluster-Server aktiviert und mindestens ein DX-Cluster-Client verbunden ist.
|
||||
|
||||
KST4Contest erzeugt nicht bei jeder im Chat gefundenen Frequenz automatisch einen Spot. Ein Spot entsteht nur dann, wenn eine gerichtete Nachricht zwischen zwei Stationen auf eine für die eigene Station interessante Antennenrichtung schließen lässt und für den Absender eine nutzbare Frequenz bekannt ist.
|
||||
|
||||
Die vollständige Herleitung und die Einrichtung des Logprogramms sind im Kapitel [Integrierter DX-Cluster-Server](de-DX-Cluster-Server) beschrieben.
|
||||
|
||||
### Band-Upgrade-Hinweis nach einem Logeintrag
|
||||
|
||||
Nach einem über UCXLog oder Win-Test empfangenen Logeintrag kann KST4Contest prüfen, ob die gerade gearbeitete Station auf einem weiteren gemeinsamen, aber noch nicht gearbeiteten Band aktiv ist.
|
||||
|
||||
@@ -46,6 +46,49 @@ public class MessageBusManagementThread extends Thread {
|
||||
private final String PTRN_QRG_CAT2 = "(([0-9]{3,4}[\\.|,| ]?[0-9]{3})([\\.|,][\\d]{1,2})?)|(([a-zA-Z][0-4]{1}[\\d]{2}\\b)([\\.|,][\\d]{1,2}\\b)?)|((\\b[0-4]{1}[\\d]{2}\\b)([\\.|,][\\d]{1,2}\\b)?)";
|
||||
private final String PTRN_QRG_CAT3 = "(([0-9]{3,5}[\\.|,| ]?[0-9]{3})([\\.|,][\\d]{1,2})?)|(([a-zA-Z][0-4]{1}[\\d]{2}\\b)([\\.|,][\\d]{1,2}\\b)?)|((\\b[0-4]{1}[\\d]{2}\\b)([\\.|,][\\d]{1,2}\\b)?)";
|
||||
|
||||
/*
|
||||
* Frequency formats handled by the smart parser:
|
||||
*
|
||||
* Group 1: full frequencies, for example 144.210 or 10368.100
|
||||
* Group 2: relative frequencies with a separator, for example .210 or ,210
|
||||
* Group 3: bare three-digit values, for example 210
|
||||
*
|
||||
* Group 3 is deliberately subjected to an additional context check. Without
|
||||
* that check, ordinary chat values such as 599 or a bare band name such as 144
|
||||
* would be converted into plausible but incorrect frequencies.
|
||||
*/
|
||||
private static final Pattern SMART_FREQUENCY_PATTERN = Pattern.compile(
|
||||
"(?<![\\d])(\\d{3,5}[.,]\\d{1,3}(?:[.,]\\d{1,3})?)(?![\\d])"
|
||||
+ "|(?<![\\d])([.,]\\d{3}(?:[.,]\\d{1,3})?)(?![\\d])"
|
||||
+ "|(?<=\\s|^)(\\d{3})(?=\\s|$)"
|
||||
);
|
||||
|
||||
/*
|
||||
* A bare three-digit value is accepted only when the nearby text makes its
|
||||
* meaning sufficiently clear. Examples:
|
||||
*
|
||||
* qrg 210
|
||||
* QRG: 210
|
||||
* freq is 210
|
||||
* on 210
|
||||
* pse 210
|
||||
* at 210
|
||||
* 210 MHz
|
||||
* 210 qrg
|
||||
*/
|
||||
private static final Pattern BARE_FREQUENCY_PREFIX_CONTEXT_PATTERN =
|
||||
Pattern.compile(
|
||||
"(?i)\\b(?:qrg|freq(?:uency)?|on|pse|at)\\b"
|
||||
+ "\\s*(?:is\\s*)?[:=@-]?\\s*$"
|
||||
);
|
||||
|
||||
private static final Pattern BARE_FREQUENCY_SUFFIX_CONTEXT_PATTERN =
|
||||
Pattern.compile(
|
||||
"(?i)^\\s*(?:mhz|qrg|freq(?:uency)?)\\b"
|
||||
);
|
||||
|
||||
private static final int BARE_FREQUENCY_CONTEXT_CHARACTERS = 32;
|
||||
|
||||
|
||||
// ==== Auto-answer flood/ping-pong protection ====
|
||||
private static final String AUTOANSWER_PREFIX = ApplicationConstants.AUTOANSWER_PREFIX;
|
||||
@@ -200,145 +243,220 @@ public class MessageBusManagementThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* Smart Frequency Parser (V1.32)
|
||||
* Replaces the old RegEx logic.
|
||||
* Features:
|
||||
* 1. Handles full frequencies (144.210) and short forms (.210, 210).
|
||||
* 2. Handles extended precision/weird formatting (144.210.10, 144,210,10).
|
||||
* 3. Prioritizes USER CONTEXT (History) over GLOBAL CONTEXT (Preferences).
|
||||
* Detects complete and relative frequencies in a chat message and stores the
|
||||
* result on the sender.
|
||||
*
|
||||
* <p>Complete frequencies determine their band directly. Relative frequencies
|
||||
* first use the sender's most recent band context if that context is not older
|
||||
* than 30 minutes. Only when no suitable sender context exists does the parser
|
||||
* use the globally configured fallback band.</p>
|
||||
*
|
||||
* <p>A relative value beginning with a dot or comma is sufficiently explicit
|
||||
* on its own. A bare three-digit value is ambiguous and is therefore accepted
|
||||
* only with nearby frequency-related text.</p>
|
||||
*
|
||||
* @param message message whose text is inspected
|
||||
* @param prefs preferences containing the global fallback band
|
||||
*/
|
||||
private void smartFrequencyExtraction(ChatMessage message, ChatPreferences prefs) {
|
||||
|
||||
// Regex Explanation:
|
||||
// Part 1 (Full): Start (not digit), 3-5 digits, sep, 1-3 digits, OPTIONAL (sep, 1-3 digits)
|
||||
// Matches: 144.210, 144.210.10, 10368.100
|
||||
// Part 2 (Short1): Start (not digit), sep, 3 digits, OPTIONAL (sep, 1-3 digits)
|
||||
// Matches: .210, .210.10, ,210
|
||||
// Part 3 (Short2): Whitespace/Start, 3 digits, Whitespace/End
|
||||
// Matches: " 210 ", " 144 "
|
||||
String smartPattern = "(?<![\\d])(\\d{3,5}[.,]\\d{1,3}(?:[.,]\\d{1,3})?)(?![\\d])|(?<![\\d])([.,]\\d{3}(?:[.,]\\d{1,3})?)(?![\\d])|(?<=\\s|^)(\\d{3})(?=\\s|$)";
|
||||
|
||||
Pattern pattern = Pattern.compile(smartPattern);
|
||||
Matcher matcher = pattern.matcher(message.getMessageText());
|
||||
if (message == null || message.getMessageText() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChatMember sender = message.getSender();
|
||||
// Safety check, in case sender is null (e.g., server message)
|
||||
if (sender == null) return;
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String messageText = message.getMessageText();
|
||||
Matcher matcher = SMART_FREQUENCY_PATTERN.matcher(messageText);
|
||||
|
||||
while (matcher.find()) {
|
||||
String foundRaw = matcher.group().trim();
|
||||
boolean dottedShortForm = matcher.group(2) != null;
|
||||
boolean bareShortForm = matcher.group(3) != null;
|
||||
boolean shortForm = dottedShortForm || bareShortForm;
|
||||
|
||||
// --- PRE-PROCESSING: Normalize separators ---
|
||||
// 1. Replace all commas with dots to unify format (144,210,10 -> 144.210.10)
|
||||
foundRaw = foundRaw.replace(",", ".");
|
||||
if (bareShortForm
|
||||
&& !hasExplicitBareFrequencyContext(
|
||||
messageText,
|
||||
matcher.start(),
|
||||
matcher.end()
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String foundRaw = matcher.group().trim().replace(',', '.');
|
||||
|
||||
double finalDetectedFrequency = 0.0;
|
||||
Band finalDetectedBand = null;
|
||||
boolean isShortForm = false;
|
||||
|
||||
// --- STEP 1: Type Determination (Short or Full?) ---
|
||||
if (shortForm) {
|
||||
if (foundRaw.startsWith(".")) {
|
||||
foundRaw = foundRaw.substring(1);
|
||||
}
|
||||
|
||||
// Check if it starts with a dot (e.g. ".210") OR is just 3 digits ("210")
|
||||
if (foundRaw.startsWith(".") || foundRaw.length() == 3) {
|
||||
/*
|
||||
* Priority 1: use this sender's most recently observed band if its
|
||||
* information is not older than 30 minutes and the reconstructed
|
||||
* frequency lies inside that band.
|
||||
*/
|
||||
long bestTimestamp = 0L;
|
||||
|
||||
// It is a short form.
|
||||
// We strip the leading dot for calculation if present -> "210.10" or "210"
|
||||
if (foundRaw.startsWith(".")) foundRaw = foundRaw.substring(1);
|
||||
isShortForm = true;
|
||||
|
||||
} else {
|
||||
// It is a full frequency (e.g., 144.210.10 or 144.210)
|
||||
try {
|
||||
// Normalize "144.210.10" to "144.21010" for Double.parseDouble
|
||||
String normalizedFull = normalizeFrequencyString(foundRaw);
|
||||
|
||||
finalDetectedFrequency = Double.parseDouble(normalizedFull);
|
||||
finalDetectedBand = Band.fromFrequency(finalDetectedFrequency);
|
||||
} catch (NumberFormatException e) { continue; }
|
||||
}
|
||||
|
||||
// --- STEP 2: Context Resolution (Only needed for Short Forms) ---
|
||||
if (isShortForm) {
|
||||
|
||||
// A) HISTORY CHECK (Priority 1: What did THIS USER do recently?)
|
||||
// We search for the most recent band where this short form makes physical sense.
|
||||
long bestTimestamp = 0;
|
||||
|
||||
// Iterate over all bands where the user is known
|
||||
// (Assumption: ChatMember has a getter getKnownActiveBands())
|
||||
if (sender.getKnownActiveBands() != null) {
|
||||
for (java.util.Map.Entry<Band, ChatMember.ActiveFrequencyInfo> entry : sender.getKnownActiveBands().entrySet()) {
|
||||
for (java.util.Map.Entry<Band, ChatMember.ActiveFrequencyInfo> entry
|
||||
: sender.getKnownActiveBands().entrySet()) {
|
||||
|
||||
Band candidateBand = entry.getKey();
|
||||
ChatMember.ActiveFrequencyInfo info = entry.getValue();
|
||||
|
||||
// Timeout Check: Info must not be older than 30 mins (1,800,000 ms)
|
||||
if (System.currentTimeMillis() - info.timestampEpoch > 1800000) continue;
|
||||
if (candidateBand == null || info == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try Reconstruction: Band Prefix + ShortForm
|
||||
// Example: Band 144 (Prefix "144") + "." + "210.10" -> "144.210.10"
|
||||
if (System.currentTimeMillis() - info.timestampEpoch > 1_800_000L) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
String reconstructedStr = candidateBand.getPrefix() + "." + foundRaw;
|
||||
String normalizedReconstruction = normalizeFrequencyString(reconstructedStr);
|
||||
|
||||
double attemptFreq = Double.parseDouble(normalizedReconstruction);
|
||||
String reconstructed =
|
||||
candidateBand.getPrefix() + "." + foundRaw;
|
||||
double candidateFrequency = Double.parseDouble(
|
||||
normalizeFrequencyString(reconstructed)
|
||||
);
|
||||
|
||||
// Does this frequency fit into the candidate band?
|
||||
if (candidateBand.isPlausible(attemptFreq)) {
|
||||
// If we have multiple matches, pick the most recent one
|
||||
if (info.timestampEpoch > bestTimestamp) {
|
||||
finalDetectedFrequency = attemptFreq;
|
||||
finalDetectedBand = candidateBand;
|
||||
bestTimestamp = info.timestampEpoch;
|
||||
}
|
||||
if (candidateBand.isPlausible(candidateFrequency)
|
||||
&& info.timestampEpoch > bestTimestamp) {
|
||||
finalDetectedFrequency = candidateFrequency;
|
||||
finalDetectedBand = candidateBand;
|
||||
bestTimestamp = info.timestampEpoch;
|
||||
}
|
||||
} catch (Exception e) { /* Ignore parsing errors */ }
|
||||
}
|
||||
}
|
||||
|
||||
// B) GLOBAL PREFERENCES CHECK (Priority 2: Fallback if history is empty/old)
|
||||
if (finalDetectedBand == null) {
|
||||
// Get standard band from prefs (e.g., "144" or "432")
|
||||
String defaultPrefix = prefs.getNotify_optionalFrequencyPrefix().get();
|
||||
try {
|
||||
String reconstructedStr = defaultPrefix + "." + foundRaw;
|
||||
String normalizedReconstruction = normalizeFrequencyString(reconstructedStr);
|
||||
|
||||
double attemptFreq = Double.parseDouble(normalizedReconstruction);
|
||||
|
||||
// Check if this results in a valid amateur radio band
|
||||
Band defaultBandCandidate = Band.fromFrequency(attemptFreq);
|
||||
|
||||
if (defaultBandCandidate != null) {
|
||||
finalDetectedFrequency = attemptFreq;
|
||||
finalDetectedBand = defaultBandCandidate;
|
||||
} catch (NumberFormatException ignored) {
|
||||
// Try the next known band.
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// Number was likely not a frequency (e.g., "73" or "599") and didn't fit any band
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- STEP 3: Process Result ---
|
||||
if (finalDetectedBand != null && finalDetectedFrequency > 0) {
|
||||
|
||||
/*
|
||||
* Store the detected QRG in the thread-safe active-member model.
|
||||
* The UI table is only a JavaFX mirror, so the MessageBus must not scan
|
||||
* or mutate getLst_chatMemberList() here.
|
||||
* Priority 2: use the configured fallback band. Invalid values from
|
||||
* an older hand-edited configuration fall back safely to 144 MHz.
|
||||
* The current UI itself offers only values from Band.values().
|
||||
*/
|
||||
client.applyDetectedFrequencyToActiveMembers(sender, finalDetectedBand, finalDetectedFrequency);
|
||||
if (finalDetectedBand == null) {
|
||||
String configuredPrefix = null;
|
||||
|
||||
System.out.println("[SmartParser] Detected for " + sender.getCallSign() + ": " +
|
||||
finalDetectedFrequency + " MHz (" + finalDetectedBand + ") " +
|
||||
(isShortForm ? "[derived from " + foundRaw + "]" : "[full match]"));
|
||||
if (prefs != null
|
||||
&& prefs.getNotify_optionalFrequencyPrefix() != null) {
|
||||
configuredPrefix =
|
||||
prefs.getNotify_optionalFrequencyPrefix().get();
|
||||
}
|
||||
|
||||
// Optional: Trigger Cluster-Spot here if enabled
|
||||
Band fallbackBand = Band.fromPrefix(configuredPrefix);
|
||||
if (fallbackBand == null) {
|
||||
fallbackBand = Band.B_144;
|
||||
}
|
||||
|
||||
try {
|
||||
String reconstructed =
|
||||
fallbackBand.getPrefix() + "." + foundRaw;
|
||||
double candidateFrequency = Double.parseDouble(
|
||||
normalizeFrequencyString(reconstructed)
|
||||
);
|
||||
|
||||
if (fallbackBand.isPlausible(candidateFrequency)) {
|
||||
finalDetectedFrequency = candidateFrequency;
|
||||
finalDetectedBand = fallbackBand;
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
// The matched value cannot be converted into a frequency.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
finalDetectedFrequency = Double.parseDouble(
|
||||
normalizeFrequencyString(foundRaw)
|
||||
);
|
||||
finalDetectedBand = Band.fromFrequency(finalDetectedFrequency);
|
||||
} catch (NumberFormatException ignored) {
|
||||
// Continue with the next possible match in the message.
|
||||
}
|
||||
}
|
||||
|
||||
if (finalDetectedBand == null || finalDetectedFrequency <= 0.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the result in the thread-safe active-member model. The existing
|
||||
* compatibility property used by the TableView and DX-Cluster code is
|
||||
* updated by applyDetectedFrequencyToActiveMembers(...), too.
|
||||
*/
|
||||
client.applyDetectedFrequencyToActiveMembers(
|
||||
sender,
|
||||
finalDetectedBand,
|
||||
finalDetectedFrequency
|
||||
);
|
||||
|
||||
System.out.println(
|
||||
"[SmartParser] Detected for "
|
||||
+ sender.getCallSign()
|
||||
+ ": "
|
||||
+ finalDetectedFrequency
|
||||
+ " MHz ("
|
||||
+ finalDetectedBand
|
||||
+ ") "
|
||||
+ (shortForm
|
||||
? "[derived from " + foundRaw + "]"
|
||||
: "[full match]")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether a bare three-digit value is surrounded by text that identifies
|
||||
* it as a frequency.
|
||||
*
|
||||
* <p>The check intentionally uses only a small area around the value. A remote
|
||||
* occurrence of the word "QRG" elsewhere in a long message must not turn every
|
||||
* three-digit number in that message into a frequency.</p>
|
||||
*
|
||||
* @param messageText complete chat message
|
||||
* @param matchStart start index of the three-digit match
|
||||
* @param matchEnd end index of the three-digit match
|
||||
* @return {@code true} if the value has explicit frequency context
|
||||
*/
|
||||
static boolean hasExplicitBareFrequencyContext(
|
||||
String messageText,
|
||||
int matchStart,
|
||||
int matchEnd
|
||||
) {
|
||||
if (messageText == null
|
||||
|| matchStart < 0
|
||||
|| matchEnd < matchStart
|
||||
|| matchEnd > messageText.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int prefixStart = Math.max(
|
||||
0,
|
||||
matchStart - BARE_FREQUENCY_CONTEXT_CHARACTERS
|
||||
);
|
||||
int suffixEnd = Math.min(
|
||||
messageText.length(),
|
||||
matchEnd + BARE_FREQUENCY_CONTEXT_CHARACTERS
|
||||
);
|
||||
|
||||
String prefixContext = messageText.substring(prefixStart, matchStart);
|
||||
String suffixContext = messageText.substring(matchEnd, suffixEnd);
|
||||
|
||||
return BARE_FREQUENCY_PREFIX_CONTEXT_PATTERN
|
||||
.matcher(prefixContext)
|
||||
.find()
|
||||
|| BARE_FREQUENCY_SUFFIX_CONTEXT_PATTERN
|
||||
.matcher(suffixContext)
|
||||
.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Normalizes weird frequency formats to valid Double strings.
|
||||
* Example: "144.210.10" -> "144.21010"
|
||||
|
||||
+81
-4
@@ -1,4 +1,81 @@
|
||||
package kst4contest.controller;
|
||||
|
||||
public class MessageBusManagementThreadFrequencyContextTest {
|
||||
}
|
||||
//package kst4contest.controller;
|
||||
//
|
||||
//import kst4contest.model.Band;
|
||||
//import org.junit.jupiter.api.Test;
|
||||
//import org.junit.jupiter.params.ParameterizedTest;
|
||||
//import org.junit.jupiter.params.provider.ValueSource;
|
||||
//
|
||||
//import java.util.regex.Matcher;
|
||||
//import java.util.regex.Pattern;
|
||||
//
|
||||
//import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
//import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
//import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
//import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
//import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
//
|
||||
//class MessageBusManagementThreadFrequencyContextTest {
|
||||
//
|
||||
// private static final Pattern THREE_DIGIT_VALUE =
|
||||
// Pattern.compile("\\b\\d{3}\\b");
|
||||
//
|
||||
// @ParameterizedTest
|
||||
// @ValueSource(strings = {
|
||||
// "qrg 210",
|
||||
// "QRG: 210",
|
||||
// "freq is 210",
|
||||
// "frequency = 210",
|
||||
// "on 210",
|
||||
// "210 MHz",
|
||||
// "210 qrg"
|
||||
// })
|
||||
// void acceptsBareThreeDigitValueWithFrequencyContext(String messageText) {
|
||||
// Matcher matcher = findThreeDigitValue(messageText);
|
||||
//
|
||||
// assertTrue(
|
||||
// MessageBusManagementThread
|
||||
// .hasExplicitBareFrequencyContext(
|
||||
// messageText,
|
||||
// matcher.start(),
|
||||
// matcher.end()
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @ParameterizedTest
|
||||
// @ValueSource(strings = {
|
||||
// "599",
|
||||
// "144",
|
||||
// "serial 210",
|
||||
// "score 210",
|
||||
// "worked 210 stations"
|
||||
// })
|
||||
// void rejectsBareThreeDigitValueWithoutFrequencyContext(String messageText) {
|
||||
// Matcher matcher = findThreeDigitValue(messageText);
|
||||
//
|
||||
// assertFalse(
|
||||
// MessageBusManagementThread
|
||||
// .hasExplicitBareFrequencyContext(
|
||||
// messageText,
|
||||
// matcher.start(),
|
||||
// matcher.end()
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void resolvesOnlySupportedFallbackPrefixes() {
|
||||
// assertEquals(Band.B_144, Band.fromPrefix("144"));
|
||||
// assertEquals(Band.B_432, Band.fromPrefix(" 432 "));
|
||||
// assertEquals(Band.B_10G, Band.fromPrefix("10368"));
|
||||
// assertNull(Band.fromPrefix("999"));
|
||||
// assertNull(Band.fromPrefix(null));
|
||||
// }
|
||||
//
|
||||
// private Matcher findThreeDigitValue(String messageText) {
|
||||
// Matcher matcher = THREE_DIGIT_VALUE.matcher(messageText);
|
||||
// assertTrue(matcher.find(), "Test message must contain a three-digit value");
|
||||
// assertNotNull(matcher.group());
|
||||
// return matcher;
|
||||
// }
|
||||
//}
|
||||
@@ -291,14 +291,6 @@ public class ReadUDPbyUCXMessageThread extends Thread {
|
||||
|
||||
ChatMember modifyThat = null;
|
||||
|
||||
// System.out.println("ReadUDPByUCX, message catched: " + udpMsg);
|
||||
|
||||
// String[] threadStatusMessage = new String[2];
|
||||
// threadStatusMessage = new String[3];
|
||||
// threadStatusMessage[0] = "on";
|
||||
// threadStatusMessage[1] = "received message:";
|
||||
// threadStatusMessage[2] = udpMsg;
|
||||
|
||||
ThreadStateMessage threadStateMessage = new ThreadStateMessage(this.ThreadNickName, true, "received Message\n" + udpMsg, false);
|
||||
|
||||
callBackToController.onThreadStatus(ThreadNickName,threadStateMessage);
|
||||
@@ -307,7 +299,7 @@ public class ReadUDPbyUCXMessageThread extends Thread {
|
||||
try {
|
||||
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
} catch (ParserConfigurationException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,35 @@ public enum Band {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves a configured MHz prefix to one of the bands supported by the
|
||||
* frequency parser.
|
||||
*
|
||||
* <p>The former free-text preference accepted arbitrary numeric values even
|
||||
* though only prefixes represented by this enum can be used for a plausible
|
||||
* frequency. Keeping the lookup here gives the UI and the parser one common
|
||||
* definition of a valid fallback band.</p>
|
||||
*
|
||||
* @param prefix configured MHz prefix, for example {@code 144} or {@code 10368}
|
||||
* @return matching band, or {@code null} if the prefix is not supported
|
||||
*/
|
||||
public static Band fromPrefix(String prefix) {
|
||||
if (prefix == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String normalizedPrefix = prefix.trim();
|
||||
|
||||
for (Band band : values()) {
|
||||
if (band.prefix.equals(normalizedPrefix)) {
|
||||
return band;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lower edge used as practical analysis frequency when only the band
|
||||
* is known. This keeps the batch reachability calculation deterministic.
|
||||
|
||||
@@ -31,6 +31,7 @@ import javafx.scene.layout.*;
|
||||
import javafx.scene.media.Media;
|
||||
import javafx.scene.media.MediaPlayer;
|
||||
import javafx.util.Duration;
|
||||
import javafx.util.StringConverter;
|
||||
import kst4contest.ApplicationConstants;
|
||||
import kst4contest.controller.ChatController;
|
||||
import kst4contest.controller.MessageVariableResolver;
|
||||
@@ -1504,19 +1505,13 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> call(CellDataFeatures<ChatMember, String> cellDataFeatures) {
|
||||
// StringProperty qrg = new SimpleStringProperty();
|
||||
|
||||
// qrg.setValue(cellDataFeatures.getValue().getFrequency());
|
||||
// qrg = (cellDataFeatures.getValue().getFrequency());
|
||||
|
||||
// if (!qrg.getValue().equals("")) {
|
||||
//
|
||||
// }
|
||||
|
||||
return cellDataFeatures.getValue().getFrequency();
|
||||
}
|
||||
|
||||
});
|
||||
applyQrgUiFormatting(qrgCol); //insert zero until qrg string looks pretty
|
||||
|
||||
|
||||
TableColumn<ChatMember, String> airScoutCol = new TableColumn<ChatMember, String>("AP [minutes / pot%]");
|
||||
airScoutCol.setCellValueFactory(new Callback<CellDataFeatures<ChatMember, String>, ObservableValue<String>>() {
|
||||
@@ -9854,53 +9849,84 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
}
|
||||
);
|
||||
|
||||
TextField txtFld_notify_DXclusterServerFrequencyPrefix =
|
||||
new TextField(
|
||||
this.chatcontroller
|
||||
.getChatPreferences()
|
||||
.getNotify_optionalFrequencyPrefix()
|
||||
.getValue()
|
||||
ComboBox<Band> cmbBx_notifyFrequencyFallbackBand =
|
||||
new ComboBox<>(
|
||||
FXCollections.observableArrayList(Band.values())
|
||||
);
|
||||
|
||||
txtFld_notify_DXclusterServerFrequencyPrefix
|
||||
.focusedProperty()
|
||||
cmbBx_notifyFrequencyFallbackBand.setEditable(false);
|
||||
cmbBx_notifyFrequencyFallbackBand.setMaxWidth(Double.MAX_VALUE);
|
||||
cmbBx_notifyFrequencyFallbackBand.setTooltip(
|
||||
new Tooltip(
|
||||
"Used for relative QRG values such as .210 when no band "
|
||||
+ "has been recognized for the sender during the "
|
||||
+ "previous 30 minutes. This setting affects the "
|
||||
+ "general QRG detection, not only DX-Cluster spots."
|
||||
)
|
||||
);
|
||||
|
||||
cmbBx_notifyFrequencyFallbackBand.setConverter(
|
||||
new StringConverter<Band>() {
|
||||
@Override
|
||||
public String toString(Band band) {
|
||||
if (band == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String displayLabel = band.getDisplayLabel();
|
||||
if (band.getPrefix().equals(displayLabel)) {
|
||||
return band.getPrefix() + " MHz";
|
||||
}
|
||||
|
||||
return band.getPrefix()
|
||||
+ " MHz ("
|
||||
+ displayLabel
|
||||
+ ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Band fromString(String displayedValue) {
|
||||
if (displayedValue == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int firstSpace = displayedValue.indexOf(' ');
|
||||
String prefix = firstSpace >= 0
|
||||
? displayedValue.substring(0, firstSpace)
|
||||
: displayedValue;
|
||||
|
||||
return Band.fromPrefix(prefix);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Band configuredFallbackBand = Band.fromPrefix(
|
||||
chatcontroller
|
||||
.getChatPreferences()
|
||||
.getNotify_optionalFrequencyPrefix()
|
||||
.get()
|
||||
);
|
||||
|
||||
if (configuredFallbackBand == null) {
|
||||
configuredFallbackBand = Band.B_144;
|
||||
chatcontroller
|
||||
.getChatPreferences()
|
||||
.setNotify_optionalFrequencyPrefix(
|
||||
configuredFallbackBand.getPrefix()
|
||||
);
|
||||
}
|
||||
|
||||
cmbBx_notifyFrequencyFallbackBand.setValue(configuredFallbackBand);
|
||||
|
||||
cmbBx_notifyFrequencyFallbackBand
|
||||
.valueProperty()
|
||||
.addListener(
|
||||
(observable, oldValue, focused) -> {
|
||||
if (focused) {
|
||||
return;
|
||||
}
|
||||
|
||||
String bandInMHz =
|
||||
txtFld_notify_DXclusterServerFrequencyPrefix
|
||||
.getText()
|
||||
.trim();
|
||||
|
||||
if (bandInMHz.matches(
|
||||
"[1-9]\\d{1,4}"
|
||||
)) {
|
||||
(observable, oldBand, newBand) -> {
|
||||
if (newBand != null) {
|
||||
chatcontroller
|
||||
.getChatPreferences()
|
||||
.setNotify_optionalFrequencyPrefix(
|
||||
bandInMHz
|
||||
);
|
||||
|
||||
txtFld_notify_DXclusterServerFrequencyPrefix
|
||||
.setText(bandInMHz);
|
||||
} else {
|
||||
showUserInputErrorWindow(
|
||||
"\""
|
||||
+ bandInMHz
|
||||
+ "\" is not a valid fallback band. "
|
||||
+ "Enter the MHz part as an integer, "
|
||||
+ "for example 144, 432 or 1296."
|
||||
);
|
||||
|
||||
txtFld_notify_DXclusterServerFrequencyPrefix
|
||||
.setText(
|
||||
chatcontroller
|
||||
.getChatPreferences()
|
||||
.getNotify_optionalFrequencyPrefix()
|
||||
.getValue()
|
||||
newBand.getPrefix()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -10075,14 +10101,13 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
|
||||
grdPnlNotify.add(
|
||||
new Label(
|
||||
"Fallback band in MHz for relative "
|
||||
+ "frequencies [default: 144]:"
|
||||
"Fallback band for relative QRG detection:"
|
||||
),
|
||||
0,
|
||||
8
|
||||
);
|
||||
grdPnlNotify.add(
|
||||
txtFld_notify_DXclusterServerFrequencyPrefix,
|
||||
cmbBx_notifyFrequencyFallbackBand,
|
||||
1,
|
||||
8
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user