chore: clean up context menu mixin

This commit is contained in:
aclist committed 2026-02-21 18:35:06 +09:00
1 parent 62da949465
commit dec2bf7e6f
4 files changed
+108 -266

No files matched your search

+24 -128
View File
@@ -172,30 +172,30 @@ class Controller(GObject.GObject):
def unblock_signals(self) -> None: def unblock_signals(self) -> None:
self.block_signals(False) self.block_signals(False)
@deprecated("Currently unused") # @deprecated("Currently unused")
def block_signals(self, state: bool = True) -> None: # def block_signals(self, state: bool = True) -> None:
self.suppress_signal( # self.suppress_signal(
self.mediator.filters, # self.mediator.filters,
self.mediator.filters.maps_combo, # self.mediator.filters.maps_combo,
"_on_map_changed", # "_on_map_changed",
state, # state,
) # )
self.suppress_signal( # self.suppress_signal(
self.mediator.menu, # self.mediator.menu,
self.mediator.menu.selected_row, # self.mediator.menu.selected_row,
"_on_tree_selection_changed", # "_on_tree_selection_changed",
state, # state,
) # )
self.suppress_signal( # self.suppress_signal(
self.mediator.menu, self.mediator.menu, "_on_keypress", state # self.mediator.menu, self.mediator.menu, "_on_keypress", state
) # )
for check in self.mediator.filters.checks: # for check in self.mediator.filters.checks:
self.suppress_signal( # self.suppress_signal(
self.mediator.filters, # self.mediator.filters,
check, # check,
"_on_check_toggled", # "_on_check_toggled",
state, # state,
) # )
def suppress_signal( def suppress_signal(
self, owner: Gtk.Widget, widget: Gtk.Widget, func_name: str, state: bool self, owner: Gtk.Widget, widget: Gtk.Widget, func_name: str, state: bool
@@ -554,54 +554,6 @@ class Controller(GObject.GObject):
client = self.query_config(Preferences.CLIENT) client = self.query_config(Preferences.CLIENT)
open_user_workshop(uid, client) open_user_workshop(uid, client)
# def copy_log(self, paths: list[Gtk.TreePath]) -> str:
# if len(paths) < 1:
# return ""
# final = []
# for path in paths:
# record = self.log_store[path]
# r = [el for el in record]
# concat = strings.delimiter.join(r)
# final.append(concat)
# text = "\n".join(final)
# return text
# def get_col_value_by_path_index(self, path: Gtk.TreePath, index: int) -> Any:
# treeview = self.get_active_treeview()
# model = treeview.get_model()
# if model is None:
# return None
# value = model[path][index]
# return value
# def copy_name(self, path: Gtk.TreePath) -> None:
# name = self.get_col_value_by_path_index(path, 0)
# if name is None:
# return
# self.copy_clipboard(name)
# def copy_ip(self, path: Gtk.TreePath) -> None:
# treeview = self.get_active_treeview()
# record = treeview.get_record()
# self.copy_clipboard(f"{record.ip}:{record.qport}")
# def copy_clipboard(self, text: str) -> None:
# self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
# self.clipboard.set_text(text, -1)
# def open_mod_page(self, path: Gtk.TreePath) -> None:
# mod, it = self.get_mod_from_tree_path(path)
# cmd = self.query_config(Preferences.CLIENT)
# open_workshop_page(mod, cmd)
# 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: def delete_single_mod_cleanup(self, _iter: Gtk.TreeIter) -> None:
self.get_mod_store().remove(_iter) self.get_mod_store().remove(_iter)
remove_stale_signatures(self.prefs.paths.config, self.prefs.paths.version) remove_stale_signatures(self.prefs.paths.config, self.prefs.paths.version)
@@ -668,64 +620,8 @@ class Controller(GObject.GObject):
self.emitter.emit("fav_server_changed", name, simple_ip) self.emitter.emit("fav_server_changed", name, simple_ip)
def menu_action(self, action: ContextMenu, tree: Gtk.TreeView) -> None: def menu_action(self, action: ContextMenu, tree: Gtk.TreeView) -> None:
# TODO: pass prefs into contextman
context_man = ContextMenuManager(tree, self) context_man = ContextMenuManager(tree, self)
context_man.process(action) context_man.process(action)
# context_man.process(action)
# match action:
# # NOTE: manipulates server stores and caches
# # add to saved servers model verbatim and sort in place
# # update tab with !
# # update config file with IP
# # TODO: needs threading
# case ContextMenu.ADD_SERVER:
# pass
# # spawn edit dialog and update cache, notes file
# case ContextMenu.ADD_NOTE:
# pass
# case ContextMenu.COPY_CLIPBOARD:
# self.copy_ip(path)
# case ContextMenu.COPY_NAME:
# self.copy_name(path)
# case ContextMenu.DELETE_MOD:
# self.delete_single_mod(path)
# # TODO: connect to emitter automatically
# # Gtk.TreeModel, row-inserted/row-deleted
# # updates statusbar
# # FIXME: signal should instead be emitted off of treeview when rows added/inserted
# # self.update_mod_statusbar()
# case ContextMenu.REFRESH_PLAYERS:
# # get record
# # call a2s on thread
# pass
# # update history model, update tab label, pop off of queue, write new list into file
# # see dq.py
# case ContextMenu.REMOVE_HISTORY:
# pass
# # reverse of ADD_SERVER
# case ContextMenu.REMOVE_SERVER:
# pass
# case ContextMenu.SET_FAV:
# self.set_fav()
# # NOTE: spawns dedicated dialogs
# # TODO: needs threading
# case ContextMenu.SHOW_DETAILS:
# pass
# # TODO: needs threading
# case ContextMenu.SHOW_MODS:
# pass
# case ContextMenu.OPEN_WORKSHOP:
# self.open_mod_page(path)
def toggle_mod_selection(self, state: bool) -> None: def toggle_mod_selection(self, state: bool) -> None:
sel = self.mediator.modtreeview.get_selection() sel = self.mediator.modtreeview.get_selection()
+19 -22
View File
@@ -18,9 +18,8 @@ class ContextMixin(TreeView):
widget: Gtk.Widget, widget: Gtk.Widget,
event: Gdk.EventButton | Gdk.EventKey, event: Gdk.EventButton | Gdk.EventKey,
) -> None: ) -> None:
# FIXME: double click causes issue
# split into present by click and present by key
# FIXME: start debug log focused
if self.is_selection_empty(): if self.is_selection_empty():
return False return False
@@ -42,8 +41,7 @@ class ContextMixin(TreeView):
self.context_menu.connect("key-press-event", self._on_key) self.context_menu.connect("key-press-event", self._on_key)
for row in group.value: for row in group.value:
item = Gtk.MenuItem(label=row.dict["label"]) item = self._process_dynamic_row(row)
item.connect("activate", self._on_menu_click, row)
self.context_menu.append(item) self.context_menu.append(item)
self.context_menu.show_all() self.context_menu.show_all()
@@ -58,6 +56,22 @@ class ContextMixin(TreeView):
self.context_menu.select_first(False) self.context_menu.select_first(False)
def _process_dynamic_row(self, row: ContextMenu) -> None:
if row == ContextMenu.ADD_SERVER and self.is_in_favs():
row = ContextMenu.REMOVE_SERVER
item = Gtk.MenuItem(label=row.dict["label"])
item.connect("activate", self._on_menu_click, row)
if row == ContextMenu.SHOW_MODS:
item.set_sensitive(self.is_modded())
return item
# TODO: notes cache
# if row == ContextMenu.ADD_NOTE:
# if self.get_record_string() in notes_cache:
# item.set_label(strings.edit_note)
def _process_button_event(self, event: Gdk.EventButton) -> None: def _process_button_event(self, event: Gdk.EventButton) -> None:
try: try:
pathinfo = self.get_path_at_pos(int(event.x), int(event.y)) pathinfo = self.get_path_at_pos(int(event.x), int(event.y))
@@ -71,24 +85,7 @@ class ContextMixin(TreeView):
pass pass
def _on_menu_click(self, widget: Gtk.MenuItem, enum: ContextMenu) -> None: def _on_menu_click(self, widget: Gtk.MenuItem, enum: ContextMenu) -> None:
""" self.controller.menu_action(enum, self)
Local mods page allows multi selection, so ensure that only focused row
is selected. Used by ContextMenu.OPEN_WORKSHOP and ContextMenu.DELETE_MOD.
ModTreeView supports multi-delete, but context menu enforces
single deletion on the focused row.
Debug log page allows multi selection and copy of rows, so special handling
is used per below.
"""
if enum == ContextMenu.COPY_LOG_CLIPBOARD:
model, records = self.get_selection().get_selected_rows()
clipboard = self.controller.copy_log(records)
self.controller.copy_clipboard(clipboard)
else:
#path = self.get_focused_row_path()
#self.controller.menu_action(enum, path)
self.controller.menu_action(enum, self)
def _on_key(self, menu: Gtk.Menu, event: Gdk.EventKey) -> bool | None: def _on_key(self, menu: Gtk.Menu, event: Gdk.EventKey) -> bool | None:
if not is_navkey(event.keyval): if not is_navkey(event.keyval):
+4 -28
View File
@@ -8,6 +8,7 @@ from dzgui.views.trees.tree_base import TreeView
from dzgui.views.mixins.context_mixin import ContextMixin from dzgui.views.mixins.context_mixin import ContextMixin
import gi import gi
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402 from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402
@@ -16,6 +17,7 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class LogTreeView(ContextMixin, TreeView): class LogTreeView(ContextMixin, TreeView):
def __init__(self, controller: "Controller") -> None: def __init__(self, controller: "Controller") -> None:
super().__init__(controller, menu=ContextMenuGroup.LOG) super().__init__(controller, menu=ContextMenuGroup.LOG)
@@ -33,42 +35,16 @@ class LogTreeView(ContextMixin, TreeView):
for i, column_title in enumerate(strings.log_cols): for i, column_title in enumerate(strings.log_cols):
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn( column = Gtk.TreeViewColumn(column_title, renderer, text=i)
column_title, renderer, text=i
)
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)
self.append_column(column) self.append_column(column)
self.connect("button-press-event", self._on_log_button_press)
self.connect("button-release-event", self._on_log_button_release)
self.connect("key-press-event", self._on_log_keypress) self.connect("key-press-event", self._on_log_keypress)
self.connect("button-press-event", self._on_log_keypress)
self.s = self.get_selection().get_selected_rows() self.s = self.get_selection().get_selected_rows()
def _on_log_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None: def _on_log_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None:
self.present_menu(widget, event) self.present_menu(widget, event)
def _on_log_button_press(self,
widget: Gtk.Widget,
event: Gdk.EventButton
) -> bool:
"""
Prevents context menu from deselecting rows
"""
if event.button == 3:
self.s = self.get_selection().get_selected_rows()
return True
return False
def _on_log_button_release(self,
widget: Gtk.Widget,
event: Gdk.EventButton
) -> None:
if event.button == 3:
self.present_menu(widget, event)
self.get_selection().unselect_all()
for row in self.s[1]:
self.get_selection().select_path(row)
+61 -88
View File
@@ -1,11 +1,12 @@
import logging import logging
import threading import threading
from queue import Queue
from typing import Any, Optional, Self from typing import Any, Optional, Self
from warnings import deprecated 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 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.api.servers import ping as Ping
from dzgui.model.map_model import MapManager from dzgui.model.map_model import MapManager
@@ -60,12 +61,10 @@ class ServerTreeView(ContextMixin, TreeView):
self.handler_id: int self.handler_id: int
self.query_func_jobs = 1 self.query_func_jobs = 1
self.seen_cache = []
self.current_proc = None self.current_proc = None
from queue import Queue
self.queue = Queue() self.queue = Queue()
#self.queue = multiprocessing.Queue() # self.queue = multiprocessing.Queue()
prefs = self.controller.get_prefs() prefs = self.controller.get_prefs()
columns = prefs.paths.columns columns = prefs.paths.columns
@@ -132,42 +131,6 @@ class ServerTreeView(ContextMixin, TreeView):
self.thread = None self.thread = None
def _get_ping(
self,
column: Gtk.TreeViewColumn,
cell: Gtk.CellRendererText,
model: Gtk.TreeModel,
it: Gtk.TreeIter,
data: Any,
):
def ping_server(model, _iter, ip: str, qport: int, ping: int):
# res = Ping(0, model[_iter])
res = Ping(0, ip, qport, ping)
ping = res.ping
print(res)
GLib.idle_add(lambda: model.set(_iter, ping_column, ping))
addr_column = 7
qport_column = 8
ping_column = 9
# TODO: unpack model before entering thread
# test 40k servers with unpacked model
addr = model.get_value(it, addr_column).split(":")[0]
qport = model.get_value(it, qport_column)
ping = model.get_value(it, ping_column)
ip = f"{addr}:{qport}"
if ip in self.seen_cache:
return
self.seen_cache.append(ip)
thread = threading.Thread(
daemon=True,
target=ping_server,
args=(model, it, ip, qport, ping),
)
thread.start()
def start_timeout(self) -> None: def start_timeout(self) -> None:
self.queue_id = GLib.timeout_add(QUEUE_CHECK_DELAY, self._check_result_queue) self.queue_id = GLib.timeout_add(QUEUE_CHECK_DELAY, self._check_result_queue)
@@ -238,15 +201,7 @@ class ServerTreeView(ContextMixin, TreeView):
# NOTE: get final width after drag action completes # NOTE: get final width after drag action completes
GLib.idle_add(self.controller.propagate_column_width, col) GLib.idle_add(self.controller.propagate_column_width, col)
#def terminate_process(self) -> None:
# if self.thread and self.thread.is_alive():
# print("thread still exists")
# if self.current_proc and self.current_proc.is_alive():
# self.current_proc.terminate()
def start_distcalc(self, emitter: Optional["Emitter"] = None): def start_distcalc(self, emitter: Optional["Emitter"] = None):
#self.terminate_process()
#self.queue_id = GLib.timeout_add(QUEUE_CHECK_DELAY, self._check_result_queue)
self.emitter.emit("distcalc_started") self.emitter.emit("distcalc_started")
record = self.get_record() record = self.get_record()
if record is None: if record is None:
@@ -261,11 +216,6 @@ class ServerTreeView(ContextMixin, TreeView):
self.controller.set_statusbar_dist(haversine, self.get_enum()) self.controller.set_statusbar_dist(haversine, self.get_enum())
return return
#def t(ip, enum, queue) -> None:
# if queue.empty():
# queue.put(["LONG DISTANCE", 0])
enum = self.get_enum() enum = self.get_enum()
self.thread = threading.Thread( self.thread = threading.Thread(
daemon=True, daemon=True,
@@ -273,16 +223,13 @@ class ServerTreeView(ContextMixin, TreeView):
args=(record.ip, enum, self.queue, self.controller), args=(record.ip, enum, self.queue, self.controller),
) )
self.thread.start() self.thread.start()
#self.current_proc = CalcDist(
# record.ip, self.get_enum(), self.queue, self.controller
#)
#self.current_proc.start()
def _check_result_queue(self) -> Literal[True]: def _check_result_queue(self) -> Literal[True]:
latest_result = None latest_result = None
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
cache = self.controller.get_dist_cache() cache = self.controller.get_dist_cache()
if latest_result: if latest_result:
@@ -299,9 +246,6 @@ class ServerTreeView(ContextMixin, TreeView):
) -> bool | None: ) -> bool | None:
if event.state is Gdk.ModifierType.CONTROL_MASK: if event.state is Gdk.ModifierType.CONTROL_MASK:
match event.keyval: match event.keyval:
case Gdk.KEY_r:
# TODO: unimplemented, threading
self.refresh_player_count()
case Gdk.KEY_f: case Gdk.KEY_f:
self.emitter.emit("request_keyword_focus") self.emitter.emit("request_keyword_focus")
case Gdk.KEY_m: case Gdk.KEY_m:
@@ -312,8 +256,10 @@ class ServerTreeView(ContextMixin, TreeView):
if self.enum is ServerTab.LAN: if self.enum is ServerTab.LAN:
self.emitter.emit("request_lan_entry_focus") self.emitter.emit("request_lan_entry_focus")
case Gdk.KEY_c: case Gdk.KEY_c:
record = self.get_record() self.controller.menu_action(ContextMenu.COPY_SERVER_IP, self)
self.controller.copy_ip(record) case Gdk.KEY_r:
# TODO: unimplemented, needs threading
self.controller.menu_action(ContextMenu.REFRESH_PLAYERS, self)
else: else:
match event.keyval: match event.keyval:
case Gdk.KEY_l | Gdk.KEY_Right: case Gdk.KEY_l | Gdk.KEY_Right:
@@ -321,30 +267,23 @@ class ServerTreeView(ContextMixin, TreeView):
case _: case _:
self.emitter.emit("check_button_pressed", event.keyval) self.emitter.emit("check_button_pressed", event.keyval)
# mod_context_items = [ContextMenu.OPEN_WORKSHOP, ContextMenu.DELETE_MOD] # TODO: unimplemented
# TODO: dynamic menu entries # def is_modded(self) -> bool:
# for row in items: # select = self.get_selection()
# if row == ContextMenu.ADD_SERVER: # sels = select.get_selected_rows()
# if self.is_in_favs(): # (model, pathlist) = sels
# row = ContextMenu.REMOVE_SERVER # path = pathlist[0]
# item = Gtk.MenuItem(label=row.dict["label"]) # tree_iter = model.get_iter(path)
# item.type = row # mods = model.get_value(tree_iter, 11)
# item.action = row.dict["action"] # return mods
# self.menu.append(item)
# if row == ContextMenu.SHOW_MODS:
# if not self.has_mods():
# item.set_sensitive(False)
# if row == ContextMenu.ADD_NOTE:
# if self.get_record_string() in notes_cache:
# item.set_label(strings.edit_note)
# if event.type is Gdk.EventType.KEY_PRESS and event.keyval is Gdk.KEY_l: # TODO: unimplemented
# if self.is_selection_empty(): # def is_in_favs(self) -> bool:
# return # record = self.get_record_string()
# self.menu.popup_at_widget(widget, Gdk.Gravity.CENTER, Gdk.Gravity.WEST) # proc = call_out("is_in_favs", record)
# else: # if proc.returncode == 0:
# self.menu.popup_at_pointer(event) # return True
# self.menu.select_first(False) # return False
def _parent_row_activated( def _parent_row_activated(
self, tree: TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn self, tree: TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn
@@ -368,7 +307,7 @@ 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: use tree_base.get_selected_row() # TODO: clean up, use tree_base.get_selected_row()
select = self.get_selection() select = self.get_selection()
sels = select.get_selected_rows() sels = select.get_selected_rows()
(model, pathlist) = sels (model, pathlist) = sels
@@ -392,6 +331,40 @@ class ServerTreeView(ContextMixin, TreeView):
def set_loaded(self, status: bool) -> None: def set_loaded(self, status: bool) -> None:
self.loaded = status self.loaded = status
# @deprecated("currently unused")
# def _get_ping(
# self,
# column: Gtk.TreeViewColumn,
# cell: Gtk.CellRendererText,
# model: Gtk.TreeModel,
# it: Gtk.TreeIter,
# data: Any,
# ):
# def ping_server(model, _iter, ip: str, qport: int, ping: int):
# res = Ping(0, ip, qport, ping)
# ping = res.ping
# GLib.idle_add(lambda: model.set(_iter, ping_column, ping))
# addr_column = 7
# qport_column = 8
# ping_column = 9
# addr = model.get_value(it, addr_column).split(":")[0]
# qport = model.get_value(it, qport_column)
# ping = model.get_value(it, ping_column)
# ip = f"{addr}:{qport}"
# if ip in self.seen_cache:
# return
# self.seen_cache.append(ip)
# thread = threading.Thread(
# daemon=True,
# target=ping_server,
# args=(model, it, ip, qport, ping),
# )
# thread.start()
@deprecated("Currently unused") @deprecated("Currently unused")
def _lazy_load( def _lazy_load(
self, self,