chore: change modelman to model factory

This commit is contained in:
aclist 2026-02-21 22:03:46 +09:00
parent 85c1d18622
commit bdfebf9a69
6 changed files with 110 additions and 147 deletions

View File

@ -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}

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"]