From 4535a190201a1ba57d5a226fa45340bae41dbe2a Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 25 Apr 2026 22:00:14 +0900 Subject: [PATCH] chore: move mod actions into ModManager (WIP) --- dzgui/controllers/mc.py | 160 +++++++++++++------------- dzgui/model/proxy_model.py | 7 +- dzgui/model/servers.py | 9 -- dzgui/views/mixins/help_menu_mixin.py | 2 - 4 files changed, 81 insertions(+), 97 deletions(-) diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index b15b3f9..4344f92 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -147,7 +147,6 @@ class Controller(GObject.GObject): logger.critical(f"{attr} is not a valid AppNavigation attribute.") def get_prefs(self) -> UserPrefs: - # return self.config_man.get_prefs() return self.prefs def set_prefs(self, prefs: UserPrefs) -> None: @@ -200,7 +199,7 @@ class Controller(GObject.GObject): msg_id = self.mediator.statusbar.set_text(text, context) return msg_id - # TODO: StatusBarManager + # TODO: StatusBarManager, move out of here def set_statusbar_dist(self, haversine: "Haversine", enum: "ServerTab") -> None: """ NOTE: prevents race condition when server tab changed, @@ -230,30 +229,6 @@ class Controller(GObject.GObject): self.emitter.emit("distcalc_ended", dist, context) - def delete_multiple_mods(self) -> None: - sel = self.mediator.modtreeview.get_selection() - model, pathlist = sel.get_selected_rows() - # NOTE: reverse when multiple selection - for path in reversed(pathlist): - self.delete_single_mod(path) - - total_mods, total_size = self.calc_mod_size() - self.update_mod_statusbar() - - def load_mods_cleanup(self, model: Gtk.ListStore) -> None: - self.mediator.modtreeview.set_model(model) - self.emitter.emit("mod_page_loaded") - - # TODO: delegate to threadmanager - @call_on_thread(strings.dialog.modlist) - def load_mods(self) -> None: - model = ModelFactory().make_mod_store() - path = self.query_config(Preferences.DEFAULT) - mods = get_delimited_mods(Path(path)) - model.extend(mods) - - self.cleanup_func = StoredFunc(self.load_mods_cleanup, model) - def toggle_config(self, key: Preferences) -> None: # NOTE: Preferences.DIST is dynamic if key == Preferences.DIST: @@ -303,6 +278,80 @@ class Controller(GObject.GObject): client = self.query_config(Preferences.CLIENT) open_user_workshop(uid, client) + ### START LOAD MODS LOGIC + + def uncolorize_mods(self) -> None: + model = self.get_mod_store() + for mod in model: + it = mod.iter + path = model.get_path(it) + model[path][4] = None + self.mediator.modtreeview.set_cursor(0) + + def highlight_stale_cleanup(self, stale_mods: list) -> None: + """Manipulates attached ListStore in the main event loop""" + model = self.get_mod_store() + for mod in model: + it = mod.iter + path = model.get_path(it) + if int(mod[2]) in stale_mods: + model[path][4] = True + self.emitter.emit("mods_highlighted") + + # TODO: delegate to mod manager + @call_on_thread(strings.dialog.working) + def highlight_stale(self) -> None: + # TODO: set progress bar for number of mods + stale = find_stale_mods(self.prefs.paths.config) + self.cleanup_func = StoredFunc(self.highlight_stale_cleanup, stale) + + def set_cleanup_func(self, func: StoredFunc) -> None: + self.cleanup_func = func + + def get_cleanup_func(self) -> StoredFunc: + return self.cleanup_func + + def _destroy_on_idle(self) -> None: + self.wait_dialog.destroy() + func = self.get_cleanup_func() + if func is not None: + func.call() + self.set_cleanup_func(None) + self.mediator.window.set_sensitive(True) + + def toggle_mod_selection(self, state: bool) -> None: + sel = self.mediator.modtreeview.get_selection() + if state: + sel.select_all() + else: + sel.unselect_all() + # TODO: signal + self.mediator.modtreeview.grab_focus() + + def load_mods_cleanup(self, model: Gtk.ListStore) -> None: + self.mediator.modtreeview.set_model(model) + self.emitter.emit("mod_page_loaded") + + # TODO: delegate to threadmanager + @call_on_thread(strings.dialog.modlist) + def load_mods(self) -> None: + model = ModelFactory().make_mod_store() + path = self.query_config(Preferences.DEFAULT) + mods = get_delimited_mods(Path(path)) + model.extend(mods) + + self.cleanup_func = StoredFunc(self.load_mods_cleanup, model) + + def delete_multiple_mods(self) -> None: + sel = self.mediator.modtreeview.get_selection() + model, pathlist = sel.get_selected_rows() + # NOTE: reverse when multiple selection + for path in reversed(pathlist): + self.delete_single_mod(path) + + total_mods, total_size = self.calc_mod_size() + self.update_mod_statusbar() + def delete_single_mod_cleanup(self, _iter: Gtk.TreeIter) -> None: self.get_mod_store().remove(_iter) remove_stale_signatures(self.prefs.paths.config, self.prefs.paths.version) @@ -335,9 +384,6 @@ class Controller(GObject.GObject): self.cleanup_func = StoredFunc(self.delete_single_mod_cleanup, _iter) - def get_mod_store(self) -> Gtk.ListStore: - return self.mediator.modtreeview.get_model() - def format_mod_statusbar(self) -> str: total_mods, total_size = self.calc_mod_size() msg = format_mods(total_size, total_mods) @@ -353,6 +399,11 @@ class Controller(GObject.GObject): total_size += mod[3] return total_mods, total_size + ### END LOAD MODS LOGIC + + def get_mod_store(self) -> Gtk.ListStore: + return self.mediator.modtreeview.get_model() + def set_fav(self) -> None: treeview = self.get_active_treeview() name = treeview.get_value_at_index(0) @@ -373,15 +424,6 @@ class Controller(GObject.GObject): context_man = ContextMenuManager(tree, self) context_man.process(action) - def toggle_mod_selection(self, state: bool) -> None: - sel = self.mediator.modtreeview.get_selection() - if state: - sel.select_all() - else: - sel.unselect_all() - # TODO: signal - self.mediator.modtreeview.grab_focus() - def populate_log(self) -> None: log = self.prefs.paths.debug try: @@ -400,51 +442,10 @@ class Controller(GObject.GObject): if mod[4] == HEX_RED: sel.select_path(path) - # TODO: make as method of tree? - # TODO: could have a LocalModManager that accepts button enums - def uncolorize_mods(self) -> None: - model = self.get_mod_store() - for mod in model: - it = mod.iter - path = model.get_path(it) - model[path][4] = None - self.mediator.modtreeview.set_cursor(0) - def get_filter_man(self) -> "FilterManager": """Each ServerTreeView has an atomic FilterManager""" return self.get_active_treeview().get_filter_man() - def highlight_stale_cleanup(self, stale_mods: list) -> None: - """Manipulates attached ListStore in the main event loop""" - model = self.get_mod_store() - for mod in model: - it = mod.iter - path = model.get_path(it) - if int(mod[2]) in stale_mods: - model[path][4] = True - self.emitter.emit("mods_highlighted") - - # TODO: delegate to mod manager - @call_on_thread(strings.dialog.working) - def highlight_stale(self) -> None: - # TODO: set progress bar for number of mods - stale = find_stale_mods(self.prefs.paths.config) - self.cleanup_func = StoredFunc(self.highlight_stale_cleanup, stale) - - def set_cleanup_func(self, func: StoredFunc) -> None: - self.cleanup_func = func - - def get_cleanup_func(self) -> StoredFunc: - return self.cleanup_func - - def _destroy_on_idle(self) -> None: - self.wait_dialog.destroy() - func = self.get_cleanup_func() - if func is not None: - func.call() - self.set_cleanup_func(None) - self.mediator.window.set_sensitive(True) - def dump_diagnostics(self) -> None: picker = FilePicker(self.mediator.window) file = picker.pick_file() @@ -511,7 +512,6 @@ class Controller(GObject.GObject): def get_filters(self) -> list: return self.mediator.filters.get_filters() - # TODO: clean up routes between controller and filter panel def get_map_store(self) -> Gtk.ListStore: filter_man = self.get_filter_man() return filter_man.get_map_store() diff --git a/dzgui/model/proxy_model.py b/dzgui/model/proxy_model.py index cad4e17..13e89e2 100644 --- a/dzgui/model/proxy_model.py +++ b/dzgui/model/proxy_model.py @@ -1,6 +1,5 @@ import re -from collections import deque from typing import Any, Optional, TYPE_CHECKING from warnings import deprecated @@ -97,7 +96,6 @@ class ProxyModelManager: if skip_cache is False: if filters in self.filter_cache: - print("already in cache, not updating proxy model") cache = self.filter_cache[filters] self.set_proxy_model(cache[0]) self.set_filtered(cache[1]) @@ -106,17 +104,14 @@ class ProxyModelManager: match mode: case FilterMode.INITIAL: rows = self.filter_initial(filters) - - # TODO: consolidate into one enum case FilterMode.TOGGLE_ON: rows = self.filter_toggle_on(filters) - case FilterMode.TOGGLE_OFF: for f in filters[2:]: self.set_filtered(self.filter_toggle_off(filters, f)) rows = self.filtered - # NOTE: this FastInsertListStore manipulation must remain local to the thread + # NOTE: FastInsertListStore manipulation must remain local to the thread clone = ModelFactory().make_server_store() if len(rows) > 0: rows = self.sort_rows(rows) diff --git a/dzgui/model/servers.py b/dzgui/model/servers.py index 1ba50c8..6cd978f 100644 --- a/dzgui/model/servers.py +++ b/dzgui/model/servers.py @@ -31,10 +31,6 @@ if TYPE_CHECKING: logger = logging.getLogger(__name__) -# TODO: failure should spawn error dialog -# TODO: non failure with empty model: updates statusbar with help text - - @dataclass class NewPlayerCount: treeiter: Gtk.TreeIter @@ -357,11 +353,6 @@ class ServerModelManager: proxy = self._get_proxy_man().get_proxy_model() self.tv.set_model(proxy) - # TODO: make sure control model len is N + 1 - # TODO: signals or other approach to deferring map - # model insertion after thread closes - # cf. servers_loaded signal - # TODO: servers_loaded vs servers_reloaded self.emitter.emit("servers_loaded", self.enum) diff --git a/dzgui/views/mixins/help_menu_mixin.py b/dzgui/views/mixins/help_menu_mixin.py index 3b2870e..1af135d 100644 --- a/dzgui/views/mixins/help_menu_mixin.py +++ b/dzgui/views/mixins/help_menu_mixin.py @@ -1,7 +1,5 @@ from typing import Literal -from dzgui.const.enum import NotebookPage - import gi gi.require_version("Gtk", "3.0")