diff --git a/dzgui/api/mods.py b/dzgui/api/mods.py index 4953ceb..9bda5be 100644 --- a/dzgui/api/mods.py +++ b/dzgui/api/mods.py @@ -154,7 +154,12 @@ def remove_stale_signatures(config: Path, versions: Path) -> None: def find_stale_mods(config: Path) -> list[int]: def push_record(rec: str) -> list: record = fqip_to_record(rec) - return [mod.workshop_id for mod in get_rules(record)] + try: + mods = get_rules(record) + print(mods) + except Exception: + return [] + return [mod.workshop_id for mod in mods] steam = lookup(config, Preferences.DEFAULT) steam_path = Path(steam) diff --git a/dzgui/api/servers.py b/dzgui/api/servers.py index 29b23b4..aa54712 100644 --- a/dzgui/api/servers.py +++ b/dzgui/api/servers.py @@ -438,6 +438,7 @@ def get_rules(record: Record) -> list["DayzMod"]: return [mod for mod in mods] except Exception as e: logger.critical(e) + # TODO: supposed to skip failing servers for highlight action return [] diff --git a/dzgui/const/enum.py b/dzgui/const/enum.py index 712d4e2..a1d8eac 100644 --- a/dzgui/const/enum.py +++ b/dzgui/const/enum.py @@ -109,6 +109,7 @@ class NotebookPage(EnumWithAttrs): OPTIONS = {"crumbs": strings.crumbs.options, "statusbar": False} SERVERS = {"crumbs": strings.crumbs.servers, "statusbar": True} THANKS = {"crumbs": strings.crumbs.thanks, "statusbar": True} + CONNECTION = {"crumbs": "Connect", "statusbar": False} class RowType(EnumWithAttrs): diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index fb165a1..53af881 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -27,6 +27,7 @@ from dzgui.util.format import format_player_count from dzgui.util.open_links import open_user_workshop, open_workshop_page from dzgui.views.dialogs.filepicker import FilePicker from dzgui.views.dialogs.generic import ExceptionDialog +from dzgui.views.dialogs.servers import ServerModDialog import gi @@ -38,6 +39,7 @@ logger = logging.getLogger(APP_NAME) if TYPE_CHECKING: from dzgui.api.servers import Record from dzgui.const.enum import ServerTab + from dzgui.lib.dayzquery import DayzMod from dzgui.managers.filter import FilterManager from dzgui.util.dist import Haversine from dzgui.views.base import Notebook, Grid, OuterWindow @@ -139,7 +141,9 @@ class Controller(GObject.GObject): def remove_statusbar(self, context: "NotebookPage | ServerTab") -> None: self.mediator.statusbar.pop(context) - def set_statusbar_dist(self, haversine: Union["Haversine", None], enum: "ServerTab") -> None: + def set_statusbar_dist( + self, haversine: Union["Haversine", None], enum: "ServerTab" + ) -> None: """ NOTE: prevents race condition when server tab changed, but allows caching the distance in the background @@ -400,7 +404,7 @@ class Controller(GObject.GObject): ConnectionManager(self).query_details(record) def get_modlist(self, record: "Record") -> None: - ConnectionManager(self).query_modlist(record) + ConnectionManager(self).query_modlist_and_present(record) def get_server_name(self) -> str: tv = self.get_active_treeview() @@ -448,8 +452,14 @@ class Controller(GObject.GObject): def get_modtreeview(self) -> "ModTreeView": return self.mediator.modtreeview + def get_exit_event(self) -> None: + return self.exit_event + def set_exit_event(self) -> None: self.exit_event.set() - def get_exit_event(self) -> threading.Event: - return self.exit_event + def open_connection_assistant(self, res: dict[Any], mods: list["DayzMod"]) -> None: + self.open_page(NotebookPage.CONNECTION) + # TODO: populate assistant + # TODO: embed dialogs + # dialog = ServerModDialog(self, mods) diff --git a/dzgui/managers/connection.py b/dzgui/managers/connection.py index 7d3b680..eea70ce 100644 --- a/dzgui/managers/connection.py +++ b/dzgui/managers/connection.py @@ -55,11 +55,18 @@ class ConnectionManager: self.thread_man.set_cleanup_func( StoredFunc(self._server_timeout), destroy_first=True ) - rules = Servers.get_rules(record) + # TODO: proper error handling (currently returns empty list) + try: + mods = self.query_modlist(record) + except Exception: + self.thread_man.set_cleanup_func( + StoredFunc(self._server_timeout), destroy_first=True + ) + self.controller.open_connection_assistant(res, mods) # TODO: add to history if successful - print(res) - print(rules) + # print(res) + # print(rules) @call_on_thread(dialog.querying) def query_details(self, record: Servers.Record) -> None: @@ -73,18 +80,17 @@ class ConnectionManager: StoredFunc(self._present_details_dialog, details), destroy_first=True ) - @call_on_thread(dialog.querying) def query_modlist(self, record: Servers.Record) -> None: mods = Servers.get_rules(record) steam_path = self.controller.query_config(Preferences.DEFAULT) local = get_local_mod_ids(steam_path) - if len(mods) == 0: - # TODO: separate message for no mods - # TODO: separate message for actual timeout - self.thread_man.set_cleanup_func( - StoredFunc(self._server_timeout), destroy_first=True - ) - return + # if len(mods) == 0: + # # TODO: separate message for no mods + # # TODO: separate message for actual timeout + # self.thread_man.set_cleanup_func( + # StoredFunc(self._server_timeout), destroy_first=True + # ) + # return alpha_mods = [ [ mod.name, @@ -94,9 +100,19 @@ class ConnectionManager: for mod in mods ] alpha_mods.sort(key=lambda x: x[0]) + return alpha_mods + @call_on_thread(dialog.querying) + def query_modlist_and_present(self, record: Servers.Record) -> None: + try: + mods = self.query_modlist(record) + except Exception: + self.thread_man.set_cleanup_func( + StoredFunc(self._server_timeout), destroy_first=True + ) + return self.thread_man.set_cleanup_func( - StoredFunc(self._present_modlist_dialog, alpha_mods), + StoredFunc(self._present_modlist_dialog, mods), destroy_first=True, ) diff --git a/dzgui/managers/mods.py b/dzgui/managers/mods.py index 39125b5..a44c3bc 100644 --- a/dzgui/managers/mods.py +++ b/dzgui/managers/mods.py @@ -16,6 +16,9 @@ from dzgui.const.enum import Preferences from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager from dzgui.model.model_factory import FastInsertListStore, ModelFactory from dzgui.util.format import format_mods +from dzgui.util.strings import server_timeout +from dzgui.views.dialogs.generic import ExceptionDialog + import dzgui.api.pefile as PeFile @@ -34,11 +37,9 @@ class ModManager: """ Because mods may be dynamically updated on the system, this manager is instantiated each time the Mods page is opened - and persists until the next time the page is opened """ def __init__(self, controller: "Controller") -> None: - self.controller = controller self.emitter = controller.get_emitter() self.prefs = controller.get_prefs() @@ -50,6 +51,7 @@ class ModManager: self.thread_man = ThreadingManager(controller) self._get_mods() + # TODO: strings @call_on_thread("getting mods") def _get_mods(self) -> None: mods = get_delimited_mods(self.path) @@ -69,11 +71,12 @@ class ModManager: total_mods = len(self.store) self.emitter.emit("mods_updated", msg, total_mods) + # TODO: strings @call_on_thread("deleting mods") def delete_mods(self) -> None: sel = self.treeview.get_selection() model, pathlist = sel.get_selected_rows() - # NOTE reverse when multiple selection + # NOTE: reverse when multiple selection iters = [] for path in reversed(pathlist): _iter = self.delete_single_mod(path) @@ -174,13 +177,24 @@ class ModManager: model[path][4] = True self.emitter.emit("mods_highlighted") + # TODO: strings @call_on_thread("working") def highlight_stale(self) -> None: - # TODO: set progress bar for number of mods + # try: stale = find_stale_mods(self.prefs.paths.config) + # except Exception: + # # TODO: clearer error message + # func = StoredFunc(self._server_timeout) + # self.thread_man.set_cleanup_func(func) + # return + func = StoredFunc(self._on_stale_mods_found, stale) self.thread_man.set_cleanup_func(func) + def _server_timeout(self) -> None: + dialog = ExceptionDialog(self.controller, server_timeout) + dialog.run() + def select_colorized(self) -> None: model = self.treeview.get_model() if model is None: diff --git a/dzgui/managers/threading.py b/dzgui/managers/threading.py index a778124..8f85302 100644 --- a/dzgui/managers/threading.py +++ b/dzgui/managers/threading.py @@ -53,7 +53,7 @@ class ThreadingManager: def __init__(self, controller: "Controller") -> None: self.controller = controller self.jobs = 1 - self.cleanup_func: StoredFunc | None + self.cleanup_func: StoredFunc | None = None self.destroy_first = False def call_on_thread(self, dialog_str: str, func: StoredFunc) -> None: @@ -75,7 +75,9 @@ class ThreadingManager: def increment_dialog_with_str(self, text: str) -> None: GLib.idle_add(lambda: self.wait_dialog.increment(text)) - def set_cleanup_func(self, func: StoredFunc | None, destroy_first: bool = False) -> None: + def set_cleanup_func( + self, func: StoredFunc | None, destroy_first: bool = False + ) -> None: if type(func) not in (StoredFunc, type(None)): msg = f"Callback function '{func}' is not of type StoredFunc or None" logger.critical(msg) diff --git a/dzgui/views/base.py b/dzgui/views/base.py index bc9a816..681dc7b 100644 --- a/dzgui/views/base.py +++ b/dzgui/views/base.py @@ -23,6 +23,7 @@ from dzgui.views.pages.keys import Keybindings from dzgui.views.pages.log import Log from dzgui.views.pages.mods import Mods from dzgui.views.pages.options import Options +from dzgui.views.pages.preconnect import PreConnectionAssistant from dzgui.views.pages.servers import ServerNotebook from dzgui.views.pages.thanks import Thanks @@ -62,6 +63,8 @@ warnings.filterwarnings("ignore", ".*g_value_get_int", Warning) # return f"{record.ip}:{record.gameport}:{record.qport}" # # + + class OuterWindow(Gtk.Window): def __init__(self) -> None: super().__init__(title=APP_NAME, border_width=10, icon_name=APP_NAME_LOWER) @@ -125,6 +128,8 @@ class Notebook(ScrollableMixin, Gtk.Notebook): # type: ignore self.log = Log(MainController) self.developers = Developers(MainController) + self.connection = PreConnectionAssistant(MainController) + self.pages = { self.help: NotebookPage.HELP, self.clog: NotebookPage.CHANGELOG, @@ -135,6 +140,7 @@ class Notebook(ScrollableMixin, Gtk.Notebook): # type: ignore self.log: NotebookPage.LOG, self.thanks: NotebookPage.THANKS, self.developers: NotebookPage.DEVELOPERS, + self.connection: NotebookPage.CONNECTION, } self.indexes = {}