diff --git a/app-desktop/src/main/java/kst4contest/view/Kst4ContestApplication.java b/app-desktop/src/main/java/kst4contest/view/Kst4ContestApplication.java index b42d52cf..8039929f 100644 --- a/app-desktop/src/main/java/kst4contest/view/Kst4ContestApplication.java +++ b/app-desktop/src/main/java/kst4contest/view/Kst4ContestApplication.java @@ -3034,7 +3034,8 @@ public class Kst4ContestApplication implements StatusUpdateListener, SettingsHos member -> parseTableDouble(formatPriorityScore(member)), (member, band, worked) -> formatBandCellStatus(member, band, worked), BandOpportunityResolver.getEnabledStationBands(chatcontroller.getChatPreferences())), - RowKeys.INSTANCE.byValue(ChatMember::getCallSign), + RowKeys.INSTANCE.byValue(member -> member.getCallSign() + "|" + + (member.getChatCategory() == null ? "" : member.getChatCategory().getCategoryNumber())), "compose-stations", widths); @@ -3222,6 +3223,11 @@ public class Kst4ContestApplication implements StatusUpdateListener, SettingsHos composeMemberListener = rows -> uiDispatcher.runOnUi(() -> stations.replaceRows(rows)); chatcontroller.getLst_chatMemberList().addListener(composeMemberListener); + composeMainWindowState.setStationSelector(member -> { + selectStationInCompose(selectedStation, stations, member); + return kotlin.Unit.INSTANCE; + }); + composeChatListener = rows -> uiDispatcher.runOnUi(() -> { directed.replaceRows(chatcontroller.toMeMessages()); publicMessages.replaceRows(rows); diff --git a/app-desktop/src/main/kotlin/kst4contest/view/compose/DataTableState.kt b/app-desktop/src/main/kotlin/kst4contest/view/compose/DataTableState.kt index 3988d1fa..057b60ca 100644 --- a/app-desktop/src/main/kotlin/kst4contest/view/compose/DataTableState.kt +++ b/app-desktop/src/main/kotlin/kst4contest/view/compose/DataTableState.kt @@ -318,12 +318,12 @@ class DataTableState( * rows jump. */ val order = column.comparator - ?: compareBy(currentRows.associateWith { column.value(it) }::getValue) + ?: compareBy(filteredRows.associateWith { column.value(it) }::getValue) if (ascending) { - currentRows.sortedWith(order) + filteredRows.sortedWith(order) } else { - currentRows.sortedWith(order.reversed()) + filteredRows.sortedWith(order.reversed()) } } diff --git a/app-desktop/src/main/kotlin/kst4contest/view/compose/MainWindowState.kt b/app-desktop/src/main/kotlin/kst4contest/view/compose/MainWindowState.kt index c2a7c09d..a3371881 100644 --- a/app-desktop/src/main/kotlin/kst4contest/view/compose/MainWindowState.kt +++ b/app-desktop/src/main/kotlin/kst4contest/view/compose/MainWindowState.kt @@ -62,6 +62,13 @@ class MainWindowState( ) { /** The shortcut buttons above the send line. */ + /** + * The one path that selects a station for the whole application (panel, table, score + * service, send line). Set by the host after construction; other windows, such as the + * map, go through it instead of touching [selectedStation] alone. Null clears. + */ + var stationSelector: ((ChatMember?) -> Unit)? = null + val shortcuts = RosterMirror(prefs.getLst_txtShortCutBtnList()) /** The snippets behind Ctrl+1..Ctrl+0 and the right-click menus. */ diff --git a/app-desktop/src/main/kotlin/kst4contest/view/compose/map/StationMapWindow.kt b/app-desktop/src/main/kotlin/kst4contest/view/compose/map/StationMapWindow.kt index 388ef923..98710e8b 100644 --- a/app-desktop/src/main/kotlin/kst4contest/view/compose/map/StationMapWindow.kt +++ b/app-desktop/src/main/kotlin/kst4contest/view/compose/map/StationMapWindow.kt @@ -217,7 +217,8 @@ object StationMapWindow { } kst4contest.view.compose.Form.button(strings.mapResetView) { - mainWindowState.selectedStation.select(null) + mainWindowState.stationSelector?.invoke(null) + ?: mainWindowState.selectedStation.select(null) val home = runCatching { kst4contest.locatorUtils.Location(ownLocator6) }.getOrNull() @@ -277,10 +278,22 @@ object StationMapWindow { darkMode = isDarkTheme, onMarkerClicked = { snapshot -> val chatController = ApplicationRuntimeLauncher.getCurrent()?.chatController - val member = chatController?.lst_chatMemberList?.snapshot()?.find { it.callSignRaw == snapshot.callSignRaw() } + val variants = chatController?.lst_chatMemberList?.snapshot() + ?.filter { it.callSignRaw == snapshot.callSignRaw() } + .orEmpty() + /* + * A marker stands for a raw callsign, not a category. Keep the + * category already selected when it is one of the variants. + */ + val member = variants.firstOrNull { it === mainWindowState.selectedStation.selected } + ?: variants.firstOrNull() if (member != null) { - mainWindowState.selectedStation.select(member) - + val selector = mainWindowState.stationSelector + if (selector != null) { + selector(member) + } else { + mainWindowState.selectedStation.select(member) + } // Mirror old JavaFX handleMapCallsignSelection logic: prefill /cq mainWindowState.chatInput.prepareCq(member.callSign ?: "", forceOverwrite = true) }