From bdfebf9a694e4affa6f337abb632a4593e0c533b Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:03:46 +0900 Subject: [PATCH] chore: change modelman to model factory --- dzgui/const/enum.py | 27 +++-------- dzgui/controllers/mc.py | 42 +++-------------- dzgui/model/misc_model.py | 82 ---------------------------------- dzgui/model/model_factory.py | 82 ++++++++++++++++++++++++++++++++++ dzgui/views/trees/tree_log.py | 10 +++-- dzgui/views/trees/tree_menu.py | 14 ++++-- 6 files changed, 110 insertions(+), 147 deletions(-) delete mode 100644 dzgui/model/misc_model.py create mode 100644 dzgui/model/model_factory.py diff --git a/dzgui/const/enum.py b/dzgui/const/enum.py index 1162a95..656782e 100644 --- a/dzgui/const/enum.py +++ b/dzgui/const/enum.py @@ -26,14 +26,6 @@ class Popup(Enum): QUIT = 8 -class Command(Enum): - INTERACTIVE = 1 - ONESHOT = 2 - HELP = 3 - TOGGLE = 4 - THANKS = 5 - - class VAdjustment(Enum): UP = 1 DOWN = 2 @@ -111,14 +103,14 @@ class Preferences(EnumWithAttrs): class NotebookPage(EnumWithAttrs): CHANGELOG = {"crumbs": strings.crumbs.changelog, "statusbar": True} + DEVELOPERS = {"crumbs": strings.crumbs.developers, "statusbar": False} + HELP = {"crumbs": strings.crumbs._help, "statusbar": True} KEYS = {"crumbs": strings.crumbs.keys, "statusbar": True} LOG = {"crumbs": strings.crumbs.log, "statusbar": True} - HELP = {"crumbs": strings.crumbs._help, "statusbar": True} MODS = {"crumbs": strings.crumbs.mods, "statusbar": True} OPTIONS = {"crumbs": strings.crumbs.options, "statusbar": False} SERVERS = {"crumbs": strings.crumbs.servers, "statusbar": True} THANKS = {"crumbs": strings.crumbs.thanks, "statusbar": True} - DEVELOPERS = {"crumbs": strings.crumbs.developers, "statusbar": False} class RowType(EnumWithAttrs): @@ -128,7 +120,7 @@ class RowType(EnumWithAttrs): if string == member.dict["label"]: return member - # TODO: add to strings + # TODO: add to notebook tab tooltips # SERVER_BROWSER = { # "label": "Server browser", # "tooltip": "Used to browse the global server list", @@ -155,6 +147,7 @@ class RowType(EnumWithAttrs): # "quad_label": "Mods", # "type": "mods", # } + # TODO: strings CHANGELOG = { "label": "View changelog", "tooltip": "Opens the DZGUI changelog", @@ -162,7 +155,6 @@ class RowType(EnumWithAttrs): SHOW_LOG = { "label": "Show debug log", "tooltip": "Read the DZGUI log generated since startup", - "quad_label": "Debug log", } SEPARATOR = { "label": "SEPARATOR", @@ -171,43 +163,34 @@ class RowType(EnumWithAttrs): DUMP_LOG = { "label": "Output system info to log file", "tooltip": "Dump diagnostic data for troubleshooting", - "wait_msg": "Generating log", - "type": Command.ONESHOT, } - # help pages DOCS = { "label": "Documentation/help files (GitHub) ⧉", "tooltip": "Open the DZGUI documentation in a browser", - "type": Command.HELP, } DOCS_FALLBACK = { "label": "Documentation/help files (Codeberg mirror) ⧉", "tooltip": "Open the DZGUI documentation in a browser", - "type": Command.HELP, } BUGS = { "label": "Report a bug (GitHub) ⧉", "tooltip": "Open the DZGUI issue tracker in a browser", - "type": Command.HELP, } FORUM = { "label": "DZGUI Subreddit ⧉", "tooltip": "Open the DZGUI discussion forum in a browser", - "type": Command.HELP, } SPONSOR = { "label": "Sponsor (GitHub) ⧉", "tooltip": "Sponsor development of the DZGUI project", - "type": Command.HELP, } THANKS = { "label": "Special thanks", "tooltip": "A list of contributors, testers, and sponsors", - "type": Command.THANKS, } -# TODO: rename to ContextItem +# TODO: rename to ContextMenuItem class ContextMenu(EnumWithAttrs): ADD_NOTE = {"label": strings.add_note} ADD_SERVER = {"label": strings.add} diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index 710effa..172acce 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -45,14 +45,13 @@ from dzgui.config.userprefs import UserPrefs from dzgui.controllers.emitter import Emitter from dzgui.model.contextmenu import ContextMenuManager from dzgui.model.filtered_model import FilteredModelManager -from dzgui.model.misc_model import ModelManager +from dzgui.model.model_factory import ModelFactory from dzgui.util import strings from dzgui.util._json import read_json, write_json from dzgui.util.diag import write_diagnostic from dzgui.util.format import format_mods, format_player_count from dzgui.util.localize import number from dzgui.util.open_links import open_workshop_page, open_user_workshop -from dzgui.util.redact import redact_log from dzgui.views.dialogs.filepicker import FilePicker from dzgui.views.dialogs.generic import ExceptionDialog, WaitDialog @@ -112,7 +111,7 @@ class Controller(GObject.GObject): self.prefs: UserPrefs self.cleanup_func: StoredFunc = None - self.model_man = ModelManager() + #self.model_man = ModelManager() self.emitter = Emitter() self.emitter.connect("map_selection_changed", self._on_map_selection_changed) self.emitter.connect("check_toggled", self._on_check_toggled) @@ -163,12 +162,6 @@ class Controller(GObject.GObject): def is_auto_install(self) -> bool: return self.query_config(Preferences.INSTALL) - def reinit_map_store(self) -> None: - self.model_man.set_all_maps() - - def append_map(self, map_row: list) -> None: - self.model_man.append_map(map_row) - def unblock_signals(self) -> None: self.block_signals(False) @@ -313,7 +306,7 @@ class Controller(GObject.GObject): @call_on_thread(strings.dialog.modlist) def load_mods(self) -> None: - model = self.model_man.new_mod_store() + model = ModelFactory().make_mod_store() #self.model_man.new_mod_store() path = self.query_config(Preferences.DEFAULT) mods = get_delimited_mods(Path(path)) @@ -543,11 +536,7 @@ class Controller(GObject.GObject): self.push_data_success(parsed, FilterMode.INITIAL) def get_help_row(self) -> str: - tv = self.mediator.menu - model = self.get_help_store() - tree_iter = tv.get_focused_row_iter() - value = model.get_value(tree_iter, 1) - return value.dict["tooltip"] + return self.mediator.menu.get_row_enum() def open_user_workshop(self, uid: str) -> None: # NOTE: uid may contain leading zeroes, not a real integer @@ -634,22 +623,12 @@ class Controller(GObject.GObject): def populate_log(self) -> None: log = self.prefs.paths.debug - store = self.model_man.get_log_store() - store.clear() - # NOTE: this model is reloaded each time as log changes try: - with open(log, "r") as f: - lines = [ - line.split(strings.delimiter) for line in f.read().splitlines() - ] - for record in lines: - clean = redact_log(record) - store.append(clean) + self.mediator.logtreeview.populate_log(log) + self.open_page(NotebookPage.LOG) except Exception as e: dialog = ExceptionDialog(self, str(e)) dialog.run() - return - self.open_page(NotebookPage.LOG) def select_colorized(self) -> None: model = self.get_mod_store() @@ -930,15 +909,6 @@ class Controller(GObject.GObject): def get_dist_cache(self) -> dict[str, "Haversine"]: return self.dist_cache - def get_help_store(self) -> Gtk.ListStore: - return self.model_man.get_help_store() - - def get_modlist_store(self) -> Gtk.ListStore: - return self.model_man.get_modlist_store() - - def get_log_store(self) -> Gtk.ListStore: - return self.model_man.get_log_store() - def get_filters(self) -> list: return self.mediator.filters.get_filters() diff --git a/dzgui/model/misc_model.py b/dzgui/model/misc_model.py deleted file mode 100644 index 6431e1e..0000000 --- a/dzgui/model/misc_model.py +++ /dev/null @@ -1,82 +0,0 @@ -from dataclasses import dataclass -from dzgui.const.enum import HELP_MENU_ROWS - -import gi - -gi.require_version("Gtk", "3.0") -from gi.repository.Gtk import ListStore # noqa E402 -from gi.repository import GObject, Gtk # noqa E402 - - -@dataclass(slots=True, frozen=True) -class ModCols: - name: str - symlink: str - directory: str - size: float - color: str - - -@dataclass(slots=True, frozen=True) -class LogCols: - timestamp: str - flag: str - traceback: str - msg: str - - -@dataclass(slots=True, frozen=True) -class ServerModCols: - name: str - uid: GObject.TYPE_INT64 - installed: str - - -@dataclass(slots=True, frozen=True) -class MenuCols: - name: str - hidden: GObject.TYPE_PYOBJECT - - -class ModelManager: - """ - Manager for miscellaneous ListStores - """ - - def __init__(self) -> None: - - self.map_store = ListStore(str) - self.help_store = self.new_model_from_class(MenuCols) - self.log_store = self.new_model_from_class(LogCols) - # FIXME: needs to be generated on demand for servers - self.modlist_store = self.new_model_from_class(ServerModCols) - - for row in HELP_MENU_ROWS: - label = row.dict["label"] - self.help_store.append([label, row]) - - def new_model_from_class(self, cls: type) -> ListStore: - store = ListStore(*[ftype for field, ftype in cls.__annotations__.items()]) - return store - - def get_map_store(self) -> ListStore: - return self.map_store - - def get_help_store(self) -> ListStore: - return self.help_store - - def new_mod_store(self) -> ListStore: - return self.new_model_from_class(ModCols) - - def get_log_store(self) -> ListStore: - return self.log_store - - def get_modlist_store(self) -> ListStore: - return self.modlist_store - - def set_all_maps(self) -> None: - self.map_store.clear() - self.map_store.append(["All maps"]) - - def append_map(self, row: list) -> None: - self.map_store.append(row) diff --git a/dzgui/model/model_factory.py b/dzgui/model/model_factory.py new file mode 100644 index 0000000..afeb3c1 --- /dev/null +++ b/dzgui/model/model_factory.py @@ -0,0 +1,82 @@ +from dataclasses import dataclass + +from dzgui.const.enum import HELP_MENU_ROWS +from dzgui.util.redact import redact_log +from dzgui.util.strings import delimiter +from dzgui.views.dialogs.generic import ExceptionDialog + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository.Gtk import ListStore # noqa E402 +from gi.repository import GObject # noqa E402 + + +@dataclass(slots=True, frozen=True) +class ModCols: + name: str + symlink: str + directory: str + size: float + color: str + + +@dataclass(slots=True, frozen=True) +class LogCols: + timestamp: str + flag: str + traceback: str + msg: str + + +@dataclass(slots=True, frozen=True) +class ServerModCols: + name: str + uid: GObject.TYPE_INT64 + installed: str + + +@dataclass(slots=True, frozen=True) +class MenuCols: + name: str + hidden: GObject.TYPE_PYOBJECT + + +class ModelFactory: + def __init__(self) -> None: + pass + + def new_model_from_logfile(self, path: str) -> None: + store = self.make_log_store() + with open(path, "r") as f: + lines = [ + line.split(delimiter) for line in f.read().splitlines() + ] + for record in lines: + # NOTE: strip PII and API keys + clean = redact_log(record) + store.append(clean) + return store + + def new_model_from_class(self, cls: type) -> ListStore: + store = ListStore(*[ftype for field, ftype in cls.__annotations__.items()]) + return store + + def make_map_store(self) -> ListStore: + return ListStore(str) + + def make_help_store(self) -> ListStore: + store = self.new_model_from_class(MenuCols) + for row in HELP_MENU_ROWS: + label = row.dict["label"] + store.append([label, row]) + return store + + def make_mod_store(self) -> ListStore: + return self.new_model_from_class(ModCols) + + def make_log_store(self) -> ListStore: + return self.new_model_from_class(LogCols) + + def make_server_mod_store(self) -> ListStore: + return self.new_model_from_class(ServerModCols) diff --git a/dzgui/views/trees/tree_log.py b/dzgui/views/trees/tree_log.py index b5ec90a..1824558 100644 --- a/dzgui/views/trees/tree_log.py +++ b/dzgui/views/trees/tree_log.py @@ -3,6 +3,7 @@ import logging from typing import TYPE_CHECKING from dzgui.const.enum import ContextMenuGroup +from dzgui.model.model_factory import ModelFactory from dzgui.util import strings from dzgui.views.trees.tree_base import TreeView from dzgui.views.mixins.context_mixin import ContextMixin @@ -25,13 +26,11 @@ class LogTreeView(ContextMixin, TreeView): self.controller = controller self.controller.register_widget("logtreeview", self) - # TODO: maybe put this in init self.set_headers_visible(True) self.set_fixed_height_mode(True) self.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) - model = self.controller.get_log_store() - self.set_model(model) + self.set_model(None) for i, column_title in enumerate(strings.log_cols): renderer = Gtk.CellRendererText() @@ -44,7 +43,10 @@ class LogTreeView(ContextMixin, TreeView): self.connect("key-press-event", self._on_log_keypress) self.connect("button-press-event", self._on_log_keypress) - self.s = self.get_selection().get_selected_rows() + def populate_log(self, filepath: str) -> None: + model = ModelFactory().new_model_from_logfile(filepath) + self.set_model(model) + self.set_cursor(0) def _on_log_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None: self.present_menu(widget, event) diff --git a/dzgui/views/trees/tree_menu.py b/dzgui/views/trees/tree_menu.py index 2319a24..8292bb1 100644 --- a/dzgui/views/trees/tree_menu.py +++ b/dzgui/views/trees/tree_menu.py @@ -1,7 +1,8 @@ import logging -from typing import TYPE_CHECKING +from typing import Any, TYPE_CHECKING from dzgui.const.enum import RowType, NotebookPage +from dzgui.model.model_factory import ModelFactory from dzgui.util.open_links import open_link_by_rowtype from dzgui.views.trees.tree_base import TreeView @@ -32,7 +33,7 @@ class MenuTreeView(TreeView): column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) self.append_column(column) - help_store = self.controller.get_help_store() + help_store = ModelFactory().make_help_store() self.set_model(help_store) self.selected_row = self.get_selection() @@ -45,6 +46,7 @@ class MenuTreeView(TreeView): def _parent_row_activated( self, tree: TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn ) -> None: + # FIXME: may be expected to return str, not enum row_type = self.get_value_at_index(1) match row_type: @@ -66,5 +68,11 @@ class MenuTreeView(TreeView): RowType.SPONSOR, ] if row_type in docs: - # FIXME: prior method is returning a str, not enum open_link_by_rowtype(row_type) + + def get_row_enum(self) -> Any: + # NOTE: col 1 contains a RowType enum + model = self.get_model() + _iter = self.get_focused_row_iter() + rowtype = model.get_value(_iter, 1) + return rowtype.dict["tooltip"]