feat: populate ServerTreeViews

This commit is contained in:
aclist committed 2025-12-21 20:40:29 +09:00
1 parent 4a3d407e5f
commit 37dab3e83b
9 files changed
+140 -130

No files matched your search

+20 -16
View File
@@ -311,6 +311,7 @@ class ContextMenu(EnumWithAttrs):
OPEN_WORKSHOP = {"label": strings.open_workshop} OPEN_WORKSHOP = {"label": strings.open_workshop}
DELETE_MOD = {"label": strings.delete_mod} DELETE_MOD = {"label": strings.delete_mod}
COPY_LOG_CLIPBOARD = {"label": strings.copy_log} COPY_LOG_CLIPBOARD = {"label": strings.copy_log}
CONNECT = {"label": strings.connect}
class ContextMenuGroup(Enum): class ContextMenuGroup(Enum):
@@ -324,6 +325,7 @@ class ContextMenuGroup(Enum):
ContextMenu.COPY_LOG_CLIPBOARD, ContextMenu.COPY_LOG_CLIPBOARD,
) )
SERVER_BROWSER = ( SERVER_BROWSER = (
ContextMenu.CONNECT,
ContextMenu.ADD_SERVER, ContextMenu.ADD_SERVER,
ContextMenu.COPY_NAME, ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD, ContextMenu.COPY_CLIPBOARD,
@@ -333,6 +335,7 @@ class ContextMenuGroup(Enum):
ContextMenu.REFRESH_PLAYERS, ContextMenu.REFRESH_PLAYERS,
) )
SCAN_LAN = ( SCAN_LAN = (
ContextMenu.CONNECT,
ContextMenu.COPY_NAME, ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD, ContextMenu.COPY_CLIPBOARD,
ContextMenu.ADD_NOTE, ContextMenu.ADD_NOTE,
@@ -341,6 +344,7 @@ class ContextMenuGroup(Enum):
ContextMenu.REFRESH_PLAYERS, ContextMenu.REFRESH_PLAYERS,
) )
SAVED = ( SAVED = (
ContextMenu.CONNECT,
ContextMenu.REMOVE_SERVER, ContextMenu.REMOVE_SERVER,
ContextMenu.COPY_NAME, ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD, ContextMenu.COPY_CLIPBOARD,
@@ -350,6 +354,7 @@ class ContextMenuGroup(Enum):
ContextMenu.REFRESH_PLAYERS, ContextMenu.REFRESH_PLAYERS,
) )
RECENT = ( RECENT = (
ContextMenu.CONNECT,
ContextMenu.ADD_SERVER, ContextMenu.ADD_SERVER,
ContextMenu.REMOVE_HISTORY, ContextMenu.REMOVE_HISTORY,
ContextMenu.COPY_NAME, ContextMenu.COPY_NAME,
@@ -360,22 +365,6 @@ class ContextMenuGroup(Enum):
ContextMenu.REFRESH_PLAYERS, ContextMenu.REFRESH_PLAYERS,
) )
HELP_MENU_ROWS = (
RowType.CHANGELOG,
RowType.SHOW_LOG,
RowType.DUMP_LOG,
RowType.SEPARATOR,
RowType.DOCS,
RowType.DOCS_FALLBACK,
RowType.BUGS,
RowType.FORUM,
RowType.SPONSOR,
RowType.SEPARATOR,
RowType.THANKS,
)
class ModButton(EnumWithAttrs): class ModButton(EnumWithAttrs):
SELECT_ALL = { SELECT_ALL = {
"label": strings.mod_panel.select_all, "label": strings.mod_panel.select_all,
@@ -429,3 +418,18 @@ class ButtonType(EnumWithAttrs):
"tooltip": strings.buttons.exit_tooltip, "tooltip": strings.buttons.exit_tooltip,
"opens": None, "opens": None,
} }
HELP_MENU_ROWS = (
RowType.CHANGELOG,
RowType.SHOW_LOG,
RowType.DUMP_LOG,
RowType.SEPARATOR,
RowType.DOCS,
RowType.DOCS_FALLBACK,
RowType.BUGS,
RowType.FORUM,
RowType.SPONSOR,
RowType.SEPARATOR,
RowType.THANKS,
)
+17 -11
View File
@@ -68,7 +68,7 @@ class Controller:
def set_help_menu_crumbs(self) -> None: def set_help_menu_crumbs(self) -> None:
# TODO: going to be deprecated after server notebook is added # TODO: going to be deprecated after server notebook is added
tip = self.mediator.treeview.get_model()[0][0] tip = self.mediator.menu.get_model()[0][0]
store = self.model_manager.get_help_store()[0][0] store = self.model_manager.get_help_store()[0][0]
if tip == store: if tip == store:
self.set_crumbs("Help") self.set_crumbs("Help")
@@ -79,8 +79,17 @@ class Controller:
def get_crumbs(self) -> str: def get_crumbs(self) -> str:
return self.mediator.grid.get_breadcrumbs() return self.mediator.grid.get_breadcrumbs()
#def get_row_store(self) -> Gtk.ListStore: def get_server_store(self) -> Gtk.ListStore:
# return self.model_manager.get_row_store() return self.model_manager.get_server_store()
def get_saved_store(self) -> Gtk.ListStore:
return self.model_manager.get_saved_store()
def get_recent_store(self) -> Gtk.ListStore:
return self.model_manager.get_recent_store()
def get_lan_store(self) -> Gtk.ListStore:
return self.model_manager.get_lan_store()
def get_help_store(self) -> Gtk.ListStore: def get_help_store(self) -> Gtk.ListStore:
return self.model_manager.get_help_store() return self.model_manager.get_help_store()
@@ -137,12 +146,12 @@ class Controller:
state, state,
) )
self.suppress_signal( self.suppress_signal(
self.mediator.treeview, self.mediator.menu,
self.mediator.treeview.selected_row, self.mediator.menu.selected_row,
"_on_tree_selection_changed", "_on_tree_selection_changed",
state, state,
) )
self.suppress_signal(self.mediator.treeview, self.mediator.treeview, "_on_keypress", state) self.suppress_signal(self.mediator.menu, self.mediator.menu, "_on_keypress", state)
for check in self.mediator.grid.right_panel.filters_vbox.checks: for check in self.mediator.grid.right_panel.filters_vbox.checks:
self.suppress_signal( self.suppress_signal(
self.mediator.grid.right_panel.filters_vbox, self.mediator.grid.right_panel.filters_vbox,
@@ -161,7 +170,7 @@ class Controller:
else: else:
widget.handler_unblock_by_func(func) widget.handler_unblock_by_func(func)
# TODO # TODO
#self.mediator.treeview.sel_blocked = state #self.mediator.menu.sel_blocked = state
def toggle_debug_mode(self) -> None: def toggle_debug_mode(self) -> None:
self.toggle_config(Preferences.DEBUG) self.toggle_config(Preferences.DEBUG)
@@ -278,7 +287,6 @@ class Controller:
self.mediator.grid.notebook.set_page_by_enum(page) self.mediator.grid.notebook.set_page_by_enum(page)
def open_page_by_button(self, button: "ContextualButton") -> None: def open_page_by_button(self, button: "ContextualButton") -> None:
print(button.context)
match button.context: match button.context:
case ButtonType.EXIT: case ButtonType.EXIT:
logger.info("Normal user exit") logger.info("Normal user exit")
@@ -289,9 +297,7 @@ class Controller:
case ButtonType.MODS: case ButtonType.MODS:
self.load_mods() self.load_mods()
case ButtonType.HELP: case ButtonType.HELP:
help_store = self.model_manager.get_help_store() pass
# TODO: simply set this model once and open the page
self.mediator.treeview.set_model(help_store)
case ButtonType.SERVERS: case ButtonType.SERVERS:
self.mediator.notebook.set_page_by_enum(button.opens) self.mediator.notebook.set_page_by_enum(button.opens)
# TODO: shorten this # TODO: shorten this
+16 -3
View File
@@ -76,9 +76,10 @@ class ModelManager:
self.log_store = self.new_model_from_class(LogCols) self.log_store = self.new_model_from_class(LogCols)
self.modlist_store = self.new_model_from_class(ServerModCols) self.modlist_store = self.new_model_from_class(ServerModCols)
#for row in MAIN_MENU_ROWS: self.server_store = self.new_model()
# label = row.dict["label"] self.saved_store = self.new_model()
# self.row_store.append([label, row]) self.recent_store = self.new_model()
self.lan_store = self.new_model()
for row in HELP_MENU_ROWS: for row in HELP_MENU_ROWS:
label = row.dict["label"] label = row.dict["label"]
@@ -93,6 +94,18 @@ class ModelManager:
cls.instance = super(ModelManager, cls).__new__(cls) cls.instance = super(ModelManager, cls).__new__(cls)
return cls.instance return cls.instance
def get_recent_store(self) -> ListStore:
return self.recent_store
def get_lan_store(self) -> ListStore:
return self.lan_store
def get_saved_store(self) -> ListStore:
return self.saved_store
def get_server_store(self) -> ListStore:
return self.server_store
def new_model_from_class(self, cls: type) -> ListStore: def new_model_from_class(self, cls: type) -> ListStore:
store = ListStore(*[ftype for field, ftype in cls.__annotations__.items()]) store = ListStore(*[ftype for field, ftype in cls.__annotations__.items()])
return store return store
+2 -3
View File
@@ -19,8 +19,7 @@ def is_navkey(key: int) -> bool:
return False return False
def is_ctrl_mask(event: Gdk.EventKey) -> bool: def is_ctrl_mask(event: Gdk.EventKey) -> bool:
if event.keyval is Gdk.KEY_l \ if event.state is Gdk.ModifierType.CONTROL_MASK:
and event.state is Gdk.ModifierType.CONTROL_MASK: return True
return True
else: else:
return False return False
+16 -1
View File
@@ -53,8 +53,9 @@ copy_name = "Copy name to clipboard"
copy_ip = "Copy IP to clipboard" copy_ip = "Copy IP to clipboard"
copy_log = "Copy record(s) to clipboard" copy_log = "Copy record(s) to clipboard"
add = "Add to my servers" add = "Add to my servers"
remove = "Remove from my servers" remove = "Remove from Saved Servers"
remove_history = "Remove from history" remove_history = "Remove from history"
connect = "Connect"
# Columns # Columns
server_mod_cols = ["Mod", "ID", "Installed"] server_mod_cols = ["Mod", "ID", "Installed"]
@@ -496,3 +497,17 @@ developers = DevelopersPage(
prefs_label="Boot preferences", prefs_label="Boot preferences",
columns=["Key", "Value"] columns=["Key", "Value"]
) )
@dataclass(slots=True, frozen=True)
class ServerLabels:
browser: str
saved: str
recent: str
lan: str
server_labels = ServerLabels(
browser="Server Browser",
saved="Saved Servers",
recent="Recent",
lan="LAN",
)
+26 -23
View File
@@ -47,6 +47,7 @@ from dzgui.views.dialogs.generic import GenericDialog
from dzgui.views.mixins.scrollable_mixin import ScrollableMixin from dzgui.views.mixins.scrollable_mixin import ScrollableMixin
# TREES # TREES
from dzgui.views.trees.tree_menu import MenuTreeView
from dzgui.views.trees.tree_log import LogTreeView from dzgui.views.trees.tree_log import LogTreeView
from dzgui.views.trees.tree_mods import ModTreeView from dzgui.views.trees.tree_mods import ModTreeView
from dzgui.views.trees.tree_servers import ServerTreeView from dzgui.views.trees.tree_servers import ServerTreeView
@@ -308,21 +309,17 @@ class Notebook(ScrollableMixin, Gtk.Notebook):
AppNav.notebook = self AppNav.notebook = self
self.prior_page: int self.prior_page: int
# TODO: set static help page from dzgui.views.pages.help import Help
#self.scrollable_treelist = ScrollableTree() self.help = Help(MainController)
#self.scrollable_treelist.set_hexpand(False) view = self.help.get_treeview()
#self.scrollable_treelist.set_vexpand(True) AppNav.menu = view
#self.scrollable_treelist.type = None
self.change = Changelog(MainController) self.change = Changelog(MainController)
self.clog = ScrollableNote(self.change, back_button=False) self.clog = ScrollableNote(self.change, back_button=False)
self.clog.scrollable.set_propagate_natural_width(False) self.clog.scrollable.set_propagate_natural_width(False)
self.clog.type = RowType.CHANGELOG
# TODO: scrollable internally # TODO: scrollable internally
self.keys = ScrollableNote(Keybindings()) self.keys = ScrollableNote(Keybindings())
self.keys.type = RowType.KEYBINDINGS
self.settings = Options(MainController) self.settings = Options(MainController)
# TODO: make all treeviews internally scrollable in base class # TODO: make all treeviews internally scrollable in base class
@@ -354,6 +351,7 @@ class Notebook(ScrollableMixin, Gtk.Notebook):
self.developers = ScrollableNote(developers) self.developers = ScrollableNote(developers)
self.pages = { self.pages = {
self.help: NotebookPage.HELP,
#self.scrollable_treelist: NotebookPage.MAIN, #self.scrollable_treelist: NotebookPage.MAIN,
self.clog: NotebookPage.CHANGELOG, self.clog: NotebookPage.CHANGELOG,
self.keys: NotebookPage.KEYS, self.keys: NotebookPage.KEYS,
@@ -452,14 +450,21 @@ class Notebook(ScrollableMixin, Gtk.Notebook):
def focus_current(self) -> None: def focus_current(self) -> None:
widget = self.get_page() widget = self.get_page()
if widget: if widget is None:
w = widget.get_children()[0] return
# NOTE: if item contains treeview, focus first cell
try: if widget is self.servers:
w.focus_first_row() view = self.servers.get_active_treeview()
w.grab_focus() view.grab_focus()
except Exception as e: return
w.grab_focus()
w = widget.get_children()[0]
# NOTE: if item contains treeview, focus first cell
try:
w.focus_first_row()
w.grab_focus()
except Exception as e:
w.grab_focus()
def get_page(self) -> Gtk.Widget | None: def get_page(self) -> Gtk.Widget | None:
ind = self.get_current_page() ind = self.get_current_page()
@@ -491,13 +496,10 @@ class Notebook(ScrollableMixin, Gtk.Notebook):
is_mods = True if enum is NotebookPage.MODS else False is_mods = True if enum is NotebookPage.MODS else False
MainController.toggle_mod_panel(is_mods) MainController.toggle_mod_panel(is_mods)
# TODO:
crumbs = enum.dict["crumbs"] crumbs = enum.dict["crumbs"]
MainController.set_crumbs(crumbs) MainController.set_crumbs(crumbs)
# TODO:
# MainController.set_help_menu_crumbs()
# TODO: move to components # TODO: move to components
class Statusbar(Gtk.Statusbar): class Statusbar(Gtk.Statusbar):
def __init__(self) -> None: def __init__(self) -> None:
@@ -570,6 +572,9 @@ class Grid(Gtk.Grid):
AppNav.grid = self AppNav.grid = self
self.breadcrumbs = Gtk.Label(halign=Gtk.Align.START)
self.set_breadcrumbs(strings.label_main_menu)
# FIXME: do not pass AppNav to right panel # FIXME: do not pass AppNav to right panel
self.right_panel = RightPanel(AppNav, MainController) self.right_panel = RightPanel(AppNav, MainController)
self.sel_panel = ModSelectionPanel(MainController) self.sel_panel = ModSelectionPanel(MainController)
@@ -578,8 +583,6 @@ class Grid(Gtk.Grid):
self.notebook = Notebook() self.notebook = Notebook()
self.statusbar = Statusbar() self.statusbar = Statusbar()
self.breadcrumbs = Gtk.Label(halign=Gtk.Align.START)
self.set_breadcrumbs(strings.label_main_menu)
self.attach(self.notebook, 0, 0, 3, 1) self.attach(self.notebook, 0, 0, 3, 1)
self.attach_next_to( self.attach_next_to(
@@ -649,7 +652,7 @@ class AppNavigation:
window: OuterWindow window: OuterWindow
notebook: Notebook notebook: Notebook
right_panel: RightPanel right_panel: RightPanel
#treeview: MenuTreeView menu: MenuTreeView
servers: Gtk.ScrolledWindow servers: Gtk.ScrolledWindow
browser: ServerTreeView browser: ServerTreeView
saved: ServerTreeView saved: ServerTreeView
+6 -4
View File
@@ -54,11 +54,13 @@ class ButtonBox(Gtk.Box):
def _on_selection_button_clicked(self, button: Gtk.Button) -> None: def _on_selection_button_clicked(self, button: Gtk.Button) -> None:
# # TODO: maybe drop this and just ensure buttons respond correctly
self.controller.open_page_by_button(button) self.controller.open_page_by_button(button)
button.set_sensitive(False) # if button.context != ButtonType.HELP:
for b in self.buttons: # button.set_sensitive(False)
if b != button: # for b in self.buttons:
b.set_sensitive(True) # if b != button:
# b.set_sensitive(True)
def _walk_buttons(self, increment: int) -> None: def _walk_buttons(self, increment: int) -> None:
for i, button in enumerate(self.buttons): for i, button in enumerate(self.buttons):
+2 -2
View File
@@ -29,8 +29,8 @@ class MenuTreeView(TreeView):
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
self.append_column(column) self.append_column(column)
row_store = self.controller.get_row_store() help_store = self.controller.get_help_store()
self.set_model(row_store) self.set_model(help_store)
self.selected_row = self.get_selection() self.selected_row = self.get_selection()
+35 -67
View File
@@ -8,6 +8,7 @@ from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
from dzgui.const.enum import ( from dzgui.const.enum import (
ContextMenu, ContextMenu,
ContextMenuGroup,
RowType, RowType,
) )
from dzgui.const.constants import UDP_PORT from dzgui.const.constants import UDP_PORT
@@ -29,6 +30,12 @@ if TYPE_CHECKING:
# TODO: add multiprocessing queue # TODO: add multiprocessing queue
# TODO: fix cache # TODO: fix cache
class EnumeratedMenuItem(Gtk.MenuItem):
def __init__(self, enum: ContextMenu):
super().__init__(label=enum.dict["label"])
self.enum = enum
class ServerTreeView(TreeView): class ServerTreeView(TreeView):
__gsignals__ = { __gsignals__ = {
"on_distcalc_started": (GObject.SignalFlags.RUN_FIRST, None, ()) "on_distcalc_started": (GObject.SignalFlags.RUN_FIRST, None, ())
@@ -36,6 +43,7 @@ class ServerTreeView(TreeView):
def __init__(self, controller: "Controller") -> None: def __init__(self, controller: "Controller") -> None:
super().__init__(controller) super().__init__(controller)
self.menu = Gtk.Menu()
self.controller = controller self.controller = controller
self.set_fixed_height_mode(True) self.set_fixed_height_mode(True)
@@ -62,9 +70,6 @@ class ServerTreeView(TreeView):
column.set_resizable(True) column.set_resizable(True)
column.set_sort_column_id(i) column.set_sort_column_id(i)
# TODO: use index of column instead of name
# so literal name won't matter
# needs conversion logic for old configs
if valid_json: if valid_json:
try: try:
saved_size = data["cols"][column_title] saved_size = data["cols"][column_title]
@@ -81,11 +86,8 @@ class ServerTreeView(TreeView):
self.append_column(column) self.append_column(column)
self.connect("on_distcalc_started", self._on_calclat_started) self.connect("on_distcalc_started", self._on_calclat_started)
self.connect("button-release-event", self._on_server_button_release) self.connect("button-release-event", self._on_server_button_release)
self.connect("key-press-event", self._on_server_keypress) self.connect("key-press-event", self._on_server_keypress)
self.connect("generic_row_activated", self._parent_row_activated) self.connect("generic_row_activated", self._parent_row_activated)
self.connect("generic_treesel_changed", self._parent_selection_changed) self.connect("generic_treesel_changed", self._parent_selection_changed)
@@ -150,6 +152,18 @@ class ServerTreeView(TreeView):
case _: case _:
return False return False
def set_context_menu(self, items: ContextMenuGroup) -> None:
# TODO: if debug is on, add raw command
for item in items.value:
menu_item = EnumeratedMenuItem(item)
menu_item.connect("activate", self._on_menu_click)
self.menu.append(menu_item)
self.menu.show_all()
def _on_menu_click(self, item) -> None:
print(item.enum)
pass
def _on_server_button_release( def _on_server_button_release(
self, widget: Gtk.Widget, event: Gdk.EventButton self, widget: Gtk.Widget, event: Gdk.EventButton
) -> None: ) -> None:
@@ -168,69 +182,23 @@ class ServerTreeView(TreeView):
except AttributeError: except AttributeError:
pass pass
self.menu = Gtk.Menu()
mod_context_items = [ContextMenu.OPEN_WORKSHOP, ContextMenu.DELETE_MOD] mod_context_items = [ContextMenu.OPEN_WORKSHOP, ContextMenu.DELETE_MOD]
# TODO: reimplement server context enums
# TODO: inherit from tree_servers.py
server_context_items = {
RowType.SERVER_BROWSER: [
ContextMenu.ADD_SERVER,
ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD,
ContextMenu.ADD_NOTE,
ContextMenu.SHOW_MODS,
ContextMenu.SHOW_DETAILS,
ContextMenu.REFRESH_PLAYERS,
],
RowType.SCAN_LAN: [
ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD,
ContextMenu.ADD_NOTE,
ContextMenu.SHOW_MODS,
ContextMenu.SHOW_DETAILS,
ContextMenu.REFRESH_PLAYERS,
],
RowType.SAVED_SERVERS: [
ContextMenu.REMOVE_SERVER,
ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD,
ContextMenu.ADD_NOTE,
ContextMenu.SHOW_MODS,
ContextMenu.SHOW_DETAILS,
ContextMenu.REFRESH_PLAYERS,
],
RowType.RECENT_SERVERS: [
ContextMenu.ADD_SERVER,
ContextMenu.REMOVE_HISTORY,
ContextMenu.COPY_NAME,
ContextMenu.ADD_NOTE,
ContextMenu.COPY_CLIPBOARD,
ContextMenu.SHOW_MODS,
ContextMenu.SHOW_DETAILS,
ContextMenu.REFRESH_PLAYERS,
],
}
# TODO: how to get current server context # TODO: dynamic menu entries
items = server_context_items[self.subpage] #for row in items:
# if row == ContextMenu.ADD_SERVER:
for row in items: # if self.is_in_favs():
if row == ContextMenu.ADD_SERVER: # row = ContextMenu.REMOVE_SERVER
if self.is_in_favs(): # item = Gtk.MenuItem(label=row.dict["label"])
row = ContextMenu.REMOVE_SERVER # item.type = row
item = Gtk.MenuItem(label=row.dict["label"]) # item.action = row.dict["action"]
item.type = row # self.menu.append(item)
item.action = row.dict["action"] # if row == ContextMenu.SHOW_MODS:
item.connect("activate", self._on_menu_click) # if not self.has_mods():
self.menu.append(item) # item.set_sensitive(False)
if row == ContextMenu.SHOW_MODS: # if row == ContextMenu.ADD_NOTE:
if not self.has_mods(): # if self.get_record_string() in notes_cache:
item.set_sensitive(False) # item.set_label(strings.edit_note)
if row == ContextMenu.ADD_NOTE:
if self.get_record_string() in notes_cache:
item.set_label(strings.edit_note)
self.menu.show_all()
if event.type is Gdk.EventType.KEY_PRESS and event.keyval is Gdk.KEY_l: if event.type is Gdk.EventType.KEY_PRESS and event.keyval is Gdk.KEY_l:
if self.is_selection_empty(): if self.is_selection_empty():