From 333063f3507a91718666e70768c2e6b8561e85c6 Mon Sep 17 00:00:00 2001 From: Marc Froehlich Date: Sun, 26 Jul 2026 11:04:47 +0200 Subject: [PATCH] Changed Autoanswer implementation (cooldown timer, message routing) and its documentation --- ...client_settings_window_messagehandling.png | Bin 0 -> 53428 bytes github_docs/de-Benutzeroberflaeche.md | 13 +++- github_docs/de-Funktionen.md | 16 ++++ github_docs/de-Konfiguration.md | 65 +++++++++++++++- .../kst4contest/ApplicationConstants.java | 2 +- .../MessageBusManagementThread.java | 71 +++++++++++------- .../kst4contest/model/ChatPreferences.java | 8 ++ .../view/Kst4ContestApplication.java | 45 ++++++----- 8 files changed, 161 insertions(+), 59 deletions(-) create mode 100644 github_docs/client_settings_window_messagehandling.png diff --git a/github_docs/client_settings_window_messagehandling.png b/github_docs/client_settings_window_messagehandling.png new file mode 100644 index 0000000000000000000000000000000000000000..24b795845e500741d076d49890cdb3a012d4e576 GIT binary patch literal 53428 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 literal 0 HcmV?d00001 diff --git a/github_docs/de-Benutzeroberflaeche.md b/github_docs/de-Benutzeroberflaeche.md index 34cec21..98d8c60 100644 --- a/github_docs/de-Benutzeroberflaeche.md +++ b/github_docs/de-Benutzeroberflaeche.md @@ -64,9 +64,18 @@ Die Filter-Leiste (ab v1.21 als Flowpane für kleine Bildschirme): ## Stationsinfo-Panel (Further Info) -Rechts unten: Zeigt alle Nachrichten einer ausgewählten Station (CQ-Nachrichten und PMs in einem Panel). Ein Nachrichtenfilter lässt sich über den Standard-Filter in den Preferences vorbelegen. +Rechts unten werden die Nachrichten der ausgewählten Station zusammengeführt. Dazu gehören öffentliche Nachrichten, Privatnachrichten an die eigene Station und – soweit im Chat sichtbar – Privatnachrichten an andere Stationen. -Hier können auch **Sked-Erinnerungen** aktiviert werden. +Der im Panel gewählte Filter bestimmt, welche dieser Nachrichten angezeigt werden. Unter **Settings → GUI** lässt sich festlegen, welcher Filter beim Öffnen einer Stationsinformation vorausgewählt ist: + +- alle Nachrichten, +- Privatnachrichten an die eigene Station, +- Privatnachrichten an andere Stationen oder +- öffentliche Nachrichten. + +Die Einstellung verändert nur die Darstellung im Stationsinfo-Panel. Nachrichten werden dadurch weder verworfen noch aus den übrigen Nachrichtentabellen entfernt. Der Filter kann im Panel jederzeit für die aktuell betrachtete Station gewechselt werden. + +Hier können auch **Sked-Erinnerungen / Wecker** für beide Skkedpartner aktiviert werden. --- diff --git a/github_docs/de-Funktionen.md b/github_docs/de-Funktionen.md index 5ea9b96..ff93ddd 100644 --- a/github_docs/de-Funktionen.md +++ b/github_docs/de-Funktionen.md @@ -115,6 +115,22 @@ KST4Contest erkennt solche Nachrichten, die das eigene Rufzeichen enthalten, und --- +## Automatische Antworten auf Privatnachrichten (ab v1.25) + +Nicht jede im ON4KST-Chat eingeloggte Station nimmt am gerade laufenden Contest teil. Trotzdem werden Sked-Anfragen während größerer Contests teilweise unkoordiniert und in großer Zahl an erreichbare Rufzeichen verteilt. Ohne automatische Antwort müssten diese Stationen immer wieder von Hand erklären, dass sie nicht mitfunken oder keine Skeds fahren. + +KST4Contest kann darauf mit einem vorher festgelegten Text reagieren. Die eingehende Privatnachricht bleibt dabei sichtbar; sie wird weder blockiert noch verworfen. Davon getrennt lässt sich eine QRG-Antwort aktivieren, die auf typische Fragen wie `qrg?`, `freq?` oder `pse qrg` reagiert. + +Bei zwei gleichzeitig geöffneten Chat-Kategorien bleibt der Zusammenhang erhalten: Die Antwort wird in der Kategorie der eingegangenen Nachricht gesendet. Eine QRG-Anfrage erhält außerdem nur die QRG dieser Kategorie und nicht eine Liste aller konfigurierten Frequenzen. + +Automatische Antworten benötigen Grenzen. KST4Contest versieht sie daher mit `[KST4C Automsg]`, ignoriert entsprechend gekennzeichnete Nachrichten bei der allgemeinen und QRG-bezogenen Antwort und begrenzt weitere Antworten an dieselbe Station in derselben Kategorie auf eine Nachricht innerhalb von zwei Minuten. Der Schutz gilt gemeinsam für beide Antwortarten. + +Im Klartext: Die Funktion verhindert keine Massenanfragen. Sie verhindert aber, dass der Empfänger jede davon einzeln mit derselben Absage beantworten muss. Sie soll keine Unterhaltung simulieren und erst recht keine endlose Diskussion mit einem zweiten automatischen Client beginnen. + +Konfiguration, erkannte QRG-Anfragen und genaue Kategorienzuordnung: [Konfiguration – Messagehandling Settings](de-Konfiguration#messagehandling-settings-ab-v125). + +--- + ## Multi-Channel-Login (ab v1.26) Gleichzeitiger Login in **zwei Chat-Kategorien** (z. B. 144 MHz und 432 MHz). Beide Chats werden parallel überwacht. diff --git a/github_docs/de-Konfiguration.md b/github_docs/de-Konfiguration.md index f37963a..02b37bb 100644 --- a/github_docs/de-Konfiguration.md +++ b/github_docs/de-Konfiguration.md @@ -226,11 +226,68 @@ Im Klartext: Solange auf einer festen QRG CQ gerufen wird, spart der Beacon Arbe ## Messagehandling Settings (ab v1.25) -Neuer Einstellungsbereich mit folgenden Optionen: +![Automatische Antworten](client_settings_window_messagehandling.png) -- **Auto-Antwort auf alle eingehenden Nachrichten**: Automatische Antwort auf Privatnachrichten konfigurierbar. -- **Auto-Antwort mit eigener CQ-QRG**: Wenn jemand nach der eigenen QRG fragt, antwortet KST4Contest automatisch mit dem Inhalt der `MYQRG`-Variable. -- **Standard-Filter für das Userinfo-Fenster**: Voreingestellter Nachrichtenfilter für das Stationsinfo-Fenster konfigurierbar *(für Gianluca :-) )*. +Die wichtigste Anwendung der allgemeinen automatischen Antwort betrifft Stationen, die zwar im ON4KST-Chat eingeloggt sind, den laufenden Contest aber nicht mitfunken. Gerade während größerer Contests werden Sked-Anfragen teilweise unkoordiniert und in großer Zahl an eingeloggte Stationen verteilt, ohne vorher zu prüfen, ob sie überhaupt teilnehmen. Die Empfänger müssten sonst immer wieder dieselbe Absage schreiben. + +KST4Contest kann darauf mit einem vorher festgelegten Text reagieren. Davon getrennt steht eine gezielte QRG-Auskunft zur Verfügung. Beide Funktionen können unabhängig voneinander aktiviert werden. + +### Allgemeine automatische Antwort + +**Enable automatic reply to all private messages** beantwortet eingehende Privatnachrichten mit dem Text im Feld rechts daneben. Es gibt einen gemeinsamen Text für beide Chat-Kategorien. Die beim Eingeben verwendete Groß- und Kleinschreibung bleibt erhalten. + +Eine zweckmäßige Nachricht ist beispielsweise: + +```text +Sri, I am not taking part in this contest. No skeds. +``` + +Die eingegangene Privatnachricht bleibt sichtbar. Die Funktion blockiert oder verwirft keine Anfrage, sondern erspart lediglich die wiederholte manuelle Antwort. + +Die Antwort wird in derselben Chat-Kategorie gesendet, in der die Privatnachricht eingegangen ist. Das ist bei einem parallelen Login in zwei Kategorien entscheidend: Eine Nachricht aus dem Microwave-Chat darf nicht versehentlich im VHF/UHF-Chat beantwortet werden. + +### Automatische QRG-Antwort + +**Enable automatic QRG replies** reagiert auf typische QRG-Anfragen. Die Erkennung unterscheidet nicht zwischen Groß- und Kleinschreibung und sucht nach folgenden Textbestandteilen: + +```text +ur qrg? +your qrg? +qrg? +freq? +pse qrg +``` + +Die Antwort enthält nur die QRG der Kategorie, in der die Anfrage eingegangen ist: + +| Eingegangene Privatnachricht | Verwendete QRG | +|---|---| +| Hauptkategorie | aktuelle QRG der Hauptkategorie | +| zweite Chat-Kategorie | aktuelle QRG der zweiten Kategorie | + +Die Werte stammen aus denselben QRG-Feldern, die auch von `MYQRG` und `SECONDQRG` verwendet werden. Die Haupt-QRG kann manuell eingetragen oder durch die [TRX-Synchronisation](#trx-sync-einstellungen) aktualisiert werden. Für die zweite Kategorie wird der dort konfigurierte beziehungsweise manuell eingetragene Wert verwendet. + +Sind die allgemeine und die QRG-bezogene Antwort gleichzeitig aktiviert, hat die QRG-Antwort Vorrang. Eine erkannte QRG-Anfrage erzeugt daher nicht zusätzlich den allgemeinen Antworttext. + +### Schutz vor wiederholten Antworten + +Jede automatisch erzeugte Nachricht trägt das feste Präfix: + +```text +[KST4C Automsg] +``` + +Die allgemeine und die QRG-bezogene Antwort reagieren nicht auf Nachrichten, die dieses Präfix bereits enthalten. Dadurch beantworten sich zwei entsprechend arbeitende Clients nicht gegenseitig in einer Schleife. + +Zusätzlich gilt eine gemeinsame Sperrzeit von zwei Minuten für beide Antwortarten. Die Sperre wird getrennt je Rufzeichen und Chat-Kategorie geführt. Hat eine Station gerade in der Hauptkategorie eine automatische Antwort erhalten, kann sie deshalb weiterhin eine Antwort in der zweiten Kategorie erhalten. Weitere Nachrichten derselben Station in derselben Kategorie lösen während der folgenden zwei Minuten dagegen keine neue automatische Antwort aus. + +Die Sperrzeit beginnt nur, wenn KST4Contest tatsächlich eine Antwort sendet. + +> **Hinweis**: Der Antworttext sollte den tatsächlichen Status eindeutig benennen. Wer den Contest nur beobachtet und keine Skeds fahren möchte, sollte genau das mitteilen. Eine vage Nachricht erzeugt im Zweifel nur die nächste Rückfrage – und damit exakt die Arbeit, welche die Funktion vermeiden soll. + +Änderungen wirken während der laufenden Verbindung. Damit Aktivierung und Text nach dem nächsten Programmstart erhalten bleiben, anschließend **Save Settings** verwenden. + +Weitere Hintergründe: [Automatische Antworten auf Privatnachrichten](de-Funktionen#automatische-antworten-auf-privatnachrichten-ab-v125). --- diff --git a/src/main/java/kst4contest/ApplicationConstants.java b/src/main/java/kst4contest/ApplicationConstants.java index d0f80b1..40245a0 100644 --- a/src/main/java/kst4contest/ApplicationConstants.java +++ b/src/main/java/kst4contest/ApplicationConstants.java @@ -43,7 +43,7 @@ public class ApplicationConstants { public static final String DISCONNECT_RDR_POISONPILL = "UNKNOWN: KST4C KILL POISONPILL_KILLTHREAD=: " + sessionRuntimeUniqueId; //whereever a (blocking) udp or tcp reader in an infinite loop gets this message, it will break this loop - public static final String AUTOANSWER_PREFIX = "[KST4C Automsg] "; // hard-coded marker (user can't remove it) + public static final String AUTOANSWER_PREFIX = "[KST4C Automsg]"; // hard-coded marker (user cannot remove it) /** * UI message retention limits. diff --git a/src/main/java/kst4contest/controller/MessageBusManagementThread.java b/src/main/java/kst4contest/controller/MessageBusManagementThread.java index 93bdfb8..425498f 100644 --- a/src/main/java/kst4contest/controller/MessageBusManagementThread.java +++ b/src/main/java/kst4contest/controller/MessageBusManagementThread.java @@ -47,13 +47,12 @@ public class MessageBusManagementThread extends Thread { 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)?)"; - // ==== Autoanswer Flood/Pingpong Protection ==== - private static final String AUTOANSWER_PREFIX = ApplicationConstants.AUTOANSWER_PREFIX; // hard-coded marker (user can't remove it) - private static final long AUTOANSWER_COOLDOWN_MS = 45_000L; // 45_000L = 45s + // ==== Auto-answer flood/ping-pong protection ==== + private static final String AUTOANSWER_PREFIX = ApplicationConstants.AUTOANSWER_PREFIX; + private static final long AUTOANSWER_COOLDOWN_MS = 120_000L; // two minutes - // Cooldown per opponent station (and ChatCategory) – only setted if this client sends + // Cooldown per remote station and chat category; updated only after this client sends. private final Hashtable lastLocalAutoAnswerPerRemoteMs = new Hashtable<>(); - // BufferedWriter bufwrtrDBGMSGOut; // private String text; @@ -829,7 +828,11 @@ public class MessageBusManagementThread extends Thread { versionInfo.setSender(itsMe); versionInfo.setReceiver(newMessageArrived.getSender()); - versionInfo.setMessageText("/CQ " + newMessageArrived.getSender().getCallSign() + " " + ApplicationConstants.AUTOANSWER_PREFIX + " " + "KST4Contest " + " v" + ApplicationConstants.APPLICATION_CURRENT_VERSION + " by DO5AMF"); + versionInfo.setChatCategory(newMessageArrived.getChatCategory()); + versionInfo.setMessageText("/CQ " + newMessageArrived.getSender().getCallSign() + + " " + AUTOANSWER_PREFIX + + " KST4Contest v" + ApplicationConstants.APPLICATION_CURRENT_VERSION + + " by DO5AMF"); this.client.getMessageTXBus().add(versionInfo); } @@ -876,11 +879,11 @@ public class MessageBusManagementThread extends Thread { // } // } - // ==== Unified Autoanswer (Generic + QRG) with Pingpong-Guard + per-Remote Cooldown ==== + // ==== Unified auto-answer (generic + QRG) with ping-pong guard and per-remote cooldown ==== final String incomingText = newMessageArrived.getMessageText(); final String incomingLower = (incomingText == null) ? "" : incomingText.toLowerCase(Locale.ROOT); - // 1) Pingpong-security: never ever react to auto generated messages + // Never answer another automatically generated message. if (!isAutoMessage(newMessageArrived)) { boolean qrgRequested = false; @@ -896,24 +899,17 @@ public class MessageBusManagementThread extends Thread { boolean genericEnabled = this.client.getChatPreferences().isMsgHandling_autoAnswerEnabled(); - // 2) Entscheide, ob überhaupt geantwortet wird (QRG hat Vorrang vor Generic) + // A QRG reply takes precedence over the generic reply. String payload = null; if (qrgRequested) { - - if (this.client.getChatPreferences().isLoginToSecondChatEnabled()) { - payload = "QRGs: " + this.client.getChatPreferences().getMYQRGFirstCat().getValue() - + " / " + this.client.getChatPreferences().getMYQRGSecondCat().getValue(); - } else { - payload = "QRG is: " + this.client.getChatPreferences().getMYQRGFirstCat().getValue(); - } - + payload = "QRG is: " + getAutoAnswerQrgForCategory(newMessageArrived.getChatCategory()); } else if (genericEnabled) { payload = this.client.getChatPreferences().getMessageHandling_autoAnswerTextMainCat(); } - // 3) Cooldown pro Gegenstation: nur wenn DIESER Client jetzt wirklich sendet + // Apply the cooldown only when this client is about to send a reply. if (payload != null && isAutoAnswerAllowedNow(newMessageArrived)) { ChatMessage automaticAnswer = new ChatMessage(); @@ -922,15 +918,15 @@ public class MessageBusManagementThread extends Thread { automaticAnswer.setSender(itsMe); automaticAnswer.setReceiver(newMessageArrived.getSender()); + automaticAnswer.setChatCategory(newMessageArrived.getChatCategory()); - // Prefix fest + nicht entfernbar, damit Auto↔Auto nicht pingpongt + // The fixed prefix prevents automatic clients from answering each other. automaticAnswer.setMessageText("/CQ " + newMessageArrived.getSender().getCallSign() + " " + AUTOANSWER_PREFIX + " " + payload); this.client.getMessageTXBus().add(automaticAnswer); - // Cooldown wird NUR hier gesetzt (nicht bei 'message sent by me' Echo), - // damit nur lokale Auto-Sends zählen. + // Record only locally generated replies, not the later server echo. markLocalAutoAnswerSent(newMessageArrived); } } @@ -1544,9 +1540,7 @@ public class MessageBusManagementThread extends Thread { /** - * check if message had been auto generated - * @param msg - * @return + * Returns whether a message carries the fixed marker used for automatic replies. */ private boolean isAutoMessage(ChatMessage msg) { return msg != null @@ -1554,6 +1548,22 @@ public class MessageBusManagementThread extends Thread { && msg.getMessageText().contains(AUTOANSWER_PREFIX); } + /** + * Returns the configured QRG for the category in which the request was received. + * If the category cannot be resolved, the main category remains the safe fallback. + */ + private String getAutoAnswerQrgForCategory(ChatCategory incomingCategory) { + ChatCategory secondCategory = this.client.getChatCategorySecondChat(); + + if (incomingCategory != null + && secondCategory != null + && incomingCategory.getCategoryNumber() == secondCategory.getCategoryNumber()) { + return this.client.getChatPreferences().getMYQRGSecondCat().getValue(); + } + + return this.client.getChatPreferences().getMYQRGFirstCat().getValue(); + } + private String autoAnswerCooldownKey(ChatMessage incoming) { String remoteCall = "UNKNOWN"; @@ -1561,13 +1571,16 @@ public class MessageBusManagementThread extends Thread { remoteCall = incoming.getSender().getCallSign().toUpperCase(); } - int cat = 0; // fallback - if (incoming != null && incoming.getSender() != null && incoming.getSender().getChatCategory() != null) { - cat = incoming.getSender().getChatCategory().getCategoryNumber(); + int categoryNumber = 0; + if (incoming != null && incoming.getChatCategory() != null) { + categoryNumber = incoming.getChatCategory().getCategoryNumber(); + } else if (incoming != null + && incoming.getSender() != null + && incoming.getSender().getChatCategory() != null) { + categoryNumber = incoming.getSender().getChatCategory().getCategoryNumber(); } - // pro Gegenstation + pro Chat-Kategorie (falls derselbe Call in Cat2/Cat3 PMs macht) - return remoteCall + "|" + cat; + return remoteCall + "|" + categoryNumber; } private boolean isAutoAnswerAllowedNow(ChatMessage incoming) { diff --git a/src/main/java/kst4contest/model/ChatPreferences.java b/src/main/java/kst4contest/model/ChatPreferences.java index b3d8cc7..6eb87c8 100644 --- a/src/main/java/kst4contest/model/ChatPreferences.java +++ b/src/main/java/kst4contest/model/ChatPreferences.java @@ -2692,6 +2692,14 @@ public class ChatPreferences { messageHandling_autoAnswerEnabledSecondCat, "messageHandling_autoAnswerEnabledSecondCat", "autoAnswerEnabledSecondCat"); + + /* + * The user interface intentionally exposes one shared generic auto-answer + * setting for both chat categories. Keep the legacy second-category XML + * fields synchronized so existing configuration files remain compatible. + */ + messageHandling_autoAnswerTextSecondCat = messageHandling_autoAnswerTextMainCat; + messageHandling_autoAnswerEnabledSecondCat = messageHandling_autoAnswerEnabled; } diff --git a/src/main/java/kst4contest/view/Kst4ContestApplication.java b/src/main/java/kst4contest/view/Kst4ContestApplication.java index 1c65844..44a8198 100644 --- a/src/main/java/kst4contest/view/Kst4ContestApplication.java +++ b/src/main/java/kst4contest/view/Kst4ContestApplication.java @@ -10472,38 +10472,37 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL // CheckBox chkBxEnableTRXMsgbyUCX = new CheckBox(); grdPnlMessageHandlingBeacon.add(generateLabeledSeparator(100, - "Set the unworked penetrator Beacons (intervalled PM to unworked stations)"), 0, 0, 2, 1); - - grdPnlMessageHandlingBeacon.add(generateLabeledSeparator(100, - "Automatic answering options)"), 0, 1, 2, 1); + "Automatic answering options"), 0, 0, 2, 1); // Label lbl_unwkd_autoAnswerDescriptor = new Label("Auto-answer Text:"); // grdPnlMessageHandlingBeacon.add(lbl_unwkd_autoAnswerDescriptor,0,3); - CheckBox chkbx_msgHandlingAutoAnswerEnabled = new CheckBox("Auto-reply (to all queries): "); - chkbx_msgHandlingAutoAnswerEnabled.setTooltip(new Tooltip("KST4Contest will answer for you with your pre-definied text to all PMs")); + CheckBox chkbx_msgHandlingAutoAnswerEnabled = new CheckBox("Enable automatic reply to all private messages"); + chkbx_msgHandlingAutoAnswerEnabled.setTooltip(new Tooltip( + "KST4Contest replies with the configured text in the chat category from which the private message was received.\n" + + "The same station can receive one automatic reply per chat category every two minutes.")); chkbx_msgHandlingAutoAnswerEnabled.setSelected(this.chatcontroller.getChatPreferences().isMsgHandling_autoAnswerEnabled()); chkbx_msgHandlingAutoAnswerEnabled.selectedProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { chatcontroller.getChatPreferences().setMessageHandling_autoAnswerEnabled(chkbx_msgHandlingAutoAnswerEnabled.isSelected()); + chatcontroller.getChatPreferences().setMessageHandling_autoAnswerEnabledSecondCat(chkbx_msgHandlingAutoAnswerEnabled.isSelected()); System.out.println("[Main.java, Info]: Autoreply turned on: " + newValue); } }); - CheckBox chkbx_messageHandlingAutoQRGInfoEnabled = new CheckBox("Enable auto-reply with my QRG on QRG-request"); - - String changeMeToPreferences = ""; - changeMeToPreferences += ("ur qrg?\n"); - changeMeToPreferences += ("your qrg?\n"); - changeMeToPreferences += ("qrg?\n"); - changeMeToPreferences += ("freq?\n"); - changeMeToPreferences += ("pse QRG\n"); - - chkbx_messageHandlingAutoQRGInfoEnabled.setTooltip(new Tooltip("KST4Contest can answer with your QRG automatically. Following Strings causing reaction: \n " + changeMeToPreferences)); + CheckBox chkbx_messageHandlingAutoQRGInfoEnabled = new CheckBox("Enable automatic QRG replies"); + String qrgRequestExamples = "ur qrg?\n" + + "your qrg?\n" + + "qrg?\n" + + "freq?\n" + + "pse qrg"; + chkbx_messageHandlingAutoQRGInfoEnabled.setTooltip(new Tooltip( + "KST4Contest replies with the QRG configured for the chat category in which the request was received.\n" + + "Recognized text:\n" + qrgRequestExamples)); chkbx_messageHandlingAutoQRGInfoEnabled.setSelected(this.chatcontroller.getChatPreferences().isMessageHandling_autoAnswerToQRGRequestEnabled()); chkbx_messageHandlingAutoQRGInfoEnabled.selectedProperty().addListener(new ChangeListener() { @Override @@ -10515,22 +10514,22 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL }); TextField txtFld_messageHandlingAutoAnswer = new TextField(); + txtFld_messageHandlingAutoAnswer.setPrefWidth(400); txtFld_messageHandlingAutoAnswer.setText(this.chatcontroller.getChatPreferences().getMessageHandling_autoAnswerTextMainCat()); txtFld_messageHandlingAutoAnswer.textProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observed, String oldString, String newString) { - System.out.println("[Main.java, Info]: Setted the autoanswer: " + txtFld_messageHandlingAutoAnswer.getText().toUpperCase()); - chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextMainCat(txtFld_messageHandlingAutoAnswer.getText().toUpperCase()); - chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextSecondCat(txtFld_messageHandlingAutoAnswer.getText().toUpperCase()); + System.out.println("[Main.java, Info]: Set the auto-answer text: " + newString); + chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextMainCat(newString); + chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextSecondCat(newString); } }); + grdPnlMessageHandlingBeacon.add(chkbx_msgHandlingAutoAnswerEnabled, 0, 1); + grdPnlMessageHandlingBeacon.add(txtFld_messageHandlingAutoAnswer, 1, 1); - grdPnlMessageHandlingBeacon.add(txtFld_messageHandlingAutoAnswer,1,2); - grdPnlMessageHandlingBeacon.add(chkbx_msgHandlingAutoAnswerEnabled,0,2); - - grdPnlMessageHandlingBeacon.add(chkbx_messageHandlingAutoQRGInfoEnabled,0,4, 2,1); + grdPnlMessageHandlingBeacon.add(chkbx_messageHandlingAutoQRGInfoEnabled, 0, 2, 2, 1); VBox vbxMsgHandlBeacon = new VBox(); vbxMsgHandlBeacon.setPadding(new Insets(10, 10, 10, 10));