fix: set cell renderer properties

This commit is contained in:
aclist committed 2026-02-22 22:57:44 +09:00
1 parent a22d1a6324
commit e56b89fd64
10 files changed
+160 -98

No files matched your search

+7 -2
View File
@@ -33,8 +33,13 @@ class Emitter(GObject.GObject):
pass pass
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=()) @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
def request_lan_entry_focus(self) -> None: def request_custom_port_focus(self) -> None:
"""User invoked Ctrl-p keybinding from ServerTreeView""" """User invoked Ctrl-n keybinding from ServerTreeView"""
pass
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
def request_default_port_focus(self) -> None:
"""user invoked ctrl-d keybinding from servertreeview"""
pass pass
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=()) @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
+7 -15
View File
@@ -4,18 +4,14 @@ import shutil
import threading import threading
import traceback import traceback
from concurrent.futures import wait, as_completed
from concurrent.futures import ThreadPoolExecutor
from functools import wraps from functools import wraps
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Optional, TYPE_CHECKING from typing import Any, Callable, Optional, TYPE_CHECKING
from warnings import deprecated from warnings import deprecated
import dzgui.api.pefile as PeFile import dzgui.api.pefile as PeFile
import dzgui.api.servers as Servers
import dzgui.util._json as JSON # noqa import dzgui.util._json as JSON # noqa
from dzgui.api.bm import map_id_to_record
from dzgui.api.mods import ( from dzgui.api.mods import (
get_delimited_mods, get_delimited_mods,
get_local_mod_path, get_local_mod_path,
@@ -112,7 +108,7 @@ class Controller(GObject.GObject):
self.prefs: UserPrefs self.prefs: UserPrefs
self.cleanup_func: StoredFunc = None self.cleanup_func: StoredFunc = None
#self.config_man = ConfigManager() # self.config_man = ConfigManager()
self.emitter = Emitter() self.emitter = Emitter()
self.emitter.connect("map_selection_changed", self._on_map_selection_changed) self.emitter.connect("map_selection_changed", self._on_map_selection_changed)
@@ -223,7 +219,7 @@ class Controller(GObject.GObject):
treeview = self.get_active_treeview() treeview = self.get_active_treeview()
columns = treeview.get_columns() columns = treeview.get_columns()
#columns_file = self.config_man.get_columns() # columns_file = self.config_man.get_columns()
columns_file = self.prefs.paths.columns columns_file = self.prefs.paths.columns
try: try:
data = JSON.read_json(columns_file) data = JSON.read_json(columns_file)
@@ -249,7 +245,7 @@ class Controller(GObject.GObject):
w, h = self.mediator.window.get_size() w, h = self.mediator.window.get_size()
data = {"res": {"width": w, "height": h}} data = {"res": {"width": w, "height": h}}
#res_path = self.config_man.get_resolution() # res_path = self.config_man.get_resolution()
res_path = self.prefs.paths.resolution res_path = self.prefs.paths.resolution
try: try:
write_json(data, res_path) write_json(data, res_path)
@@ -316,13 +312,13 @@ class Controller(GObject.GObject):
# TODO: delegate to threadmanager # TODO: delegate to threadmanager
@call_on_thread(strings.dialog.modlist) @call_on_thread(strings.dialog.modlist)
def load_mods(self) -> None: def load_mods(self) -> None:
model = ModelFactory().make_mod_store() #self.model_man.new_mod_store() model = ModelFactory().make_mod_store() # self.model_man.new_mod_store()
path = self.query_config(Preferences.DEFAULT) path = self.query_config(Preferences.DEFAULT)
mods = get_delimited_mods(Path(path)) mods = get_delimited_mods(Path(path))
for mod in mods: for mod in mods:
# NOTE: holds color column # NOTE: show highlight color bool
mod.append(None) mod.append(False)
model.append(mod) model.append(mod)
self.cleanup_func = StoredFunc(self.load_mods_cleanup, model) self.cleanup_func = StoredFunc(self.load_mods_cleanup, model)
@@ -749,7 +745,7 @@ class Controller(GObject.GObject):
it = mod.iter it = mod.iter
path = model.get_path(it) path = model.get_path(it)
if int(mod[2]) in stale_mods: if int(mod[2]) in stale_mods:
model[path][4] = HEX_RED model[path][4] = True
self.emitter.emit("mods_highlighted") self.emitter.emit("mods_highlighted")
@call_on_thread(strings.dialog.working) @call_on_thread(strings.dialog.working)
@@ -946,10 +942,6 @@ class Controller(GObject.GObject):
map_man.set_selected_map(selection) map_man.set_selected_map(selection)
self.refilter_model(FilterMode.MAP) self.refilter_model(FilterMode.MAP)
def hide_widgets_on_init(self) -> None:
self.mediator.grid.conpan.set_lan_visible(False)
self.mediator.grid.right_panel.sel_panel.hide()
def get_notebook(self) -> "Notebook": def get_notebook(self) -> "Notebook":
return self.mediator.notebook return self.mediator.notebook
+1
View File
@@ -21,6 +21,7 @@ def call_on_thread(dialog_str: str) -> Callable:
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
self = args[0] self = args[0]
stored = StoredFunc(func, *args, **kwargs) stored = StoredFunc(func, *args, **kwargs)
print("SELF", self)
if not hasattr(self, "thread_man"): if not hasattr(self, "thread_man"):
raise AttributeError raise AttributeError
if type(self.thread_man) is not ThreadingManager: if type(self.thread_man) is not ThreadingManager:
+17 -6
View File
@@ -18,7 +18,7 @@ class ModCols:
symlink: str symlink: str
directory: str directory: str
size: float size: float
color: str color: bool
@dataclass(slots=True, frozen=True) @dataclass(slots=True, frozen=True)
@@ -42,6 +42,17 @@ class MenuCols:
hidden: GObject.TYPE_PYOBJECT hidden: GObject.TYPE_PYOBJECT
class FastInsertListStore(ListStore):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
def append(self, row) -> None:
total = len(row)
i = len(self)
tree_iter = self.insert_with_values(i, tuple(range(0, total)), row)
return tree_iter
class ModelFactory: class ModelFactory:
def __init__(self) -> None: def __init__(self) -> None:
pass pass
@@ -49,17 +60,17 @@ class ModelFactory:
def new_model_from_logfile(self, path: str) -> None: def new_model_from_logfile(self, path: str) -> None:
store = self.make_log_store() store = self.make_log_store()
with open(path, "r") as f: with open(path, "r") as f:
lines = [ lines = [line.split(delimiter) for line in f.read().splitlines()]
line.split(delimiter) for line in f.read().splitlines()
]
for record in lines: for record in lines:
# NOTE: strip PII and API keys # NOTE: strip PII and API keys
clean = redact_log(record) clean = redact_log(record)
store.append(clean) store.append(clean)
return store return store
def new_model_from_class(self, cls: type) -> ListStore: def new_model_from_class(self, cls: type) -> FastInsertListStore:
store = ListStore(*[ftype for field, ftype in cls.__annotations__.items()]) store = FastInsertListStore(
*[ftype for field, ftype in cls.__annotations__.items()]
)
return store return store
def make_map_store(self) -> ListStore: def make_map_store(self) -> ListStore:
+51 -29
View File
@@ -12,7 +12,7 @@ from dzgui.const.constants import (
) )
from dzgui.const.enum import FilterMode, Preferences, ServerTab from dzgui.const.enum import FilterMode, Preferences, ServerTab
from dzgui.managers.thread_man import call_on_thread, StoredFunc, ThreadingManager from dzgui.managers.thread_man import call_on_thread, StoredFunc, ThreadingManager
from dzgui.util.strings import dialog from dzgui.util.strings import api_warn_msg, dialog
from dzgui.views.dialogs.generic import ExceptionDialog from dzgui.views.dialogs.generic import ExceptionDialog
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
@@ -36,8 +36,11 @@ logger = logging.getLogger(__name__)
# TODO: failure: spawns error dialog # TODO: failure: spawns error dialog
# TODO: non failure with empty model: updates statusbar # TODO: non failure with empty model: updates statusbar
class ServerModelManager: class ServerModelManager:
def __init__(self, controller: "Controller", tv: Gtk.TreeView, first_iteration=False) -> None: def __init__(
self, controller: "Controller", tv: Gtk.TreeView, first_iteration=False
) -> None:
enum = tv.get_enum() enum = tv.get_enum()
self.controller = controller self.controller = controller
@@ -58,6 +61,8 @@ class ServerModelManager:
# filter: iteration N+1 # filter: iteration N+1
self.first_iteration = first_iteration self.first_iteration = first_iteration
# TODO: pass servers.saved treeview when using conpan regardless of current context
match enum: match enum:
case ServerTab.BROWSER: case ServerTab.BROWSER:
# NOTE: extra DAYZ_EXP param # NOTE: extra DAYZ_EXP param
@@ -69,8 +74,11 @@ class ServerModelManager:
# TODO: get row count # TODO: get row count
self._dump_history() self._dump_history()
case ServerTab.LAN: case ServerTab.LAN:
return # NOTE: LAN tab is only loaded on demand
#self._dump_lan() pass
case _:
pass
# self._dump_lan()
@call_on_thread(dialog.fetching) @call_on_thread(dialog.fetching)
def _dump_api(self) -> None: def _dump_api(self) -> None:
@@ -85,14 +93,18 @@ class ServerModelManager:
self.thread_man.increment_dialog() self.thread_man.increment_dialog()
res = future.result(timeout=API_TIMEOUT) res = future.result(timeout=API_TIMEOUT)
if res.status != 200 or not res.parsed: if res.status != 200 or not res.parsed:
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure)
)
return return
j = res.json j = res.json
servers += j["response"]["servers"] servers += j["response"]["servers"]
except Exception as e: except Exception as e:
# TODO: could store exception in cleanup func # TODO: could store exception in cleanup func
logger.critical(e) logger.critical(e)
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure)
)
return return
# NOTE: This step is allowed to fail, since this metadata is incidental # NOTE: This step is allowed to fail, since this metadata is incidental
@@ -112,9 +124,7 @@ class ServerModelManager:
event = threading.Event() event = threading.Event()
with ThreadPoolExecutor() as executor: with ThreadPoolExecutor() as executor:
futures = [ futures = [executor.submit(Servers.test_ip, i, port, event) for i in ports]
executor.submit(Servers.test_ip, i, port, event) for i in ports
]
for future in as_completed(futures): for future in as_completed(futures):
try: try:
res = future.result(timeout=LAN_TIMEOUT) res = future.result(timeout=LAN_TIMEOUT)
@@ -122,14 +132,18 @@ class ServerModelManager:
# NOTE: first non-empty hit, flag pending threads to close # NOTE: first non-empty hit, flag pending threads to close
event.set() event.set()
servers.append(res) servers.append(res)
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_success)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_success)
)
return return
if res is None: if res is None:
continue continue
servers.append(res) servers.append(res)
except Exception as e: except Exception as e:
logger.critical(e) logger.critical(e)
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure)
)
if len(servers) == 0: if len(servers) == 0:
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure)) self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure))
return return
@@ -161,7 +175,9 @@ class ServerModelManager:
continue continue
servers.append(res) servers.append(res)
if len(servers) == 0: if len(servers) == 0:
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure)
)
return return
parsed = Servers.parse_json(servers) parsed = Servers.parse_json(servers)
@@ -200,8 +216,8 @@ class ServerModelManager:
# NOTE: this can be called from other tabs--if current focus is not ServerTab.SAVED, update label only # NOTE: this can be called from other tabs--if current focus is not ServerTab.SAVED, update label only
# TODO: saved servers might not be loaded yet, in which case should just update local file only # TODO: saved servers might not be loaded yet, in which case should just update local file only
# TODO: perform simple equality comparison of self.tv.get_enum() == ServerTab.SAVED # TODO: perform simple equality comparison of self.tv.get_enum() == ServerTab.SAVED
# FIXME: filter man is saved on a per tab basis, so this will mismatch # FIXME: filter man is saved on a per tab basis, so this will mismatch
# check if servers.get_active_treeview() is same as self.tv # check if servers.get_active_treeview() is same as self.tv
self.set_cleanup_func(StoredFunc(self._cleanup_on_insert)) self.set_cleanup_func(StoredFunc(self._cleanup_on_insert))
def _dump_history(self) -> None: def _dump_history(self) -> None:
@@ -211,10 +227,14 @@ class ServerModelManager:
with open(history, "r") as f: with open(history, "r") as f:
rows = [row.rstrip("\n") for row in f] rows = [row.rstrip("\n") for row in f]
except OSError: except OSError:
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure, False)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure, False)
)
return return
if len(rows) == 0: if len(rows) == 0:
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure, False)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure, False)
)
return return
self.thread_man.set_job_count(len(rows)) self.thread_man.set_job_count(len(rows))
self._dump_ips(rows) self._dump_ips(rows)
@@ -226,7 +246,9 @@ class ServerModelManager:
if len(ips) == 0: if len(ips) == 0:
# FIXME: this is not a failure, just a quiet exit with custom statusbar # FIXME: this is not a failure, just a quiet exit with custom statusbar
# TODO: add custom statusbar parameters # TODO: add custom statusbar parameters
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure, False)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure, False)
)
return return
self._dump_ips(ips) self._dump_ips(ips)
@@ -273,10 +295,10 @@ class ServerModelManager:
self.new_maps = None self.new_maps = None
def _cleanup_on_failure(self, show_dialog=True) -> None: def _cleanup_on_failure(self, show_dialog=True) -> None:
map_man = self.treeview.get_map_man() map_man = self.tv.get_map_man()
# 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, servers_failed_to_load) # -> signal driven (servers_empty, servers_failed_to_load)
# TODO: what if refresh action occurred and failed, and the old model is still valid? # TODO: what if refresh action occurred and failed, and the old model is still valid?
# skip the step below if refresh action failed # skip the step below if refresh action failed
# do not wipe control model in this case # do not wipe control model in this case
@@ -284,15 +306,15 @@ class ServerModelManager:
# revert old model # revert old model
# wipe refresh state to False # wipe refresh state to False
self.treeview.set_model(None) self.tv.set_model(None)
map_man.set_unique_maps(None) map_man.set_unique_maps(None)
context = self.treeview.get_enum() context = self.tv.get_enum()
# TODO: distinguish signals, e.g. "servers_failed_to_load", "servers_loaded_empty" # TODO: distinguish signals, e.g. "servers_failed_to_load", "servers_loaded_empty"
# customize statusbar accordingly # customize statusbar and dialog accordingly
self.emitter.emit("servers_loaded", context) self.emitter.emit("servers_loaded", context)
if show_dialog: if show_dialog:
dialog = ExceptionDialog(self, strings.api_warn_msg) dialog = ExceptionDialog(self.controller, api_warn_msg)
dialog.run() dialog.run()
# TODO: break into initial dump and refilter modes, can drop filtermode kwarg # TODO: break into initial dump and refilter modes, can drop filtermode kwarg
@@ -330,9 +352,9 @@ class ServerModelManager:
# self.cleanup_func = StoredFunc(self.cleanup_on_success) # self.cleanup_func = StoredFunc(self.cleanup_on_success)
# TODO: call filter_man methods directly # 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() self.filter_man = tv.get_filter_man()
# if filter_man.get_control() is None: if self.filter_man.get_control() is None:
# return return
# self.filter_threaded(filter_man, mode, label) self.filter_threaded(self.filter_man, mode, label)
+2 -1
View File
@@ -132,7 +132,8 @@ servers = {
"Ctrl-p": "refresh ping", "Ctrl-p": "refresh ping",
"Ctrl-f": "jump to keyword search field", "Ctrl-f": "jump to keyword search field",
"Ctrl-m": "jump to maps field", "Ctrl-m": "jump to maps field",
"Ctrl-d": "toggle dry run (debug) mode", "Ctrl-d": "select default LAN port",
"Ctrl-n": "select custom LAN port",
"Ctrl-i": "jump to IP insert field", "Ctrl-i": "jump to IP insert field",
"ESC": "return to table", "ESC": "return to table",
"1-9": "toggle filter 1-9 on/off", "1-9": "toggle filter 1-9 on/off",
+36 -13
View File
@@ -32,9 +32,11 @@ class LanPanel(Gtk.Frame):
label = BoldLabel(lan_panel.heading) label = BoldLabel(lan_panel.heading)
self.set_label_widget(label) self.set_label_widget(label)
self.radio1 = Gtk.RadioButton.new_with_label(None, lan_panel.default_button) self.default_radio = Gtk.RadioButton.new_with_label(
radio2 = Gtk.RadioButton.new_with_label_from_widget( None, lan_panel.default_button
self.radio1, lan_panel.custom_button )
self.custom_radio = Gtk.RadioButton.new_with_label_from_widget(
self.default_radio, lan_panel.custom_button
) )
self.entry = PortEntry(controller) self.entry = PortEntry(controller)
@@ -47,18 +49,22 @@ class LanPanel(Gtk.Frame):
"Unless you have multiple DayZ servers on your LAN,\nleave this checked to get results faster" "Unless you have multiple DayZ servers on your LAN,\nleave this checked to get results faster"
) )
self.entry.connect("activate", self._on_entry_activated)
self.entry.connect("string_validated", self._on_port_validated) self.entry.connect("string_validated", self._on_port_validated)
self.emitter.connect("request_custom_port_focus", self._on_custom_port_binding)
self.emitter.connect( self.emitter.connect(
"request_lan_entry_focus", lambda _: self.entry.grab_focus() "request_default_port_focus", lambda _: self.default_radio.set_active(True)
) )
self.radio1.connect("toggled", self._on_radio_toggled) self.default_radio.connect("toggled", self._on_radio_toggled)
self.grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5) self.grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
self.grid.attach(self.radio1, 0, 0, COLS, ROWS) self.grid.attach(self.default_radio, 0, 0, COLS, ROWS)
self.grid.attach_next_to( self.grid.attach_next_to(
radio2, self.radio1, Gtk.PositionType.RIGHT, COLS, ROWS self.custom_radio, self.default_radio, Gtk.PositionType.RIGHT, COLS, ROWS
)
self.grid.attach_next_to(
self.entry, self.custom_radio, Gtk.PositionType.RIGHT, COLS, ROWS
) )
self.grid.attach_next_to(self.entry, radio2, Gtk.PositionType.RIGHT, COLS, ROWS)
self.grid.attach_next_to( self.grid.attach_next_to(
self.scan, self.entry, Gtk.PositionType.RIGHT, COLS, ROWS self.scan, self.entry, Gtk.PositionType.RIGHT, COLS, ROWS
) )
@@ -70,23 +76,36 @@ class LanPanel(Gtk.Frame):
self.entry.set_sensitive(False) self.entry.set_sensitive(False)
def _on_custom_port_binding(self, emitter: "Emitter") -> None:
self.custom_radio.set_active(True)
self.entry.grab_focus()
def _on_entry_activated(self, entry: Gtk.Entry) -> None:
if self.entry.get_text() == "":
return
self.scan_ports()
def _on_scan_clicked(self, button: Gtk.Button) -> None: def _on_scan_clicked(self, button: Gtk.Button) -> None:
if self.radio1.get_active(): self.scan_ports()
def scan_ports(self) -> None:
if self.default_radio.get_active():
port = 27016 port = 27016
else: else:
port = self.entry.get_text() port = self.entry.get_text()
abort = self.early_abort.get_active() abort = self.early_abort.get_active()
smm = ServerModelManager(self.controller, self.controller.get_active_treeview()) smm = ServerModelManager(self.controller, self.controller.get_active_treeview())
smm.dump_lan(int(port), abort) smm.dump_lan(int(port), abort)
#self.controller.dump_lan(int(port), abort)
def _on_radio_toggled(self, button: Gtk.RadioButton) -> None: def _on_radio_toggled(self, button: Gtk.RadioButton) -> None:
state = button.get_active() state = button.get_active()
self.entry.set_sensitive(not state) self.entry.set_sensitive(not state)
if state: if state:
self.scan.set_sensitive(True) self.scan.set_sensitive(True)
elif len(self.entry.get_text()) < 1: else:
self.scan.set_sensitive(False) self.entry.grab_focus()
if len(self.entry.get_text()) < 1:
self.scan.set_sensitive(False)
def _on_port_validated(self, entry: Gtk.Entry, state: bool) -> None: def _on_port_validated(self, entry: Gtk.Entry, state: bool) -> None:
self.scan.set_sensitive(state) self.scan.set_sensitive(state)
@@ -182,9 +201,13 @@ class AddPanel(Gtk.Frame):
def _submit_query(self) -> None: def _submit_query(self) -> None:
text = self.entry.get_text() text = self.entry.get_text()
self.controller.add_by_id_or_ip(text) # TODO: call servermodelmanager
ServerModelManager().add_by_id_or_ip(text)
# self.controller.add_by_id_or_ip(text)
def _on_activate(self, entry: Gtk.Entry) -> None: def _on_activate(self, entry: Gtk.Entry) -> None:
if not self.add_server.is_sensitive():
return
self._submit_query() self._submit_query()
def _on_add_clicked(self, button: Gtk.Button) -> None: def _on_add_clicked(self, button: Gtk.Button) -> None:
+4 -4
View File
@@ -1,6 +1,6 @@
import logging import logging
from typing import Self, TYPE_CHECKING from typing import Optional, Self, TYPE_CHECKING
from dzgui.controllers.mc import StoredFunc from dzgui.controllers.mc import StoredFunc
from dzgui.const.enum import ContextMenuGroup, ServerTab from dzgui.const.enum import ContextMenuGroup, ServerTab
@@ -76,13 +76,13 @@ class ServerNotebook(Gtk.ScrolledWindow):
def _on_unmap(self, widget: Self) -> None: def _on_unmap(self, widget: Self) -> None:
self.emitter.emit("server_page_toggled", False) self.emitter.emit("server_page_toggled", False)
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None: def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> Optional[False]:
if event.state is Gdk.ModifierType.CONTROL_MASK:
return False
match event.keyval: match event.keyval:
case Gdk.KEY_n: case Gdk.KEY_n:
self.notebook.next_page() self.notebook.next_page()
case Gdk.KEY_p: case Gdk.KEY_p:
if event.state is Gdk.ModifierType.CONTROL_MASK:
return
self.notebook.prev_page() self.notebook.prev_page()
case _: case _:
return return
+22 -5
View File
@@ -1,11 +1,12 @@
import logging import logging
from typing import Any, TYPE_CHECKING from typing import Any, TYPE_CHECKING
from dzgui.const.constants import HEX_RED
from dzgui.const.enum import ContextMenuGroup
from dzgui.util import strings, localize from dzgui.util import strings, localize
from dzgui.views.trees.tree_base import TreeView
from dzgui.views.mixins.context_mixin import ContextMixin from dzgui.views.mixins.context_mixin import ContextMixin
from dzgui.views.mixins.mods_mixin import ModsMixin from dzgui.views.mixins.mods_mixin import ModsMixin
from dzgui.const.enum import ContextMenuGroup from dzgui.views.trees.tree_base import TreeView
import gi import gi
@@ -35,14 +36,15 @@ class ModTreeView(ModsMixin, ContextMixin, TreeView):
for i, column_title in enumerate(strings.mod_cols): for i, column_title in enumerate(strings.mod_cols):
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i, foreground=4) column = Gtk.TreeViewColumn(column_title, renderer, text=i)
if i == 3: column.set_cell_data_func(renderer, self._format_color, func_data=None)
if i == 4:
column.set_cell_data_func(renderer, self._format_float, func_data=None) column.set_cell_data_func(renderer, self._format_float, func_data=None)
if column_title == "Mod": if column_title == "Mod":
column.set_fixed_width(500) column.set_fixed_width(500)
else: else:
column.set_fixed_width(150) column.set_fixed_width(150)
# NOTE: hidden color property column
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
column.set_sort_column_id(i) column.set_sort_column_id(i)
if i != 4: if i != 4:
@@ -88,6 +90,21 @@ class ModTreeView(ModsMixin, ContextMixin, TreeView):
def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection): def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection):
pass pass
def _format_color(
self,
column: Gtk.TreeViewColumn,
cell: Gtk.CellRendererText,
model: Gtk.TreeModel,
it: Gtk.TreeIter,
data: Any,
) -> Any:
state = model[it][4]
if state is True:
cell.set_property("foreground", HEX_RED)
else:
cell.set_property("foreground", None)
return
def _format_float( def _format_float(
self, self,
column: Gtk.TreeViewColumn, column: Gtk.TreeViewColumn,
+13 -23
View File
@@ -8,12 +8,11 @@ from warnings import deprecated
from dzgui.views.mixins.context_mixin import ContextMixin from dzgui.views.mixins.context_mixin import ContextMixin
from dzgui.const.enum import ContextMenu, ContextMenuGroup, ServerTab from dzgui.const.enum import ContextMenu, ContextMenuGroup, ServerTab
from dzgui.api.servers import Record from dzgui.api.servers import Record
from dzgui.api.servers import ping as Ping
from dzgui.model.map_model import MapManager from dzgui.model.map_model import MapManager
from dzgui.model.filtered_model import FilteredModelManager from dzgui.model.filtered_model import FilteredModelManager
from dzgui.util.dist import CalcDist from dzgui.util.dist import CalcDist
from dzgui.util import strings from dzgui.util import strings
from typing import Callable, Literal, TYPE_CHECKING from typing import Literal, TYPE_CHECKING
from dzgui.views.trees.tree_base import TreeView from dzgui.views.trees.tree_base import TreeView
@@ -28,7 +27,7 @@ from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
if TYPE_CHECKING: if TYPE_CHECKING:
from dzgui.controllers.mc import Controller, StoredFunc from dzgui.controllers.mc import Controller
from dzgui.controllers.emitter import Emitter from dzgui.controllers.emitter import Emitter
QUEUE_CHECK_DELAY = 200 QUEUE_CHECK_DELAY = 200
@@ -216,7 +215,7 @@ class ServerTreeView(ContextMixin, TreeView):
while not self.queue.empty(): while not self.queue.empty():
latest_result = self.queue.get() latest_result = self.queue.get()
# FIXME: cache is being checked at two intervals # FIXME: cache is being checked in two passes
cache = self.controller.get_dist_cache() cache = self.controller.get_dist_cache()
if latest_result: if latest_result:
@@ -239,9 +238,11 @@ class ServerTreeView(ContextMixin, TreeView):
self.emitter.emit("request_maps_focus") self.emitter.emit("request_maps_focus")
case Gdk.KEY_i: case Gdk.KEY_i:
self.emitter.emit("request_ip_entry_focus") self.emitter.emit("request_ip_entry_focus")
case Gdk.KEY_p: case Gdk.KEY_d:
self.emitter.emit("request_default_port_focus")
case Gdk.KEY_n:
if self.enum is ServerTab.LAN: if self.enum is ServerTab.LAN:
self.emitter.emit("request_lan_entry_focus") self.emitter.emit("request_custom_port_focus")
case Gdk.KEY_c: case Gdk.KEY_c:
self.controller.menu_action(ContextMenu.COPY_SERVER_IP, self) self.controller.menu_action(ContextMenu.COPY_SERVER_IP, self)
case Gdk.KEY_r: case Gdk.KEY_r:
@@ -294,23 +295,12 @@ class ServerTreeView(ContextMixin, TreeView):
return f"{addr}:{qport}" return f"{addr}:{qport}"
def get_record(self) -> Record | None: def get_record(self) -> Record | None:
# TODO: clean up, use tree_base.get_selected_row() r = self.get_record_string()
select = self.get_selection() try:
sels = select.get_selected_rows() ip, gameport, qport = r.split(":")
(model, pathlist) = sels return Record(ip, int(gameport), int(qport))
if len(pathlist) < 1: except ValueError:
return None return None
path = pathlist[0]
model = self.get_model()
if not model:
return None
addr = model[path][7]
if addr is None:
return
qport = model[path][8]
ip = addr.split(":")[0]
gameport = int(addr.split(":")[1])
return Record(ip, gameport, qport)
def is_loaded(self) -> bool: def is_loaded(self) -> bool:
return self.loaded return self.loaded
@@ -348,7 +338,7 @@ class ServerTreeView(ContextMixin, TreeView):
# thread = threading.Thread( # thread = threading.Thread(
# daemon=True, # daemon=True,
# target=ping_server, # target=ping_server,
# args=(model, it, ip, qport, ping), # args=(model, it, addr, qport, ping),
# ) # )
# thread.start() # thread.start()