diff --git a/src/main/java/kst4contest/controller/ChatController.java b/src/main/java/kst4contest/controller/ChatController.java index 881fcc3..4232773 100644 --- a/src/main/java/kst4contest/controller/ChatController.java +++ b/src/main/java/kst4contest/controller/ChatController.java @@ -3981,42 +3981,96 @@ private ObservableList } /** - * decides if a message in the in-queue is directed to me or if its directed to another station and sniffed - * @param chatMessage - * @return + * Checks whether a message belongs to a monitored base callsign. + * + *

QSO monitoring intentionally combines all visible ON4KST variants of + * the same station. An entry for DN9APW therefore also matches DN9APW-2, + * DN9APW-70 and other suffixes. This affects monitoring only; message + * routing continues to use the complete callsign and chat category.

+ * + * @param chatMessage message to examine + * @return true if sender or receiver belongs to a monitored base callsign */ public boolean isSniffedMessage(ChatMessage chatMessage) { - if (chatMessage == null || chatMessage.getSender() == null || chatMessage.getReceiver() == null) { + + if (chatMessage == null + || chatMessage.getSender() == null + || chatMessage.getReceiver() == null) { return false; } - String senderCall = chatMessage.getSender().getCallSign(); - String receiverCall = chatMessage.getReceiver().getCallSign(); + String senderCall = + chatMessage.getSender().getCallSign(); + String receiverCall = + chatMessage.getReceiver().getCallSign(); if (senderCall == null || receiverCall == null) { return false; } - if (lstNotify_QSOSniffer_sniffedCallSignList == null || lstNotify_QSOSniffer_sniffedCallSignList.isEmpty()) { + if (lstNotify_QSOSniffer_sniffedCallSignList == null + || lstNotify_QSOSniffer_sniffedCallSignList.isEmpty()) { return false; } + String senderBaseCall = + ChatMember.normalizeCallSignToBaseCallSign( + senderCall + ); + String receiverBaseCall = + ChatMember.normalizeCallSignToBaseCallSign( + receiverCall + ); + boolean observedCall = - lstNotify_QSOSniffer_sniffedCallSignList.contains(senderCall) - || lstNotify_QSOSniffer_sniffedCallSignList.contains(receiverCall); + lstNotify_QSOSniffer_sniffedCallSignList + .stream() + .anyMatch( + monitoredCall -> { + String monitoredBaseCall = + ChatMember + .normalizeCallSignToBaseCallSign( + monitoredCall + ); + + return monitoredBaseCall != null + && ( + monitoredBaseCall + .equalsIgnoreCase( + senderBaseCall + ) + || monitoredBaseCall + .equalsIgnoreCase( + receiverBaseCall + ) + ); + } + ); if (!observedCall) { return false; } - String myCall = getChatPreferences() != null ? getChatPreferences().getStn_loginCallSign() : null; - String myRawCall = getChatPreferences() != null ? getChatPreferences().getStn_loginCallSignRaw() : null; + String myCall = + getChatPreferences() != null + ? getChatPreferences().getStn_loginCallSign() + : null; + String myRawCall = + getChatPreferences() != null + ? getChatPreferences().getStn_loginCallSignRaw() + : null; /* - * Sniffed messages should appear in the private table only if they are not - * already direct messages to my own callsign. + * Messages which are already addressed directly to the local station + * belong in the PM table without an additional Sniffed marker. */ - return !receiverCall.equals(myCall) && !receiverCall.equals(myRawCall); + boolean directedToOwnCall = + (myCall != null + && receiverCall.equalsIgnoreCase(myCall)) + || (myRawCall != null + && receiverCall.equalsIgnoreCase(myRawCall)); + + return !directedToOwnCall; } /** diff --git a/src/main/java/kst4contest/model/ChatPreferences.java b/src/main/java/kst4contest/model/ChatPreferences.java index a97299a..43b5cf8 100644 --- a/src/main/java/kst4contest/model/ChatPreferences.java +++ b/src/main/java/kst4contest/model/ChatPreferences.java @@ -2631,10 +2631,15 @@ public class ChatPreferences { if (callSign != null && !callSign.isBlank()) { + /* + * Older preference files may still contain complete KST callsigns + * such as DN9APW-2. Monitoring is stored by base callsign so that + * every suffix of the same station is covered by one entry. + */ String normalizedCallSign = - callSign - .trim() - .toUpperCase(); + ChatMember.normalizeCallSignToBaseCallSign( + callSign + ); if (!lstNotify_QSOSniffer_sniffedCallSignList .contains(normalizedCallSign)) { @@ -2660,12 +2665,28 @@ public class ChatPreferences { for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { - String word = child.getTextContent(); - if (word != null) { - word = word.trim(); - } - if (word != null && !word.isEmpty()) { - lstNotify_QSOSniffer_sniffedWordsList.add(word); + String callSign = child.getTextContent(); + + if (callSign != null + && !callSign.isBlank()) { + + /* + * Older preference files may contain complete KST callsigns + * such as DN9APW-2. QSO monitoring is stored by base callsign, + * so one entry covers every suffix of the same station. + */ + String normalizedCallSign = + ChatMember.normalizeCallSignToBaseCallSign( + callSign + ); + + if (normalizedCallSign != null + && !normalizedCallSign.isBlank() + && !lstNotify_QSOSniffer_sniffedCallSignList + .contains(normalizedCallSign)) { + lstNotify_QSOSniffer_sniffedCallSignList + .add(normalizedCallSign); + } } } } diff --git a/src/main/java/kst4contest/view/Kst4ContestApplication.java b/src/main/java/kst4contest/view/Kst4ContestApplication.java index 9eceebf..745402b 100644 --- a/src/main/java/kst4contest/view/Kst4ContestApplication.java +++ b/src/main/java/kst4contest/view/Kst4ContestApplication.java @@ -4775,21 +4775,31 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL callSignColumn.setOnEditCommit(event -> { int row = event.getTablePosition().getRow(); - String newValue = + String enteredCallSign = event.getNewValue() == null ? "" : event.getNewValue() .trim() .toUpperCase(Locale.ROOT); - if (newValue.isBlank()) { + if (enteredCallSign.isBlank()) { event.getTableView() .getItems() .remove(row); return; } - if (!GuiUtils.isCallSignSyntax(newValue)) { + /* + * QSO monitoring intentionally works with the base callsign. + * Entering DN9APW, DN9APW-2 or DN9APW-70 therefore produces + * the same monitoring entry: DN9APW. + */ + String monitoredBaseCall = + ChatMember.normalizeCallSignToBaseCallSign( + enteredCallSign + ); + + if (!GuiUtils.isCallSignSyntax(monitoredBaseCall)) { alertWindowEvent( "Please enter a valid callsign." ); @@ -4813,7 +4823,9 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL .get(i); if (existing != null - && existing.equalsIgnoreCase(newValue)) { + && existing.equalsIgnoreCase( + monitoredBaseCall + )) { duplicate = true; break; } @@ -4821,7 +4833,7 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL if (duplicate) { alertWindowEvent( - "This callsign is already " + "This base callsign is already " + "in the monitoring list." ); event.getTableView().refresh(); @@ -4830,7 +4842,7 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL event.getTableView() .getItems() - .set(row, newValue); + .set(row, monitoredBaseCall); }); table.getColumns().add(callSignColumn); @@ -10915,15 +10927,21 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL dialog.showAndWait().ifPresent( input -> { - String callSign = + String enteredCallSign = input .trim() .toUpperCase( Locale.ROOT ); + String monitoredBaseCall = + ChatMember + .normalizeCallSignToBaseCallSign( + enteredCallSign + ); + if (!GuiUtils.isCallSignSyntax( - callSign + monitoredBaseCall )) { alertWindowEvent( "Please enter " @@ -10938,15 +10956,16 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL .stream() .anyMatch( existing -> - existing + existing != null + && existing .equalsIgnoreCase( - callSign + monitoredBaseCall ) ); if (duplicate) { alertWindowEvent( - "This callsign is already " + "This base callsign is already " + "in the monitoring list." ); return; @@ -10954,7 +10973,7 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL chatcontroller .getLstNotify_QSOSniffer_sniffedCallSignList() - .add(callSign); + .add(monitoredBaseCall); } ); }