diff --git a/CHANGELOG.md b/CHANGELOG.md index 83ca4b5..80a91db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,5 @@ ## Added - Add pyproject.toml file -- requests, packaging.version, psutil -- Lockfile - Changelog text wrapping and formatting - Decouple UI components into modules - Choose from kilometer or miles distance display @@ -17,26 +15,31 @@ - Integrate add/connect widgets into main menu - Favorite/connect/LAN panels integrated with server views - Colorized IP/ID validation +- Copy favorite server IP to clipboard +- Set favorite server from tables +- Detailed/copyable trace in critical error dialogs - Visual icons - Integrated server notebook -- Retain position on servers - Propagate width changes to all tables - Remember tree position in menus +- Show hidden server count after filtering +- Atomic map filters per server context ## Changed - Reduce padding on keys button - Boldface breadcrumbs - Bold labels inside frames -- Unsticky keys when clicking sidebar +- Sidebar buttos do not steal focus - Copy IP copies IP:queryport only instead of IP:gameport:queryport, mimics syntax needed by add by ip method +- Load new model into view without flushing ## Fixed - Longstanding issue with left clicks not registering as tree selection changes after spamming keyboard input - Rare segfaults when changing maps (threading) +- Moved dialogs out of threads ## Unreleased - Setup wizard -- Copy favorite server IP to clipboard -- Set favorite server from tables -- Detailed/copyable trace in critical error dialogs - Local documentation +- Offline mods +- Move debug mode to developers only diff --git a/dzgui/controllers/emitter.py b/dzgui/controllers/emitter.py index 8c15495..2be1efe 100644 --- a/dzgui/controllers/emitter.py +++ b/dzgui/controllers/emitter.py @@ -3,6 +3,7 @@ from typing import Union, TYPE_CHECKING import gi gi.require_version("Gtk", "3.0") +from gi.repository.Gtk import ListStore from gi.repository import Gdk, GObject # noqa E402 if TYPE_CHECKING: @@ -86,14 +87,14 @@ class Emitter(GObject.GObject): def servers_loaded(self, tag: "ServerTab") -> None: pass - # @GObject.Signal( - # flags=GObject.SignalFlags.RUN_LAST, - # arg_types=( - # object, - # object, - # ), - # ) - # def distcalc_ended( - # self, dist: Union[str, None], context: Union["ServerTab", "NotebookPage"] - # ) -> None: - # pass + @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=()) + def servers_loaded_init(self) -> None: + pass + + @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(str,)) + def map_selection_changed(self, map: str) -> None: + pass + + @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(object,)) + def load_maps(self, store: ListStore) -> None: + pass diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index c99c943..2ea5621 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -94,6 +94,7 @@ class Controller(GObject.GObject): self.model_man = ModelManager() self.emitter = Emitter() + self.emitter.connect("map_selection_changed", self._on_map_selection_changed) # NOTE: suppress requests until entire UI is loaded self.loaded = False @@ -235,6 +236,7 @@ class Controller(GObject.GObject): c = self.mediator.statusbar.statusbar.get_context_id(context) self.mediator.statusbar.statusbar.pop(c) + # TODO: @deprecated("use set_by_context") def set_statusbar(self, text: str, context: str) -> int: msg_id = self.mediator.statusbar.set_text(text, context) @@ -350,7 +352,6 @@ class Controller(GObject.GObject): self.open_page(button.opens) def dump_api(self) -> None: - self.first_iteration = True key = self.query_config(Preferences.STEAM) job = Servers.query_api params = Servers.params @@ -379,7 +380,6 @@ class Controller(GObject.GObject): # TODO: additional ping column pass, collated parsed = Servers.parse_json(serv) - self.new_maps = parsed self.push_data(parsed, FilterMode.INITIAL, success=True) def get_help_row(self) -> str: @@ -608,17 +608,17 @@ class Controller(GObject.GObject): import time time.sleep(1) data = ( - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "172.111.51.156:2302", 1, 1, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "172.111.51.156:2302", 1, 1, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], + ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], ) self.push_data(data, FilterMode.INITIAL, success=True) @@ -629,21 +629,25 @@ class Controller(GObject.GObject): treeview = self.get_active_treeview() treeview.set_loaded(True) treeview.set_model(self.to_insert) + map_man = treeview.get_map_man() # TODO: signals or other approach to deferring map # model insertion after thread closes # cf. servers_loaded signal - # CHORE: this is placeholder logic - if self.first_iteration: - self.mediator.filters.set_unique_maps(self.new_maps) - self.first_iteration = False context = self.get_active_context() self.emitter.emit("servers_loaded", context) + # CHORE: this is placeholder logic + if self.first_iteration: + map_man.set_unique_maps(self.new_maps) + self.emitter.emit("servers_loaded_init") + self.first_iteration = False + self.new_maps = None + + treeview.grab_focus() - # TODO: chiefly responsible for removing spinner dialog self.destroy_on_idle() #if self.success is False: # # TODO: different dialogs for server tab contexts, e.g. lan timeout @@ -655,13 +659,15 @@ class Controller(GObject.GObject): # TODO: what if refresh action occurred, and the old model is valid? treeview = self.get_active_treeview() treeview.set_model(None) + map_man = treeview.get_map_man() # TODO: disable map, keyword, and filter widgets if model is None? # -> signal driven (servers_empty) # would have to make those unsensitive when changing server tabs # if model is not None when changing tab, emit other signal - self.mediator.filters.set_unique_maps(None) + map_man.set_unique_maps(None) context = self.get_active_context() + # TODO: distinguish signals, e.g. "servers_failed_to_load" self.emitter.emit("servers_loaded", context) treeview.grab_focus() self.destroy_on_idle() @@ -693,6 +699,10 @@ class Controller(GObject.GObject): manager.set_control(data) manager.filter(mode) self.to_insert = manager.get_model() + # TODO: pre parse maps + u_maps = set([row[1] for row in data]) + self.new_maps = sorted(u_maps) + treeview.set_loaded(True) GLib.idle_add(self.cleanup) @@ -714,6 +724,9 @@ class Controller(GObject.GObject): self.callback = {"func": callback, "args": args} def destroy_on_idle(self) -> None: + """ + TODO: chiefly responsible for removing spinner dialog + """ self.wait_dialog.destroy() func = self.get_callback() self.mediator.window.set_sensitive(True) @@ -790,7 +803,8 @@ class Controller(GObject.GObject): def get_player_count(self) -> str: treeview = self.get_active_treeview() model = treeview.get_model() - control_model = treeview.filter_man.get_control() + filter_man = treeview.get_filter_man() + control_model = filter_man.get_control() count = format_player_count(model, control_model) return count @@ -804,13 +818,16 @@ class Controller(GObject.GObject): @call_on_thread(strings.dialog.filtering) def filter_threaded(self, mode: FilterMode, label: str) -> None: tv = self.get_active_treeview() - tv.filter_man.filter(mode, label) + filter_man = tv.get_filter_man() + filter_man.filter(mode, label) self.push_data("", mode, success=True) # FIXME: optional label/map/keyword parameter + # FIXME: drop set_callback def refilter_model(self, mode: FilterMode, label: Optional[str] = None) -> None: tv = self.get_active_treeview() - if tv.filter_man.get_control() is None: + filter_man = tv.get_filter_man() + if filter_man.get_control() is None: return # TODO: deprecated in this context? self.set_callback(None, None) @@ -827,10 +844,12 @@ class Controller(GObject.GObject): func = treeview.get_query_func() if func is None: self.emitter.emit("servers_loaded", treeview.get_enum()) + treeview.set_model(None) return # TODO: # manager = treeview.get_filter_man() # manager.clear_model() + self.first_iteration = True self.set_callback(None, None) self.run_query_func(func) @@ -850,9 +869,6 @@ class Controller(GObject.GObject): def get_help_store(self) -> Gtk.ListStore: return self.model_man.get_help_store() - def get_map_store(self) -> Gtk.ListStore: - return self.model_man.get_map_store() - def get_modlist_store(self) -> Gtk.ListStore: return self.model_man.get_modlist_store() @@ -865,11 +881,31 @@ class Controller(GObject.GObject): def get_filters(self) -> list: return self.mediator.filters.get_filters() + # TODO: filterman calls back to here, gets convoluted def get_keyword(self) -> str: return self.mediator.filters.get_keyword_filter() - def get_map(self) -> str: - return self.mediator.filters.get_selected_map() + def get_map_store(self) -> Gtk.ListStore: + treeview = self.get_active_treeview() + map_man = treeview.get_map_man() + return map_man.get_map_store() + + def get_selected_map(self) -> str: + treeview = self.get_active_treeview() + map_man = treeview.get_map_man() + return map_man.get_selected_map() def get_prior_map(self) -> str: - return self.mediator.filters.get_prior_map() + treeview = self.get_active_treeview() + map_man = treeview.get_map_man() + return map_man.get_prior_map() + + def _on_map_selection_changed(self, emitter: Emitter, selection: str) -> None: + treeview = self.get_active_treeview() + map_man = treeview.get_map_man() + map_man.set_selected_map(selection) + self.refilter_model(FilterMode.MAP) + + def has_server_model(self) -> bool: + treeview = self.get_active_treeview() + return treeview.get_model() is not None diff --git a/dzgui/data/CHANGELOG.md b/dzgui/data/CHANGELOG.md index 83ca4b5..80a91db 100644 --- a/dzgui/data/CHANGELOG.md +++ b/dzgui/data/CHANGELOG.md @@ -1,7 +1,5 @@ ## Added - Add pyproject.toml file -- requests, packaging.version, psutil -- Lockfile - Changelog text wrapping and formatting - Decouple UI components into modules - Choose from kilometer or miles distance display @@ -17,26 +15,31 @@ - Integrate add/connect widgets into main menu - Favorite/connect/LAN panels integrated with server views - Colorized IP/ID validation +- Copy favorite server IP to clipboard +- Set favorite server from tables +- Detailed/copyable trace in critical error dialogs - Visual icons - Integrated server notebook -- Retain position on servers - Propagate width changes to all tables - Remember tree position in menus +- Show hidden server count after filtering +- Atomic map filters per server context ## Changed - Reduce padding on keys button - Boldface breadcrumbs - Bold labels inside frames -- Unsticky keys when clicking sidebar +- Sidebar buttos do not steal focus - Copy IP copies IP:queryport only instead of IP:gameport:queryport, mimics syntax needed by add by ip method +- Load new model into view without flushing ## Fixed - Longstanding issue with left clicks not registering as tree selection changes after spamming keyboard input - Rare segfaults when changing maps (threading) +- Moved dialogs out of threads ## Unreleased - Setup wizard -- Copy favorite server IP to clipboard -- Set favorite server from tables -- Detailed/copyable trace in critical error dialogs - Local documentation +- Offline mods +- Move debug mode to developers only diff --git a/dzgui/model/filtered_model.py b/dzgui/model/filtered_model.py index b751dd9..2e2b6d6 100644 --- a/dzgui/model/filtered_model.py +++ b/dzgui/model/filtered_model.py @@ -47,7 +47,8 @@ class FilteredModelManager: self.filter_cache = {} self.ping_cache: dict[str, int] = {} - self.ephemeral_model = self.new_model_from_class(ServerColumns) + self.ephemeral_model: ListStore = None + #= self.new_model_from_class(ServerColumns) self.control_model: list = None self.filtered: list = None @@ -107,13 +108,14 @@ class FilteredModelManager: if row[7] in self.ping_cache: row[9] = self.ping_cache[row[7]] + clone = self.new_model_from_class(ServerColumns) if len(rows) > 0: - clone = self.new_model_from_class(ServerColumns) rows = self.sort_rows(rows) for row in rows: clone.append(row) - else: - clone = None + #else: + # print("nothing to filter, sending none") + # clone = None self.set_cache(filters, clone, rows) self.set_model(clone) @@ -136,7 +138,7 @@ class FilteredModelManager: Multi-filtration for any context starts by narrowing by map """ rows = self.filtered - sel_map = self.controller.get_map() + sel_map = self.controller.get_selected_map() if sel_map == strings.all_maps: return rows diff --git a/dzgui/model/misc_model.py b/dzgui/model/misc_model.py index 08b6978..0fe97c9 100644 --- a/dzgui/model/misc_model.py +++ b/dzgui/model/misc_model.py @@ -5,7 +5,7 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository.Gtk import ListStore # noqa E402 -from gi.repository import GLib, GObject, Gtk # noqa E402 +from gi.repository import GObject, Gtk # noqa E402 @dataclass(slots=True, frozen=True) diff --git a/dzgui/util/format.py b/dzgui/util/format.py index 9b06e30..3d462f5 100644 --- a/dzgui/util/format.py +++ b/dzgui/util/format.py @@ -55,16 +55,18 @@ def format_player_count(model: Gtk.TreeModel | None, control: list) -> str: players = 0 hits: int status: str - if model is None or len(model) == 0: + if model is None: return no_servers else: hits = len(model) for row in model: players += row[4] control_total = len(control) + hits_pretty = pluralize("matches", hits) players_pretty = pluralize("players", players) - control_pretty = pluralize("matches", control_total) - status = f"Showing {hits:n}/{control_total:n} {control_pretty} with {players:n} {players_pretty}" + hidden = control_total - hits + hidden_pretty = f" ({hidden:n} hidden)" if hidden > 0 else "" + status = f"Showing {hits:n} {hits_pretty}{hidden_pretty}, {players:n} {players_pretty}." return status diff --git a/dzgui/util/strings.py b/dzgui/util/strings.py index 4e4ecb2..0e43df0 100644 --- a/dzgui/util/strings.py +++ b/dzgui/util/strings.py @@ -167,7 +167,7 @@ ping_tooltip = ( ) # statusbar_helptext = "Select a row to see its detailed description" -statusbar_helptext = "No server metadata to list." +#statusbar_helptext = "No server metadata to list." # use e.g. filters.1pp filter_1pp = "1PP" diff --git a/dzgui/views/components/filter_panel.py b/dzgui/views/components/filter_panel.py index bd80573..ad89a34 100644 --- a/dzgui/views/components/filter_panel.py +++ b/dzgui/views/components/filter_panel.py @@ -17,6 +17,7 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: from dzgui.controllers.mc import Controller from dzgui.controllers.emitter import Emitter + from dzgui.const.enum import ServerTab class FilterPanel(Gtk.Box): @@ -49,10 +50,10 @@ class FilterPanel(Gtk.Box): self.enabled_filters = dict(self.default_filters) self.keyword_filter = "" - self.selected_map: str = strings.all_maps - self.prior_map: str = strings.all_maps + #self.selected_map: str = strings.all_maps + #self.prior_map: str = strings.all_maps - button_grid = Gtk.Grid( + self.button_grid = Gtk.Grid( halign=Gtk.Align.CENTER, column_spacing=5, column_homogeneous=True ) row = 1 @@ -70,7 +71,7 @@ class FilterPanel(Gtk.Box): if col > 3: row += 1 col = 1 - button_grid.attach(checkbox, col, row, 1, 1) + self.button_grid.attach(checkbox, col, row, 1, 1) checkbox.connect("toggled", self._on_check_toggled) self.checks.append(checkbox) @@ -103,6 +104,8 @@ class FilterPanel(Gtk.Box): "request_maps_focus", lambda _: self.maps_entry.grab_focus() ) self.emitter.connect("check_button_pressed", self.toggle_check_by_key) + self.emitter.connect("servers_loaded", self._on_servers_loaded) + self.emitter.connect("load_maps", self._on_maps_loaded) completion = Gtk.EntryCompletion(inline_completion=True) completion.set_text_column(0) @@ -123,26 +126,22 @@ class FilterPanel(Gtk.Box): self.maps_combo.connect("changed", self._on_map_changed) self.maps_combo.connect("key-press-event", self._on_combo_keypress) - for el in self.filters_label, self.keyword_entry, self.maps_combo, button_grid: + for el in self.filters_label, self.keyword_entry, self.maps_combo, self.button_grid: self.pack_start(el, NO_EXPAND, NO_FILL, NO_PADDING) - def set_unique_maps(self, maps: list) -> None: - if maps is None: - return - if len(maps) < 1: - return - u_maps = set([row[1] for row in maps]) - u_maps = sorted(u_maps) - self.controller.append_map([strings.all_maps]) - self.selected_map = strings.all_maps - for m in u_maps: - self.controller.append_map([m]) - self.maps_hr.append(m) + def _on_servers_loaded(self, emitter: "Emitter", tab: "ServerTab") -> None: + state = self.controller.has_server_model() + for widget in (self.keyword_entry, self.maps_combo, self.button_grid): + widget.set_sensitive(state) + + def _on_maps_loaded(self, emitter: "Emitter", store: Gtk.ListStore) -> None: + self.maps_combo.set_model(store) self.maps_combo.set_active(0) def get_filters(self) -> tuple: + selected = self.controller.get_selected_map() filters = [] - filters.append(self.selected_map) + filters.append(selected) filters.append(self.keyword_filter) for k in self.enabled_filters: if not self.enabled_filters[k]: @@ -205,8 +204,9 @@ class FilterPanel(Gtk.Box): def _on_map_completion(self, entry, editable): text = entry.get_text() completion = entry.get_completion() + store = self.controller.get_map_store() if len(text) >= completion.get_minimum_key_length(): - completion.set_model(self.map_store) + completion.set_model(store) def restore_focus_to_treeview(self) -> Literal[False]: view = self.controller.get_active_treeview() @@ -232,15 +232,6 @@ class FilterPanel(Gtk.Box): case _: return False - def set_prior_map(self, mapname: str) -> None: - self.prior_map = mapname - - def get_prior_map(self) -> str: - return self.prior_map - - def get_selected_map(self) -> str: - return self.selected_map - def get_keyword_filter(self) -> str: return self.keyword_filter @@ -293,7 +284,6 @@ class FilterPanel(Gtk.Box): check.set_active(not state) def _on_check_toggled(self, button: Gtk.CheckButton) -> None: - # treeview = self.controller.get_active_treeview() label = button.get_label() state = button.get_active() logger.info(f"User toggled button '{label}' to {state}") @@ -306,7 +296,7 @@ class FilterPanel(Gtk.Box): self.controller.refilter_model(mode, label) def _on_map_changed(self, combo: Gtk.ComboBox) -> None: - old_sel = self.selected_map + old_sel = self.controller.get_selected_map() model = combo.get_model() tree_iter = combo.get_active_iter() if tree_iter is None: @@ -317,7 +307,5 @@ class FilterPanel(Gtk.Box): if not selection: return logger.info(f"User selected map '{selection}'") - self.prior_map = self.selected_map - self.selected_map = selection self.maps_entry.set_text(selection) - self.controller.refilter_model(FilterMode.MAP) + self.emitter.emit("map_selection_changed", selection) diff --git a/dzgui/views/components/statusbar.py b/dzgui/views/components/statusbar.py index f442422..9f4a465 100644 --- a/dzgui/views/components/statusbar.py +++ b/dzgui/views/components/statusbar.py @@ -112,7 +112,7 @@ class Statusbar(Gtk.Grid): self.set_by_context(context, pretty) def append_distance(self, dist: str) -> str: - return f"{self.playercount} | Distance: {dist}" + return f"{self.playercount} Distance: {dist}" def _on_servers_loaded(self, statusbar: Self, context: "ServerTab") -> None: count = self.controller.get_player_count() diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py index 85a6a23..460d104 100644 --- a/dzgui/views/trees/tree_servers.py +++ b/dzgui/views/trees/tree_servers.py @@ -7,6 +7,7 @@ from warnings import deprecated from dzgui.views.mixins.context_mixin import ContextMixin from dzgui.const.enum import ContextMenuGroup, ServerTab from dzgui.api.servers import Record +from dzgui.model.map_model import MapManager from dzgui.model.filtered_model import FilteredModelManager from dzgui.util.dist import CalcDist from dzgui.util import strings @@ -47,6 +48,9 @@ class ServerTreeView(ContextMixin, TreeView): model = self.filter_man.get_model() self.set_model(model) + # NOTE: each tab context has its own unique maps + self.map_man = MapManager() + self.set_fixed_height_mode(True) self.set_headers_visible(True) @@ -100,14 +104,26 @@ class ServerTreeView(ContextMixin, TreeView): column.connect("notify::fixed-width", self._on_col_width_changed) self.append_column(column) - self.connect("key-press-event", self._on_server_keypress) + self.connect("button-press-event", self.present_menu) self.connect("generic_row_activated", self._parent_row_activated) self.connect("generic_treesel_changed", self._parent_selection_changed) + self.connect("key-press-event", self._on_server_keypress) + self.connect("key-press-event", self.present_menu) self.connect("map", self._on_map) self.connect("unmap", self._on_unmap) - self.connect("key-press-event", self.present_menu) - self.connect("button-press-event", self.present_menu) + self.emitter.connect("servers_loaded_init", self._on_servers_loaded_init) + self.emitter.connect("servers_loaded", self._on_servers_loaded) + + def _on_servers_loaded(self, emitter: "Emitter", tab: "ServerTab") -> None: + state = self.controller.has_server_model() + self.set_headers_clickable(state) + + def _on_servers_loaded_init(self, emitter: "Emitter") -> None: + if self.loaded is False: + return + store = self.map_man.get_map_store() + self.emitter.emit("load_maps", store) def _get_ping( self, @@ -145,6 +161,9 @@ class ServerTreeView(ContextMixin, TreeView): def start_timeout(self) -> None: self.queue_id = GLib.timeout_add(QUEUE_CHECK_DELAY, self._check_result_queue) + def get_map_man(self) -> MapManager: + return self.map_man + def get_filter_man(self) -> FilteredModelManager: return self.filter_man @@ -174,10 +193,13 @@ class ServerTreeView(ContextMixin, TreeView): return self.enum def _on_map(self, a) -> None: + # TODO: disable filter panel if current model is None if self.get_enum() is ServerTab.LAN: self.emitter.emit("lan_tab_toggled", True) # FIXME: only if the tab is active + store = self.map_man.get_map_store() + self.emitter.emit("load_maps", store) self.handler_id = self.emitter.connect("statusbar_loaded", self.start_distcalc) self.start_timeout() self.start_distcalc()