Files
dzgui/dzgui/views/pages/servers.py
T

199 lines
6.5 KiB
Python

import logging
from typing import Self, TYPE_CHECKING
from dzgui.const.constants import APP_NAME
from dzgui.const.enum import ContextMenuGroup, ServerTab
from dzgui.views.trees.tree_servers import ServerTreeView
from dzgui.util.strings import server_labels
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib # noqa E402
logger = logging.getLogger(APP_NAME)
if TYPE_CHECKING:
from dzgui.controllers.mc import Controller
from dzgui.controllers.emitter import Emitter
class ScrollableTree(Gtk.ScrolledWindow):
def __init__(self, tree: "ServerTreeView") -> None:
super().__init__(overlay_scrolling=False)
self.tree = tree
self.add(tree)
def get_tree(self) -> "ServerTreeView":
return self.tree
class ServerNotebook(Gtk.ScrolledWindow):
def __init__(self, controller: "Controller"):
super().__init__()
self.controller = controller
self.emitter = self.controller.get_emitter()
self.controller.register_widget("servers", self)
self.notebook = Gtk.Notebook(show_tabs=True)
self.browser = ServerTreeView(
controller, ServerTab.BROWSER, ContextMenuGroup.SERVER_BROWSER
)
self.saved = ServerTreeView(controller, ServerTab.SAVED, ContextMenuGroup.SAVED)
self.recent = ServerTreeView(
controller, ServerTab.RECENT, ContextMenuGroup.RECENT
)
self.lan = ServerTreeView(
controller,
ServerTab.LAN,
ContextMenuGroup.SCAN_LAN,
show_empty=True,
show_full=True,
)
tabs = [
(self.browser, server_labels.browser),
(self.saved, server_labels.saved),
(self.recent, server_labels.recent),
(self.lan, server_labels.lan),
]
for tree, label in tabs:
scrolled = ScrollableTree(tree)
self.notebook.append_page(scrolled, Gtk.Label(label=label))
self.add(self.notebook)
self.notebook.connect_after("switch-page", self._on_page_changed)
self.connect("key-press-event", self._on_keypress)
self.connect("map", self._on_map)
self.connect("unmap", self._on_unmap)
self.emitter.connect("servers_loaded", self._on_servers_loaded)
self.emitter.connect("saved_servers_changed", self._on_saved_servers_changed)
def _on_saved_servers_changed(self, emitter: "Emitter") -> None:
# TODO: can be dropped/consolidated?
saved = 1
cur_page = self.notebook.get_current_page()
if cur_page == saved:
return
page = self.notebook.get_nth_page(saved)
if not page:
return
label = self.notebook.get_tab_label(page)
if label is None:
return
if hasattr(label, "set_text"):
label.set_text(f"{server_labels.saved}*")
def _on_servers_loaded(self, emitter: "Emitter", tab: "ServerTab") -> None:
# NOTE: workaround for GTK bug where fullscreen causes headers to vanish when model is None
# TODO: this should be internal to servers page
tv = self.get_active_treeview()
if tv is None:
return
state = False if tv.get_model() is None else True
tv.set_headers_visible(state)
tv.set_loaded(True)
tv.focus_first_row()
tv.grab_focus()
def _on_map(self, widget: Self) -> None:
self.emitter.emit("server_page_toggled", True)
def _on_unmap(self, widget: Self) -> None:
self.emitter.emit("server_page_toggled", False)
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> bool:
# NOTE: abort if modifier mask is active
if event.state != 0:
return False
match event.keyval:
case Gdk.KEY_n:
self.notebook.next_page()
self.grab_content_area()
return True
case Gdk.KEY_p:
self.notebook.prev_page()
self.grab_content_area()
return True
case _:
return False
def grab_content_area(self) -> None:
tv = self.get_active_treeview()
if tv is not None:
tv.grab_focus()
def get_current_tab_text(self) -> str:
ind = self.notebook.get_current_page()
child = self.notebook.get_nth_page(ind)
if child is None:
return ""
text = self.notebook.get_tab_label_text(child)
if text is None:
return ""
return text
def _on_page_changed(
self, notebook: Gtk.Notebook, child: ScrollableTree, index: int
) -> None:
if self.controller.loaded is False:
return
label = self.notebook.get_tab_label_text(child)
if label is not None:
# TODO: strings
text = label.strip("*")
self.notebook.set_tab_label_text(child, text)
tree = child.get_tree()
self.emitter.emit("server_page_changed", tree)
# NOTE: spawns a thread
tv = self.get_active_treeview()
if tv is not None:
self.controller.populate_model(tv)
def get_active_treeview(self) -> ServerTreeView:
index = self.notebook.get_current_page()
scrollable = self.notebook.get_nth_page(index)
if scrollable is not None and hasattr(scrollable, "get_children"):
tv = scrollable.get_children()[0]
if isinstance(tv, ServerTreeView):
return tv
raise ValueError("No treeview set")
def update_tab_widths(self, col: Gtk.TreeViewColumn) -> None:
# TODO: may cause pixel offsets when application is maximized
width = col.get_width()
title = col.get_title()
for tab in (self.browser, self.saved, self.recent, self.lan):
if tab == self.get_active_treeview():
continue
for col in tab.get_columns():
if col.get_title() == title:
self.controller.suppress_signal(
tab, col, "_on_col_width_changed", True
)
col.set_fixed_width(width)
self.controller.suppress_signal(
tab, col, "_on_col_width_changed", False
)
def get_browser(self) -> ServerTreeView:
return self.browser
def get_saved(self) -> ServerTreeView:
return self.saved
def get_recent(self) -> ServerTreeView:
return self.recent
def get_lan(self) -> ServerTreeView:
return self.lan