feat: threading with GLib WIP

This commit is contained in:
aclist committed 2026-02-15 02:04:54 +09:00
1 parent b703af897f
commit b9fe87cf90
10 files changed
+134 -127

No files matched your search

+4
View File
@@ -130,3 +130,7 @@ class Emitter(GObject.GObject):
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=()) @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
def api_change_failed(self) -> None: def api_change_failed(self) -> None:
pass pass
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(str,))
def keyword_set(self, keyword: str) -> None:
pass
+98 -69
View File
@@ -6,7 +6,7 @@ import traceback
from typing import Optional from typing import Optional
from warnings import deprecated from warnings import deprecated
from concurrent.futures import wait from concurrent.futures import wait, as_completed
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from functools import wraps from functools import wraps
from pathlib import Path from pathlib import Path
@@ -131,7 +131,7 @@ class Controller(GObject.GObject):
GLib.idle_add(self._destroy_on_idle) GLib.idle_add(self._destroy_on_idle)
self = args[0] self = args[0]
self.wait_dialog = WaitDialog(self, dialog_str) self.wait_dialog = WaitDialog(self, dialog_str, True)
self.wait_dialog.show_all() self.wait_dialog.show_all()
thread = threading.Thread(target=callback) thread = threading.Thread(target=callback)
thread.start() thread.start()
@@ -388,25 +388,38 @@ class Controller(GObject.GObject):
job = Servers.query_api job = Servers.query_api
params = Servers.params params = Servers.params
serv = [] serv = []
i = 0
total = 10
with ThreadPoolExecutor() as executor: with ThreadPoolExecutor() as executor:
futures = [executor.submit(job, key, APPID_DAYZ, param) for param in params] futures = [executor.submit(job, key, APPID_DAYZ, param) for param in params]
wait(futures) #wait(futures)
for future in futures: for future in as_completed(futures):
res = future.result() try:
if res.status != 200 or not res.parsed: i += 1
# TODO: pop warning dialog, create enum around various failure states GLib.idle_add(lambda: self.wait_dialog.prog.set_fraction(i/total))
# TODO: if first iteration, disable map combo. otherwise, do nothing res = future.result(timeout=3)
self.new_maps = None if res.status != 200 or not res.parsed:
self.push_data_failure() # None, FilterMode.INITIAL, success=False) # TODO: pop warning dialog, create enum around various failure states
return # set failure type here
j = res.json self.cleanup_func = CleanupFunc(self.cleanup_on_failure)
serv += j["response"]["servers"] return
j = res.json
serv += j["response"]["servers"]
except Exception as e:
# TODO: save exception text
print(e)
self.cleanup_func = CleanupFunc(self.cleanup_on_failure)
""" """
TODO: e.g. class method like 'total' TODO: e.g. class method like 'total'
total of 10 params for this call
@call_on_thread(msg, jobs=10)
if total > 1, pop progress bar
GLib.idle_add(lambda: self.wait_dialog.format_secondary_text("Pass 2")) GLib.idle_add(lambda: self.wait_dialog.format_secondary_text("Pass 2"))
GLib.idle_add(lambda: self.wait_dialog.prog.set_fraction(0.5)) subclass or wrap add fraction and increment, then GLib.idle_add(lambda: self.wait_dialog.prog.set_fraction(0.5))
calculate off of total subclass or wrap add fraction and increment, then calculate off of total
This next step is allowed to fail, since this metadata is incidental
""" """
res = Servers.query_api(key, APPID_DAYZ_EXP, "") res = Servers.query_api(key, APPID_DAYZ_EXP, "")
if res.status == 200 and res.parsed is True: if res.status == 200 and res.parsed is True:
@@ -416,11 +429,11 @@ class Controller(GObject.GObject):
GLib.idle_add( GLib.idle_add(
lambda: self.wait_dialog.format_secondary_text("Unpacking servers") lambda: self.wait_dialog.format_secondary_text("Unpacking servers")
) )
GLib.idle_add(lambda: self.wait_dialog.prog.set_fraction(10/total))
# TODO: additional ping column pass, collated # TODO: additional ping column pass, collated
# GLib.idle_add(lambda: self.wait_dialog.prog.set_fraction(0.75))
parsed = Servers.parse_json(serv) parsed = Servers.parse_json(serv)
self.push_data(parsed, FilterMode.INITIAL, success=True) self.push_data_success(parsed, FilterMode.INITIAL)
def get_help_row(self) -> str: def get_help_row(self) -> str:
tv = self.mediator.menu tv = self.mediator.menu
@@ -484,9 +497,22 @@ class Controller(GObject.GObject):
# mod = model.get(tree_iter, 2)[0] # mod = model.get(tree_iter, 2)[0]
# return mod, tree_iter # return mod, tree_iter
def get_mod_from_tree_path(
self, tree_path: Gtk.TreePath
) -> tuple[str, Gtk.TreeIter]:
model = self.get_mod_store()
tree_iter = model.get_iter(tree_path)
mod = model.get(tree_iter, 2)[0]
return mod, tree_iter
def delete_single_mod_cleanup(self, _iter: Gtk.TreeIter) -> None:
self.get_mod_store().remove(_iter)
# TODO: strings
@call_on_thread("deleting mod")
def delete_single_mod(self, tree_path: Gtk.TreePath) -> None: def delete_single_mod(self, tree_path: Gtk.TreePath) -> None:
config = self.prefs.paths.config config = self.prefs.paths.config
mod, it = self.model_man.get_mod_from_tree_path(tree_path) mod, _iter = self.get_mod_from_tree_path(tree_path)
path = lookup(config, Preferences.DEFAULT) path = lookup(config, Preferences.DEFAULT)
steam_path = Path(path) steam_path = Path(path)
@@ -507,8 +533,7 @@ class Controller(GObject.GObject):
except PeFile.AppNotInstalledError: except PeFile.AppNotInstalledError:
pass pass
model = self.get_mod_store() self.cleanup_func = CleanupFunc(self.delete_single_mod_cleanup, _iter)
model.remove(it)
def get_mod_store(self) -> Gtk.ListStore: def get_mod_store(self) -> Gtk.ListStore:
return self.mediator.modtreeview.get_model() return self.mediator.modtreeview.get_model()
@@ -551,29 +576,37 @@ class Controller(GObject.GObject):
# update config file with IP # update config file with IP
case ContextMenu.ADD_SERVER: case ContextMenu.ADD_SERVER:
pass pass
# spawn edit dialog and update cache, notes file # spawn edit dialog and update cache, notes file
case ContextMenu.ADD_NOTE: case ContextMenu.ADD_NOTE:
pass pass
case ContextMenu.COPY_CLIPBOARD: case ContextMenu.COPY_CLIPBOARD:
self.copy_ip(path) self.copy_ip(path)
case ContextMenu.COPY_NAME: case ContextMenu.COPY_NAME:
self.copy_name(path) self.copy_name(path)
case ContextMenu.DELETE_MOD: case ContextMenu.DELETE_MOD:
self.delete_single_mod(path) self.delete_single_mod(path)
# TODO: connect to emitter automatically # TODO: connect to emitter automatically
# Gtk.TreeModel, row-inserted/row-deleted # Gtk.TreeModel, row-inserted/row-deleted
# updates statusbar # updates statusbar
self.update_mod_statusbar() # FIXME: signal should instead be emitted off of treeview when rows added/inserted
#self.update_mod_statusbar()
remove_stale_signatures( remove_stale_signatures(
self.prefs.paths.config, self.prefs.paths.version self.prefs.paths.config, self.prefs.paths.version
) )
# call a2s on thread and update ephemeral model in situ # call a2s on thread and update ephemeral model in situ
case ContextMenu.REFRESH_PLAYERS: case ContextMenu.REFRESH_PLAYERS:
pass pass
# update history model, update tab label, pop off of queue, write new list into file # update history model, update tab label, pop off of queue, write new list into file
# see dq.py # see dq.py
case ContextMenu.REMOVE_HISTORY: case ContextMenu.REMOVE_HISTORY:
pass pass
# reverse of ADD_SERVER # reverse of ADD_SERVER
case ContextMenu.REMOVE_SERVER: case ContextMenu.REMOVE_SERVER:
pass pass
@@ -627,6 +660,7 @@ class Controller(GObject.GObject):
sel.select_path(path) sel.select_path(path)
# TODO: make as method of tree? # TODO: make as method of tree?
# FIXME: move cursor when finished
def uncolorize_mods(self) -> None: def uncolorize_mods(self) -> None:
model = self.get_mod_store() model = self.get_mod_store()
for mod in model: for mod in model:
@@ -794,15 +828,12 @@ class Controller(GObject.GObject):
False, False,
], ],
) )
self.push_data(data, FilterMode.INITIAL, success=True) self.push_data_success(data, FilterMode.INITIAL)
# TODO: eg dedicated cleanup on failure, cleanup on sucess
# these can pop their own predefined dialogs, much simpler
def get_map_man(self) -> "MapManager": def get_map_man(self) -> "MapManager":
return self.get_active_treeview().get_map_man() return self.get_active_treeview().get_map_man()
def cleanup(self) -> None: def cleanup_on_success(self) -> None:
treeview = self.get_active_treeview() treeview = self.get_active_treeview()
treeview.set_loaded(True) treeview.set_loaded(True)
treeview.set_model(self.to_insert) treeview.set_model(self.to_insert)
@@ -823,21 +854,15 @@ class Controller(GObject.GObject):
self.new_maps = None self.new_maps = None
treeview.grab_focus() treeview.grab_focus()
# if self.success is False:
# # TODO: different dialogs for server tab contexts, e.g. lan timeout
# # TODO: if history/favorites is empty, don't even trigger a call to dump data
# dialog = ExceptionDialog(self, "API TIMEOUT")
# dialog.run()
def cleanup_on_failure(self) -> None: def cleanup_on_failure(self) -> None:
treeview = self.get_active_treeview() treeview = self.get_active_treeview()
treeview.set_model(None) treeview.set_model(None)
treeview.set_loaded(True)
map_man = treeview.get_map_man() map_man = treeview.get_map_man()
# TODO: what if refresh action occurred, and the old model is still valid? # TODO: what if refresh action occurred, and the old model is still valid?
# TODO: disable map, keyword, and filter widgets if model is None? # TODO: disable map, keyword, and filter widgets if model is None
# -> signal driven (servers_empty) # -> signal driven (servers_empty)
# would have to make those unsensitive when changing server tabs
# if model is not None when changing tab, emit other signal
map_man.set_unique_maps(None) map_man.set_unique_maps(None)
context = self.get_active_context() context = self.get_active_context()
@@ -847,50 +872,49 @@ class Controller(GObject.GObject):
dialog = ExceptionDialog(self, "API TIMEOUT") dialog = ExceptionDialog(self, "API TIMEOUT")
dialog.run() dialog.run()
def push_data_failure(self) -> None: #def push_data_failure(self) -> None:
treeview = self.get_active_treeview() # #treeview = self.get_active_treeview()
treeview.set_loaded(True) # #treeview.set_loaded(True)
# TODO: wipe control model on failure or keep old results? # # TODO: wipe control model on failure or keep old results?
# manager = treeview.get_filter_man() # # manager = treeview.get_filter_man()
self.cleanup_func = CleanupFunc(self.cleanup_on_failure) # self.cleanup_func = CleanupFunc(self.cleanup_on_failure)
def push_data(self, data: tuple, mode: Optional[FilterMode], success: bool) -> None:
def push_data_success(self, data: tuple, mode: Optional[FilterMode]) -> None:
# FIXME: set outside of thread
treeview = self.get_active_treeview() treeview = self.get_active_treeview()
manager = treeview.get_filter_man() manager = treeview.get_filter_man()
self.to_insert = None self.to_insert = None
# TODO: drop if data is None:
self.success = success self.to_insert = None
if success: else:
if data is None: # TODO: consolidate into filter manager
self.to_insert = None if mode == FilterMode.INITIAL:
else: manager.set_control(data)
# TODO: consolidate into filter manager manager.filter(mode)
if mode == FilterMode.INITIAL: self.to_insert = manager.get_model()
manager.set_control(data) # TODO: pre parse maps
manager.filter(mode) u_maps = set([row[1] for row in data])
self.to_insert = manager.get_model() self.new_maps = sorted(u_maps)
# TODO: pre parse maps
u_maps = set([row[1] for row in data])
self.new_maps = sorted(u_maps)
treeview.set_loaded(True) treeview.set_loaded(True)
self.cleanup_func = CleanupFunc(self.cleanup) self.cleanup_func = CleanupFunc(self.cleanup_on_success)
@call_on_thread(strings.dialog.working) def highlight_stale_cleanup(self, stale_mods: list) -> None:
def highlight_stale(self) -> None:
model = self.get_mod_store() model = self.get_mod_store()
stale = find_stale_mods(self.prefs.paths.config)
for mod in model: for mod in model:
it = mod.iter it = mod.iter
path = model.get_path(it) path = model.get_path(it)
# TODO: consider storing in ListStore as int if int(mod[2]) in stale_mods:
# FIXME: deep copy existing model and set outside of thread
if int(mod[2]) in stale:
model[path][4] = HEX_RED model[path][4] = HEX_RED
self.cleanup_func = CleanupFunc(lambda: self.emitter.emit("mods_highlighted")) self.emitter.emit("mods_highlighted")
@call_on_thread(strings.dialog.working)
def highlight_stale(self) -> None:
stale = find_stale_mods(self.prefs.paths.config)
self.cleanup_func = CleanupFunc(self.highlight_stale_cleanup, stale)
def get_cleanup_func(self) -> CleanupFunc: def get_cleanup_func(self) -> CleanupFunc:
return self.cleanup_func return self.cleanup_func
@@ -923,8 +947,7 @@ class Controller(GObject.GObject):
if res is True: if res is True:
self.update_config(key, text) self.update_config(key, text)
else: else:
# FIXME: dialog spawning in thread self.cleanup_func = CleanupFunc(lambda: self.emitter.emit("api_change_failed"))
self.cleanup_func = CleanupFunc(self.emitter.emit("api_change_failed"))
def set_resolution(self, window: "OuterWindow") -> None: def set_resolution(self, window: "OuterWindow") -> None:
if self.prefs.is_game_mode: if self.prefs.is_game_mode:
@@ -976,13 +999,15 @@ class Controller(GObject.GObject):
@call_on_thread(strings.dialog.filtering) @call_on_thread(strings.dialog.filtering)
def filter_threaded(self, mode: FilterMode, label: str) -> None: def filter_threaded(self, mode: FilterMode, label: str) -> None:
# FIXME: call outside of thread
tv = self.get_active_treeview() tv = self.get_active_treeview()
filter_man = tv.get_filter_man() filter_man = tv.get_filter_man()
filter_man.filter(mode, label) filter_man.filter(mode, label)
self.push_data("", mode, success=True) # TODO: why pushing empty data?
self.push_data_success("", mode)
# FIXME: optional label/map/keyword parameter
# TODO: consolidate with method above # TODO: consolidate with method above
# TODO: call filter_man methods directly
def refilter_model(self, mode: FilterMode, label: Optional[str] = None) -> None: def refilter_model(self, mode: FilterMode, label: Optional[str] = None) -> None:
tv = self.get_active_treeview() tv = self.get_active_treeview()
filter_man = tv.get_filter_man() filter_man = tv.get_filter_man()
@@ -1001,9 +1026,11 @@ class Controller(GObject.GObject):
self.emitter.emit("servers_loaded", treeview.get_enum()) self.emitter.emit("servers_loaded", treeview.get_enum())
treeview.set_model(None) treeview.set_model(None)
return return
# TODO: clear ephemeral model if necessary # TODO: clear ephemeral model if necessary
# manager = treeview.get_filter_man() # manager = treeview.get_filter_man()
# manager.clear_model() # manager.clear_model()
self.first_iteration = True self.first_iteration = True
self.run_query_func(func) self.run_query_func(func)
@@ -1034,7 +1061,9 @@ class Controller(GObject.GObject):
# TODO: filterman calls back to here, gets convoluted # TODO: filterman calls back to here, gets convoluted
def get_keyword(self) -> str: def get_keyword(self) -> str:
return self.mediator.filters.get_keyword_filter() tv = self.get_active_treeview()
filter_man = tv.get_filter_man()
return filter_man.get_keyword_filter()
def get_map_store(self) -> Gtk.ListStore: def get_map_store(self) -> Gtk.ListStore:
map_man = self.get_map_man() map_man = self.get_map_man()
+13 -1
View File
@@ -14,6 +14,7 @@ from gi.repository import GObject, GLib # noqa E402
if TYPE_CHECKING: if TYPE_CHECKING:
from dzgui.controllers.mc import Controller from dzgui.controllers.mc import Controller
from dzgui.controllers.emitter import Emitter
@dataclass(slots=True, frozen=True) @dataclass(slots=True, frozen=True)
@@ -44,6 +45,8 @@ class FilteredModelManager:
def __init__(self, controller: "Controller") -> None: def __init__(self, controller: "Controller") -> None:
self.controller = controller self.controller = controller
self.emitter = controller.get_emitter()
self.emitter.connect("keyword_set", self._on_keyword_set)
self.filter_cache = {} self.filter_cache = {}
self.ping_cache: dict[str, int] = {} self.ping_cache: dict[str, int] = {}
@@ -55,6 +58,14 @@ class FilteredModelManager:
self.filtered: list = None self.filtered: list = None
self.success = True self.success = True
self.keyword_filter = ""
def get_keyword_filter(self) -> str:
return self.keyword_filter
def _on_keyword_set(self, emitter: "Emitter", keyword: str) -> None:
self.keyword_filter = keyword
def append_row(self, row: list) -> None: def append_row(self, row: list) -> None:
self.ephemeral_model.append(row) self.ephemeral_model.append(row)
@@ -120,6 +131,7 @@ class FilteredModelManager:
self.set_cache(filters, clone, rows) self.set_cache(filters, clone, rows)
self.set_model(clone) self.set_model(clone)
return clone
def sort_rows(self, rows: list) -> list: def sort_rows(self, rows: list) -> list:
rows.sort(key=lambda x: re.sub(r"[^A-Za-z0-9]+", "", x[0].lower())) rows.sort(key=lambda x: re.sub(r"[^A-Za-z0-9]+", "", x[0].lower()))
@@ -148,7 +160,7 @@ class FilteredModelManager:
return rows return rows
def filter_keyword(self, filters: tuple) -> list: def filter_keyword(self, filters: tuple) -> list:
keyword = self.controller.get_keyword() keyword = self.keyword_filter
rows = self.filtered rows = self.filtered
if keyword == "": if keyword == "":
-8
View File
@@ -80,11 +80,3 @@ class ModelManager:
def append_map(self, row: list) -> None: def append_map(self, row: list) -> None:
self.map_store.append(row) self.map_store.append(row)
def get_mod_from_tree_path(
self, tree_path: Gtk.TreePath
) -> tuple[str, Gtk.TreeIter]:
model = self.get_mod_store()
tree_iter = model.get_iter(tree_path)
mod = model.get(tree_iter, 2)[0]
return mod, tree_iter
+6 -28
View File
@@ -3,7 +3,6 @@ from typing import Literal, TYPE_CHECKING
from dzgui.const.enum import FilterMode from dzgui.const.enum import FilterMode
from dzgui.const.constants import EXPAND, NO_EXPAND, NO_FILL, NO_PADDING, SEARCH_ICON from dzgui.const.constants import EXPAND, NO_EXPAND, NO_FILL, NO_PADDING, SEARCH_ICON
from dzgui.util import strings
from dzgui.util.margins import set_surrounding_margins from dzgui.util.margins import set_surrounding_margins
from dzgui.views.components.labels import BoldLabel from dzgui.views.components.labels import BoldLabel
@@ -17,7 +16,6 @@ logger = logging.getLogger(__name__)
if TYPE_CHECKING: if TYPE_CHECKING:
from dzgui.controllers.mc import Controller from dzgui.controllers.mc import Controller
from dzgui.controllers.emitter import Emitter from dzgui.controllers.emitter import Emitter
from dzgui.const.enum import ServerTab
class ButtonGrid(Gtk.Grid): class ButtonGrid(Gtk.Grid):
@@ -84,8 +82,8 @@ class KeywordEntry(Gtk.Entry):
# TODO :strings # TODO :strings
super().__init__(placeholder_text="Filter by keyword") super().__init__(placeholder_text="Filter by keyword")
self.keyword_filter = ""
self.controller = controller self.controller = controller
self.emitter = controller.get_emitter()
self.connect("activate", self._on_activated) self.connect("activate", self._on_activated)
self.connect("key-press-event", self._on_keypress) self.connect("key-press-event", self._on_keypress)
self.connect("icon-release", lambda *args: self.activate()) self.connect("icon-release", lambda *args: self.activate())
@@ -93,9 +91,6 @@ class KeywordEntry(Gtk.Entry):
self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, SEARCH_ICON) self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, SEARCH_ICON)
self.set_icon_activatable(Gtk.EntryIconPosition.SECONDARY, True) self.set_icon_activatable(Gtk.EntryIconPosition.SECONDARY, True)
def get_keyword(self) -> str:
return self.keyword_filter
def _on_keypress(self, entry: Gtk.Entry, event: Gdk.EventKey) -> bool: def _on_keypress(self, entry: Gtk.Entry, event: Gdk.EventKey) -> bool:
match event.keyval: match event.keyval:
case Gdk.KEY_Up: case Gdk.KEY_Up:
@@ -110,13 +105,15 @@ class KeywordEntry(Gtk.Entry):
def _on_activated(self, entry: Gtk.Entry) -> None: def _on_activated(self, entry: Gtk.Entry) -> None:
# TODO: investigate this method # TODO: investigate this method
self.controller.mediator.window.set_keep_below(False) self.controller.mediator.window.set_keep_below(False)
keyword = entry.get_text().lower() keyword = entry.get_text().lower()
if keyword == self.keyword_filter: if keyword == self.controller.get_keyword():
return return
if keyword.isspace(): if keyword.isspace():
return return
logger.info(f"User filtered by keyword '{keyword}'") logger.info(f"User filtered by keyword '{keyword}'")
self.keyword_filter = keyword self.emitter.emit("keyword_set", keyword)
self.controller.refilter_model(FilterMode.KEYWORD, keyword) self.controller.refilter_model(FilterMode.KEYWORD, keyword)
@@ -124,22 +121,6 @@ class FilterPanel(Gtk.Box):
def __init__(self, controller: "Controller") -> None: def __init__(self, controller: "Controller") -> None:
super().__init__(spacing=6, vexpand=False, orientation=Gtk.Orientation.VERTICAL) super().__init__(spacing=6, vexpand=False, orientation=Gtk.Orientation.VERTICAL)
# TODO: get these from metamanager
# self.default_filters = {
# strings.filter_1pp: True,
# strings.filter_day: True,
# strings.filter_empty: False,
# strings.filter_3pp: True,
# strings.filter_night: True,
# strings.filter_full: False,
# strings.filter_lowpop: True,
# strings.filter_nonascii: False,
# strings.filter_duplicate: False,
# strings.filter_official: True,
# strings.filter_unofficial: True,
# strings.filter_modded: True,
# }
self.controller = controller self.controller = controller
self.controller.register_widget("filters", self) self.controller.register_widget("filters", self)
self.emitter = self.controller.get_emitter() self.emitter = self.controller.get_emitter()
@@ -225,15 +206,12 @@ class FilterPanel(Gtk.Box):
enabled = self.controller.get_enabled_filters() enabled = self.controller.get_enabled_filters()
filters = [] filters = []
filters.append(selected) filters.append(selected)
filters.append(self.get_keyword_filter()) filters.append(self.controller.get_keyword())
for filt in enabled: for filt in enabled:
if enabled[filt] is False: if enabled[filt] is False:
filters.append(filt) filters.append(filt)
return tuple(filters) return tuple(filters)
def get_keyword_filter(self) -> str:
return self.keyword_entry.get_keyword()
# TODO: should be used when switching ServerTab contexts # TODO: should be used when switching ServerTab contexts
# use signals here # use signals here
# def reinit_panel(self) -> None: # def reinit_panel(self) -> None:
-6
View File
@@ -67,12 +67,6 @@ class ModSelectionPanel(Gtk.Box):
def _on_mod_page_toggled(self, emitter: "Emitter", state: bool) -> None: def _on_mod_page_toggled(self, emitter: "Emitter", state: bool) -> None:
self.set_visible(state) self.set_visible(state)
#def after_colorize(self) -> None:
# # TODO: split into signal that touches two widgets,
# # modtreeview and this widget
# #self.controller.unselect_all_mods()
# self.swap_sensitive(True)
def swap_sensitive(self, state: bool) -> None: def swap_sensitive(self, state: bool) -> None:
for child in self.stale_panel.get_children(): for child in self.stale_panel.get_children():
if child.enum == ModButton.HIGHLIGHT_STALE: if child.enum == ModButton.HIGHLIGHT_STALE:
+10 -9
View File
@@ -11,6 +11,7 @@ from gi.repository import Gtk, GObject # noqa E402
if TYPE_CHECKING: if TYPE_CHECKING:
from dzgui.const.enum import ServerTab from dzgui.const.enum import ServerTab
from dzgui.controllers.mc import Controller from dzgui.controllers.mc import Controller
from dzgui.controllers.emitter import Emitter
from dzgui.views.trees.tree_base import TreeView from dzgui.views.trees.tree_base import TreeView
from dzgui.views.base import Notebook from dzgui.views.base import Notebook
@@ -79,19 +80,19 @@ class Statusbar(Gtk.Grid):
return return
match enum: match enum:
case NotebookPage.MODS:
return
# FIXME: format on callback after mods load
#bar = self.controller.format_mod_statusbar()
case NotebookPage.HELP: case NotebookPage.HELP:
bar = self.controller.get_help_row() bar = self.controller.get_help_row()
case NotebookPage.SERVERS: # TODO: drop
context = self.controller.get_active_context() #case NotebookPage.MODS:
# FIXME: may be superfluous # return
#self.emitter.emit("servers_loaded", context) #case NotebookPage.SERVERS:
return # context = self.controller.get_active_context()
# # self.emitter.emit("servers_loaded", context)
# return
case NotebookPage.KEYS: case NotebookPage.KEYS:
bar = question_to_return bar = question_to_return
case _:
return
self.set_by_context(enum, bar) self.set_by_context(enum, bar)
-3
View File
@@ -283,7 +283,6 @@ class Options(Gtk.Box):
self.controller.update_config(enum, value) self.controller.update_config(enum, value)
case Preferences.BM | Preferences.STEAM: case Preferences.BM | Preferences.STEAM:
text = "".join(entry.get_text().split()) text = "".join(entry.get_text().split())
# self.controller.set_callback(self.restore_api_text, old_text, entry)
self.controller.update_api_key(text, enum) self.controller.update_api_key(text, enum)
def _on_api_change_failed(self, emitter: "Emitter") -> None: def _on_api_change_failed(self, emitter: "Emitter") -> None:
@@ -305,8 +304,6 @@ class Options(Gtk.Box):
# TODO: unimplemented # TODO: unimplemented
print("UNIMPLEMENTED") print("UNIMPLEMENTED")
# wait_msg = strings.dialog.updating_mods # wait_msg = strings.dialog.updating_mods
# show_wait_dialog = True
# call_on_thread(show_wait_dialog, cmd, wait_msg, "")
def _on_client_changed(self, combo: Gtk.ComboBoxText) -> None: def _on_client_changed(self, combo: Gtk.ComboBoxText) -> None:
# TODO: use two columns or constants here, not strings # TODO: use two columns or constants here, not strings
+1 -1
View File
@@ -1,5 +1,5 @@
import logging import logging
from typing import Any, Self, TYPE_CHECKING from typing import Any, TYPE_CHECKING
from dzgui.util import strings, localize from dzgui.util import strings, localize
from dzgui.views.trees.tree_base import TreeView from dzgui.views.trees.tree_base import TreeView
+2 -2
View File
@@ -77,8 +77,8 @@ class ServerTreeView(ContextMixin, TreeView):
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
column.set_resizable(True) column.set_resizable(True)
column.set_sort_column_id(i) column.set_sort_column_id(i)
if column_title == "Ping": #if column_title == "Ping":
column.set_cell_data_func(renderer, self._get_ping) # column.set_cell_data_func(renderer, self._get_ping)
if valid_json: if valid_json:
try: try: