diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index f405e15..4281931 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -12,7 +12,7 @@ from typing import Any, Callable, Literal, TYPE_CHECKING import dzgui.api.pefile as PeFile import dzgui.api.servers as Servers import dzgui.util._json as JSON # noqa -from dzgui.views.dialogs.generic import ExceptionDialog +from dzgui.views.dialogs.generic import ExceptionDialog, WaitDialog from dzgui.api.probe import test_steam_api, test_bm_api from dzgui.api.mods import ( @@ -182,6 +182,10 @@ class Controller(GObject.GObject): def toggle_debug_mode(self) -> None: self.toggle_config(Preferences.DEBUG) + def get_active_context(self) -> NotebookPage: + tv = self.get_active_treeview() + return tv.get_enum() + def get_active_treeview(self) -> "ServerTreeView": return self.mediator.notebook.servers.get_active_treeview() @@ -236,11 +240,10 @@ class Controller(GObject.GObject): return msg_id def set_statusbar_dist(self, haversine: "Haversine", enum: "ServerTab") -> None: - tv = self.get_active_treeview() - context = tv.get_enum() + context = self.get_active_context() page = self.mediator.notebook.get_page_by_enum() """ - NOTE: prevents race condition when notebook page changed, + NOTE: prevents race condition when server tab changed, but allows caching the distance in the background """ if page != NotebookPage.SERVERS: @@ -289,8 +292,6 @@ class Controller(GObject.GObject): mod.append(None) model.append(mod) - # self.update_mod_statusbar() - def toggle_config(self, context: Preferences) -> None: config = self.prefs.paths.config try: @@ -356,7 +357,7 @@ class Controller(GObject.GObject): self.mediator.notebook.set_page_by_enum(button.opens) - def _dump_api(self): + def dump_api(self): key = self.query_config(Preferences.STEAM) job = Servers.query_api params = Servers.params @@ -370,10 +371,7 @@ class Controller(GObject.GObject): for future in futures: res = future.result() if res.status != 200 or not res.parsed: - # ModelManager.set_store(None) - # ModelManager.set_success(False) - # GLib.idle_add(self._filter_cleanup) - print("status error") + self.push_data(None) return j = res.json serv += j["response"]["servers"] @@ -383,14 +381,9 @@ class Controller(GObject.GObject): j = res.json serv += j["response"]["servers"] + # TODO: ping column pass parsed = Servers.parse_json(serv) - self.data = parsed - self.get_func_data() - self.destroy_on_idle() - # try: - # except Exception as e: - # print(e) - # return parsed + self.push_data(parsed) def get_help_row(self) -> str: tv = self.mediator.menu @@ -574,18 +567,16 @@ class Controller(GObject.GObject): import time time.sleep(1) - self.data = ( + data = ( ["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], ) - # TODO: refer to prior implementation--should need to load data into model while in thread - self.get_func_data() - self.destroy_on_idle() + self.push_data(data) def dump_test_2(self) -> None: import time time.sleep(1) - self.data = ( + data = ( ["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], @@ -598,37 +589,34 @@ class Controller(GObject.GObject): ["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], ) - # TODO: refer to prior implementation--should need to load data into model while in thread - self.get_func_data() - self.destroy_on_idle() + self.push_data(data) - def get_func_data(self) -> None: - 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 - # TODO: append rows into filtered model - # when complete, destroy dialog and set model - for row in data: - manager.append_row(row) - treeview.set_model(manager.get_model()) - treeview.set_loaded(True) + def push_data(self, data: tuple) -> None: + def cleanup(): + # TODO: rename signal self.mediator.statusbar.emit("server_page_changed", context) + # TODO: may be superfluous treeview.grab_focus() + self.destroy_on_idle() treeview = self.get_active_treeview() - context = treeview.get_enum() + context = self.get_active_context() - manager = treeview.get_filter_man() - data = self.data - GLib.idle_add(test) + if data is None: + insert = None + else: + manager = treeview.get_filter_man() + for row in data: + manager.append_row(row) + insert = manager.get_model() + treeview.set_model(insert) + treeview.set_loaded(True) + GLib.idle_add(cleanup) def highlight_stale(self) -> None: self.call_on_thread(self.colorize_mods) def call_on_thread(self, func: Callable, *args) -> None: - from dzgui.views.dialogs.generic import WaitDialog - self.wait_dialog = WaitDialog(self, strings.dialog.fetching) self.wait_dialog.show_all() thread = threading.Thread(target=func, args=args) @@ -650,6 +638,8 @@ class Controller(GObject.GObject): def destroy_on_idle(self) -> None: self.wait_dialog.destroy() func = self.get_callback() + self.mediator.window.set_sensitive(True) + # TODO: spawn error dialog if API crawl failed if func is not None: args = self.get_callback_args() GLib.idle_add(func, *args) @@ -735,14 +725,12 @@ class Controller(GObject.GObject): if func is None: self.mediator.statusbar.emit("server_page_changed", treeview.get_enum()) return - manager = treeview.get_filter_man() - # TODO: this may lag? treeview.set_model(None) + manager = treeview.get_filter_man() manager.clear_model() self.set_callback(None, None) self.call_on_thread(func) - def focus_button_box(self) -> None: self.mediator.right_panel.focus_button_box() @@ -791,5 +779,5 @@ class Controller(GObject.GObject): def get_map(self) -> str: self.mediator.filters.get_selected_map() - def get_prio_map(self) -> str: + def get_prior_map(self) -> str: self.mediator.filters.get_prior_map() diff --git a/dzgui/model/filtered_model.py b/dzgui/model/filtered_model.py index 7505a89..c807b75 100644 --- a/dzgui/model/filtered_model.py +++ b/dzgui/model/filtered_model.py @@ -53,9 +53,9 @@ class FilteredModelManager: self.success = True def append_row(self, row: list) -> None: - self.real_model.append(row) + # self.real_model.append(row) # NOTE: append null rows to thin client - self.model.append() + self.model.append(row) def clear_model(self) -> None: self.model.clear() diff --git a/dzgui/views/pages/servers.py b/dzgui/views/pages/servers.py index 06904fe..55589e9 100644 --- a/dzgui/views/pages/servers.py +++ b/dzgui/views/pages/servers.py @@ -34,9 +34,8 @@ class ServerNotebook(Gtk.ScrolledWindow): ) self.lan = ServerTreeView(controller, ServerTab.LAN, ContextMenuGroup.SCAN_LAN) - # self.browser.set_query_func(self.controller.dump_test_2) self.lan.set_query_func(self.controller.dump_test_2) - self.browser.set_query_func(self.controller._dump_api) + self.browser.set_query_func(self.controller.dump_api) tabs = [ (self.browser, server_labels.browser), @@ -92,6 +91,7 @@ class ServerNotebook(Gtk.ScrolledWindow): # TODO: strings text = label.strip("*") self.notebook.set_tab_label_text(child, text) + # NOTE: spawns a thread self.controller.populate_model() def get_active_treeview(self) -> ServerTreeView: diff --git a/dzgui/views/trees/tree_base.py b/dzgui/views/trees/tree_base.py index b428d53..ac1f47b 100644 --- a/dzgui/views/trees/tree_base.py +++ b/dzgui/views/trees/tree_base.py @@ -104,6 +104,8 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore # self.get_selection().select_iter(it) # return True + if self.get_model() is None: + return if len(self.get_model()) < 2: return diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py index 7941d16..a8ee840 100644 --- a/dzgui/views/trees/tree_servers.py +++ b/dzgui/views/trees/tree_servers.py @@ -1,6 +1,7 @@ import logging import multiprocessing from typing import Any, Self +from warnings import deprecated from dzgui.const.enum import ContextMenu, ContextMenuGroup, FilterMode, ServerTab from dzgui.api.servers import Record @@ -24,8 +25,6 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: from dzgui.controllers.mc import Controller -# TODO: restore missing methods - class EnumeratedMenuItem(Gtk.MenuItem): def __init__(self, enum: ContextMenu): @@ -76,7 +75,6 @@ class ServerTreeView(TreeView): renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn(column_title, renderer, text=i) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) - column.set_cell_data_func(renderer, self._lazy_load, func_data=i) column.set_resizable(True) column.set_sort_column_id(i) @@ -336,8 +334,6 @@ class ServerTreeView(TreeView): print(self.get_value_at_index(0)) def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection): - # TODO: lazy load - # https://stackoverflow.com/questions/3164262/lazy-loaded-list-view-in-gtk self.terminate_process() self.emit("distcalc_started") @@ -351,7 +347,6 @@ class ServerTreeView(TreeView): select = self.get_selection() sels = select.get_selected_rows() (model, pathlist) = sels - # TODO: clean up per lazy load logic if len(pathlist) < 1: return None path = pathlist[0] @@ -372,6 +367,7 @@ class ServerTreeView(TreeView): def set_loaded(self, status: bool) -> None: self.loaded = status + @deprecated("Currently unused") def _lazy_load( self, column: Gtk.TreeViewColumn, @@ -380,11 +376,17 @@ class ServerTreeView(TreeView): it: Gtk.TreeIter, col_index: int, ) -> Any: - # TODO: initially load empty rows - # TODO: if cell is in visible range + """ + Lazy load contents from model manager into visible CellRenderers on demand + N.B., all row data will be stringified + cf. Gtk.TreeViewColumn.set_cell_data_func() + """ path = model.get_path(it) row_index = path.get_indices()[0] - start, end = self.get_visible_range() + try: + start, end = self.get_visible_range() + except Exception: + return if row_index >= start[0] <= end[0]: real_model = self.filter_man.get_real_model() value = real_model[row_index][col_index]