mirror of
https://github.com/aclist/dztui.git
synced 2026-08-27 10:17:31 +02:00
feat: initialize ServerTreeViews with atomic FilterModelManagers
This commit is contained in:
parent
fdd6cefe48
commit
6f29b1318a
@ -39,7 +39,7 @@ from dzgui.const.constants import (
|
||||
from dzgui.config import update
|
||||
from dzgui.config.query import lookup
|
||||
from dzgui.config.userprefs import UserPrefs
|
||||
from dzgui.controllers.model import ModelManager
|
||||
from dzgui.model.misc_model import ModelManager
|
||||
from dzgui.util import strings
|
||||
from dzgui.util.diag import write_diagnostic
|
||||
from dzgui.util._json import read_json, write_json
|
||||
@ -91,7 +91,9 @@ class Controller:
|
||||
self.crumbs_cache = ""
|
||||
self.mediator = AppNavigation()
|
||||
self.prefs: UserPrefs
|
||||
self.model_manager = ModelManager()
|
||||
|
||||
self.model_man = ModelManager()
|
||||
|
||||
# TODO: poc
|
||||
self.loaded = False
|
||||
|
||||
@ -107,32 +109,20 @@ class Controller:
|
||||
def get_crumbs(self) -> str:
|
||||
return self.mediator.grid.get_breadcrumbs()
|
||||
|
||||
def get_server_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_server_store()
|
||||
|
||||
def get_saved_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_saved_store()
|
||||
|
||||
def get_recent_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_recent_store()
|
||||
|
||||
def get_lan_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_lan_store()
|
||||
|
||||
def get_help_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_help_store()
|
||||
return self.model_man.get_help_store()
|
||||
|
||||
def get_map_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_map_store()
|
||||
return self.model_man.get_map_store()
|
||||
|
||||
def get_modlist_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_modlist_store()
|
||||
return self.model_man.get_modlist_store()
|
||||
|
||||
def get_mod_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_mod_store()
|
||||
return self.model_man.get_mod_store()
|
||||
|
||||
def get_log_store(self) -> Gtk.ListStore:
|
||||
return self.model_manager.get_log_store()
|
||||
return self.model_man.get_log_store()
|
||||
|
||||
def terminate_process(self) -> None:
|
||||
# TODO: only used by server table multiprocessing queue
|
||||
@ -152,10 +142,10 @@ class Controller:
|
||||
return self.query_config(Preferences.INSTALL)
|
||||
|
||||
def reinit_map_store(self) -> None:
|
||||
self.model_manager.set_all_maps()
|
||||
self.model_man.set_all_maps()
|
||||
|
||||
def append_map(self, map_row: list) -> None:
|
||||
self.model_manager.append_map(map_row)
|
||||
self.model_man.append_map(map_row)
|
||||
|
||||
def unblock_signals(self) -> None:
|
||||
self.block_signals(False)
|
||||
@ -197,7 +187,7 @@ class Controller:
|
||||
def toggle_debug_mode(self) -> None:
|
||||
self.toggle_config(Preferences.DEBUG)
|
||||
|
||||
def get_active_treeview(self) -> "TreeView":
|
||||
def get_active_treeview(self) -> "ServerTreeView":
|
||||
return self.mediator.notebook.servers.get_active_treeview()
|
||||
|
||||
def grab_active_treeview(self) -> None:
|
||||
@ -278,7 +268,7 @@ class Controller:
|
||||
|
||||
def load_mods(self) -> None:
|
||||
# TODO: threading
|
||||
model = self.model_manager.get_mod_store()
|
||||
model = self.model_man.get_mod_store()
|
||||
model.clear()
|
||||
path = self.query_config(Preferences.DEFAULT)
|
||||
mods = get_delimited_mods(Path(path))
|
||||
@ -394,7 +384,7 @@ class Controller:
|
||||
|
||||
# TODO: put in model manager (dedicated manager for mod store)
|
||||
def get_mod_from_tree_path(self, tree_path: Gtk.TreePath) -> tuple[str, Gtk.TreeIter]:
|
||||
model = self.model_manager.get_mod_store()
|
||||
model = self.model_man.get_mod_store()
|
||||
tree_iter = model.get_iter(tree_path)
|
||||
mod = model.get(tree_iter, 2)[0]
|
||||
return mod, tree_iter
|
||||
@ -423,7 +413,7 @@ class Controller:
|
||||
except PeFile.AppNotInstalledError:
|
||||
pass
|
||||
|
||||
model = self.model_manager.get_mod_store()
|
||||
model = self.model_man.get_mod_store()
|
||||
model.remove(it)
|
||||
|
||||
|
||||
@ -435,7 +425,7 @@ class Controller:
|
||||
self.mediator.statusbar.spinner.stop()
|
||||
|
||||
def calc_mod_size(self) -> tuple[int, int]:
|
||||
model = self.model_manager.get_mod_store()
|
||||
model = self.model_man.get_mod_store()
|
||||
total_mods = len(model)
|
||||
total_size = 0
|
||||
for mod in model:
|
||||
@ -493,7 +483,7 @@ class Controller:
|
||||
|
||||
def populate_log(self) -> None:
|
||||
log = self.prefs.paths.debug
|
||||
store = self.model_manager.get_log_store()
|
||||
store = self.model_man.get_log_store()
|
||||
store.clear()
|
||||
# NOTE: this model is reloaded each time as log changes
|
||||
try:
|
||||
@ -508,7 +498,7 @@ class Controller:
|
||||
self.open_page(NotebookPage.LOG)
|
||||
|
||||
def select_colorized(self) -> None:
|
||||
model = self.model_manager.get_mod_store()
|
||||
model = self.model_man.get_mod_store()
|
||||
sel = self.mediator.modtreeview.get_selection()
|
||||
for mod in model:
|
||||
it = mod.iter
|
||||
@ -517,14 +507,14 @@ class Controller:
|
||||
sel.select_path(path)
|
||||
|
||||
def uncolorize_mods(self) -> None:
|
||||
model = self.model_manager.get_mod_store()
|
||||
model = self.model_man.get_mod_store()
|
||||
for mod in model:
|
||||
it = mod.iter
|
||||
path = model.get_path(it)
|
||||
model[path][4] = None
|
||||
|
||||
def colorize_mods(self) -> None:
|
||||
model = self.model_manager.get_mod_store()
|
||||
model = self.model_man.get_mod_store()
|
||||
stale = find_stale_mods(self.prefs.paths.config)
|
||||
for mod in model:
|
||||
it = mod.iter
|
||||
@ -544,7 +534,7 @@ class Controller:
|
||||
# TODO: use model managers, etc.
|
||||
self.data = (
|
||||
["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, "172.111.51.156: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],
|
||||
@ -572,19 +562,19 @@ class Controller:
|
||||
self.get_func_data()
|
||||
self.destroy_on_idle()
|
||||
|
||||
def get_func_data(self) -> tuple:
|
||||
def get_func_data(self):
|
||||
def test():
|
||||
# NOTE: do not insert model until main thread is idle
|
||||
# TODO: grab from model manager and insert entire model
|
||||
# TODO: do not start refresh button count until load finished
|
||||
for row in data:
|
||||
model.append(row)
|
||||
manager.append_row(row)
|
||||
treeview.set_loaded(True)
|
||||
self.update_server_status()
|
||||
treeview.grab_focus()
|
||||
# TODO: use model manager
|
||||
treeview = self.get_active_treeview()
|
||||
model = treeview.get_model()
|
||||
|
||||
manager = treeview.get_filter_man()
|
||||
data = self.data
|
||||
GLib.idle_add(test)
|
||||
|
||||
@ -697,16 +687,14 @@ class Controller:
|
||||
self.mediator.statusbar.spinner.start()
|
||||
|
||||
def populate_model(self) -> None:
|
||||
# TODO: always use same server model, store in servertreeview class
|
||||
treeview = self.get_active_treeview()
|
||||
if treeview.get_loaded() is False:
|
||||
new_model = self.model_manager.new_model()
|
||||
# NOTE: set_query_func()
|
||||
# NOTE: cf. set_query_func()
|
||||
func = treeview.get_query_func()
|
||||
if func is not None:
|
||||
model = treeview.get_model()
|
||||
manager = treeview.get_filter_man()
|
||||
# TODO: this may lag?
|
||||
model.clear()
|
||||
manager.clear_model()
|
||||
self.set_callback(None, None)
|
||||
self.call_on_thread(func)
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Self
|
||||
|
||||
from dzgui.const.enum import FilterMode, HELP_MENU_ROWS
|
||||
from dzgui.const.enum import FilterMode
|
||||
from dzgui.util import strings
|
||||
|
||||
import gi
|
||||
@ -10,7 +10,6 @@ gi.require_version("Gtk", "3.0")
|
||||
from gi.repository.Gtk import ListStore # noqa E402
|
||||
from gi.repository import GObject, GLib # noqa E402
|
||||
|
||||
@dataclass
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class ServerColumns:
|
||||
name: str
|
||||
@ -27,105 +26,38 @@ class ServerColumns:
|
||||
modded: bool
|
||||
|
||||
|
||||
@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:
|
||||
class FilteredModelManager:
|
||||
"""
|
||||
Manages access to cached ListStore resources and
|
||||
performs filtering on behalf of TreeViews.
|
||||
performs filtering on behalf of atomic TreeViews,
|
||||
which share the same column structure.
|
||||
|
||||
Methods are not thread-safe in themselves.
|
||||
A FilteredModelManager is attached to each ServerTreeView.
|
||||
Filter methods are not thread-safe in themselves.
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
self.filter_cache: tuple
|
||||
self.ping_cache: dict[str, int] = {}
|
||||
|
||||
self.map_store = ListStore(str)
|
||||
self.help_store = self.new_model_from_class(MenuCols)
|
||||
self.mod_store = self.new_model_from_class(ModCols)
|
||||
self.log_store = self.new_model_from_class(LogCols)
|
||||
self.modlist_store = self.new_model_from_class(ServerModCols)
|
||||
|
||||
self.server_store = self.new_model()
|
||||
self.saved_store = self.new_model()
|
||||
self.recent_store = self.new_model()
|
||||
self.lan_store = self.new_model()
|
||||
|
||||
for row in HELP_MENU_ROWS:
|
||||
label = row.dict["label"]
|
||||
self.help_store.append([label, row])
|
||||
self.model = self.new_model_from_class(ServerColumns)
|
||||
|
||||
self.control_model = None
|
||||
self.filtered = None
|
||||
self.success = True
|
||||
|
||||
#def __new__(cls) -> Self:
|
||||
# if not hasattr(cls, "instance"):
|
||||
# cls.instance = super(ModelManager, cls).__new__(cls)
|
||||
# return cls.instance
|
||||
def append_row(self, row: list) -> None:
|
||||
self.model.append(row)
|
||||
|
||||
def get_recent_store(self) -> ListStore:
|
||||
return self.recent_store
|
||||
def clear_model(self) -> None:
|
||||
self.model.clear()
|
||||
|
||||
def get_lan_store(self) -> ListStore:
|
||||
return self.lan_store
|
||||
|
||||
def get_saved_store(self) -> ListStore:
|
||||
return self.saved_store
|
||||
|
||||
def get_server_store(self) -> ListStore:
|
||||
return self.server_store
|
||||
def get_model(self) -> ListStore:
|
||||
return self.model
|
||||
|
||||
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_row_store(self) -> ListStore:
|
||||
# return self.row_store
|
||||
|
||||
def get_help_store(self) -> ListStore:
|
||||
return self.help_store
|
||||
|
||||
def get_mod_store(self) -> ListStore:
|
||||
return self.mod_store
|
||||
|
||||
def get_modlist_store(self) -> ListStore:
|
||||
return self.modlist_store
|
||||
|
||||
def get_log_store(self) -> ListStore:
|
||||
return self.log_store
|
||||
|
||||
def filter(self, mode: FilterMode, *args, **kwargs) -> None:
|
||||
"""
|
||||
Native Gtk.TreeView.refilter() method was not performant enough
|
||||
@ -290,10 +222,6 @@ class ModelManager:
|
||||
) -> None:
|
||||
self.filter_cache[filters] = (model, rows)
|
||||
|
||||
def new_model(self) -> ListStore:
|
||||
store = self.new_model_from_class(ServerColumns)
|
||||
return store
|
||||
|
||||
def resync_model(self, addr: str, qport: int) -> None:
|
||||
"""
|
||||
Handle in-situ updates to model during
|
||||
@ -344,10 +272,3 @@ class ModelManager:
|
||||
self.ping_cache = {}
|
||||
if full:
|
||||
self.control_model = None
|
||||
|
||||
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)
|
||||
@ -24,38 +24,22 @@ class ServerNotebook(Gtk.ScrolledWindow):
|
||||
self.controller.register_widget("servers", self)
|
||||
self.notebook = Gtk.Notebook(show_tabs=True)
|
||||
|
||||
self.browser = ServerTreeView(controller, ServerTab.BROWSER)
|
||||
self.saved = ServerTreeView(controller, ServerTab.SAVED)
|
||||
self.recent = ServerTreeView(controller, ServerTab.RECENT)
|
||||
self.lan = ServerTreeView(controller, ServerTab.LAN)
|
||||
self.browser = ServerTreeView(controller, ServerTab.BROWSER, ContextMenuGroup.SERVER_BROWSER)
|
||||
self.saved = ServerTreeView(controller, ServerTab.SAVED, ContextMenuGroup.SAVED)
|
||||
self.recent = ServerTreeView(controller, ServerTab.RECENT, ContextMenuGroup.RECENT)
|
||||
self.lan = ServerTreeView(controller, ServerTab.LAN, ContextMenuGroup.SCAN_LAN)
|
||||
|
||||
self.browser.set_query_func(self.query_test2)
|
||||
self.lan.set_query_func(self.query_test)
|
||||
|
||||
# TODO: set context menu on init of ServerTreeView?
|
||||
self.browser.set_context_menu(ContextMenuGroup.SERVER_BROWSER)
|
||||
self.saved.set_context_menu(ContextMenuGroup.SAVED)
|
||||
self.recent.set_context_menu(ContextMenuGroup.RECENT)
|
||||
self.lan.set_context_menu(ContextMenuGroup.SCAN_LAN)
|
||||
|
||||
tabs = [
|
||||
(self.browser, server_labels.browser, self.controller.get_server_store),
|
||||
(self.saved, server_labels.saved, self.controller.get_saved_store),
|
||||
(self.recent, server_labels.recent, self.controller.get_recent_store),
|
||||
(self.lan, server_labels.lan, self.controller.get_lan_store),
|
||||
]
|
||||
|
||||
for tree, label, func in tabs:
|
||||
store = func()
|
||||
if label == "LAN":
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
# TODO: set model only on init of servertreeview
|
||||
# TODO: set model manager for each tab on init
|
||||
# TODO: add set_ and get_model_manager() methods
|
||||
tree.set_model(store)
|
||||
(self.browser, server_labels.browser),
|
||||
(self.saved, server_labels.saved),
|
||||
(self.recent, server_labels.recent),
|
||||
(self.lan, server_labels.lan),
|
||||
]
|
||||
|
||||
for tree, label in tabs:
|
||||
scrolled = Gtk.ScrolledWindow()
|
||||
scrolled.add(tree)
|
||||
self.notebook.append_page(scrolled, Gtk.Label(label=label))
|
||||
|
||||
@ -88,14 +88,13 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
|
||||
) -> None:
|
||||
|
||||
if is_navkey(event.keyval):
|
||||
# FIXME: will fail on mod list
|
||||
tv = self.controller.get_active_treeview()
|
||||
if len(tv.get_model()) < 1:
|
||||
# TODO: if model is None
|
||||
if len(self.get_model()) < 1:
|
||||
return
|
||||
if self.sel_blocked is False:
|
||||
self.controller.suppress_signal(
|
||||
tv,
|
||||
tv.selected_row,
|
||||
self,
|
||||
self.selected_row,
|
||||
"_on_tree_selection_changed",
|
||||
True,
|
||||
)
|
||||
|
||||
@ -15,6 +15,7 @@ from dzgui.const.enum import (
|
||||
from dzgui.const.constants import UDP_PORT
|
||||
from dzgui.const.enum import ServerTab
|
||||
from dzgui.api.servers import Record
|
||||
from dzgui.model.filtered_model import FilteredModelManager
|
||||
from dzgui.util.dist import CalcDist
|
||||
from dzgui.util.keys import is_navkey
|
||||
from dzgui.util import strings
|
||||
@ -40,7 +41,7 @@ class ServerTreeView(TreeView):
|
||||
__gsignals__ = {
|
||||
"on_distcalc_started": (GObject.SignalFlags.RUN_FIRST, None, ())
|
||||
}
|
||||
def __init__(self, controller: "Controller", enum: ServerTab) -> None:
|
||||
def __init__(self, controller: "Controller", enum: ServerTab, menu: ContextMenuGroup) -> None:
|
||||
super().__init__(controller)
|
||||
|
||||
QUEUE_CHECK_DELAY = 200
|
||||
@ -49,10 +50,15 @@ class ServerTreeView(TreeView):
|
||||
self.loaded = False
|
||||
self.query_func: Callable = None
|
||||
|
||||
self.filter_man = FilteredModelManager()
|
||||
model = self.filter_man.get_model()
|
||||
self.set_model(model)
|
||||
|
||||
self.menu = Gtk.Menu()
|
||||
self.menu.connect("key-press-event", self._on_key)
|
||||
self.controller = controller
|
||||
|
||||
self.set_context_menu(menu)
|
||||
self.set_fixed_height_mode(True)
|
||||
self.set_headers_visible(True)
|
||||
|
||||
@ -113,6 +119,9 @@ class ServerTreeView(TreeView):
|
||||
|
||||
GLib.timeout_add(QUEUE_CHECK_DELAY, self._check_result_queue)
|
||||
|
||||
def get_filter_man(self) -> FilteredModelManager:
|
||||
return self.filter_man
|
||||
|
||||
def shrink_to_fit(self) -> None:
|
||||
cols = self.get_columns()
|
||||
# TODO: run on only one treeview and propagate results
|
||||
@ -203,6 +212,8 @@ class ServerTreeView(TreeView):
|
||||
record = self.get_record()
|
||||
if record is None:
|
||||
return
|
||||
# TODO:
|
||||
self.controller.mediator.statusbar.spinner.start()
|
||||
ip = record.ip
|
||||
self.current_proc = CalcDist(record.ip, self.queue, self.controller)
|
||||
self.current_proc.start()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user