mirror of
https://github.com/aclist/dztui.git
synced 2026-08-28 18:57:12 +02:00
feat: update fav server dynamically
This commit is contained in:
parent
502b574085
commit
24125a7492
@ -28,6 +28,7 @@
|
||||
- Boldface breadcrumbs
|
||||
- Bold labels inside frames
|
||||
- Unsticky keys when clicking sidebar
|
||||
- Copy IP copies IP:queryport only instead of IP:gameport:queryport, mimics syntax needed by add by ip method
|
||||
|
||||
## Fixed
|
||||
- Longstanding issue with left clicks not registering as tree selection changes after spamming keyboard input
|
||||
|
||||
@ -389,6 +389,8 @@ def ping(iteration: int, row: list) -> Ping:
|
||||
|
||||
|
||||
def query_api(key: str, appid: int, param: str) -> Res:
|
||||
import time
|
||||
|
||||
LIMIT = 10000
|
||||
payload: dict[str, Union[int, str]] = {
|
||||
"filter": r"\appid" + rf"\{appid}" + param,
|
||||
|
||||
@ -209,20 +209,20 @@ class RowType(EnumWithAttrs):
|
||||
|
||||
# TODO: rename to ContextItem
|
||||
class ContextMenu(EnumWithAttrs):
|
||||
ADD_SERVER = {"label": strings.add}
|
||||
ADD_FAV = {"label": strings.add_fav}
|
||||
REMOVE_SERVER = {"label": strings.remove}
|
||||
COPY_NAME = {"label": strings.copy_name}
|
||||
COPY_CLIPBOARD = {"label": strings.copy_ip}
|
||||
ADD_NOTE = {"label": strings.add_note}
|
||||
SHOW_MODS = {"label": strings.show_mods}
|
||||
SHOW_DETAILS = {"label": strings.show_details}
|
||||
ADD_SERVER = {"label": strings.add}
|
||||
CONNECT = {"label": strings.connect}
|
||||
COPY_CLIPBOARD = {"label": strings.copy_ip}
|
||||
COPY_LOG_CLIPBOARD = {"label": strings.copy_log}
|
||||
COPY_NAME = {"label": strings.copy_name}
|
||||
DELETE_MOD = {"label": strings.delete_mod}
|
||||
OPEN_WORKSHOP = {"label": strings.open_workshop}
|
||||
REFRESH_PLAYERS = {"label": strings.refresh_players}
|
||||
REMOVE_HISTORY = {"label": strings.remove_history}
|
||||
OPEN_WORKSHOP = {"label": strings.open_workshop}
|
||||
DELETE_MOD = {"label": strings.delete_mod}
|
||||
COPY_LOG_CLIPBOARD = {"label": strings.copy_log}
|
||||
CONNECT = {"label": strings.connect}
|
||||
REMOVE_SERVER = {"label": strings.remove}
|
||||
SET_FAV = {"label": strings.add_fav}
|
||||
SHOW_DETAILS = {"label": strings.show_details}
|
||||
SHOW_MODS = {"label": strings.show_mods}
|
||||
|
||||
|
||||
class ContextMenuGroup(Enum):
|
||||
@ -235,7 +235,7 @@ class ContextMenuGroup(Enum):
|
||||
SERVER_BROWSER = (
|
||||
ContextMenu.CONNECT,
|
||||
ContextMenu.ADD_SERVER,
|
||||
ContextMenu.ADD_FAV,
|
||||
ContextMenu.SET_FAV,
|
||||
ContextMenu.COPY_NAME,
|
||||
ContextMenu.COPY_CLIPBOARD,
|
||||
ContextMenu.ADD_NOTE,
|
||||
@ -245,7 +245,7 @@ class ContextMenuGroup(Enum):
|
||||
)
|
||||
SCAN_LAN = (
|
||||
ContextMenu.CONNECT,
|
||||
ContextMenu.ADD_FAV,
|
||||
ContextMenu.SET_FAV,
|
||||
ContextMenu.COPY_NAME,
|
||||
ContextMenu.COPY_CLIPBOARD,
|
||||
ContextMenu.ADD_NOTE,
|
||||
@ -255,7 +255,7 @@ class ContextMenuGroup(Enum):
|
||||
)
|
||||
SAVED = (
|
||||
ContextMenu.CONNECT,
|
||||
ContextMenu.ADD_FAV,
|
||||
ContextMenu.SET_FAV,
|
||||
ContextMenu.REMOVE_SERVER,
|
||||
ContextMenu.COPY_NAME,
|
||||
ContextMenu.COPY_CLIPBOARD,
|
||||
@ -267,7 +267,7 @@ class ContextMenuGroup(Enum):
|
||||
RECENT = (
|
||||
ContextMenu.CONNECT,
|
||||
ContextMenu.ADD_SERVER,
|
||||
ContextMenu.ADD_FAV,
|
||||
ContextMenu.SET_FAV,
|
||||
ContextMenu.REMOVE_HISTORY,
|
||||
ContextMenu.COPY_NAME,
|
||||
ContextMenu.COPY_CLIPBOARD,
|
||||
|
||||
@ -41,6 +41,10 @@ class Emitter(GObject.GObject):
|
||||
"""User invoked right movement keybinding from ServerTreeView"""
|
||||
pass
|
||||
|
||||
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(str, str))
|
||||
def fav_server_changed(self, name: str, addr: str) -> None:
|
||||
"""Change favorite server via context menu"""
|
||||
|
||||
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(int,))
|
||||
def check_button_pressed(self, keyval: int) -> None:
|
||||
"""User toggled filter panel check button via keyboard"""
|
||||
|
||||
@ -359,7 +359,8 @@ class Controller(GObject.GObject):
|
||||
# TODO: reload using refresh button, rather than on demand?
|
||||
self.load_mods()
|
||||
|
||||
self.mediator.notebook.set_page_by_enum(button.opens)
|
||||
self.open_page(button.opens)
|
||||
#self.mediator.notebook.set_page_by_enum(button.opens)
|
||||
|
||||
def dump_api(self) -> None:
|
||||
self.first_iteration = True
|
||||
@ -443,23 +444,22 @@ class Controller(GObject.GObject):
|
||||
self.clipboard.set_text(text, -1)
|
||||
|
||||
def open_mod_page(self, path: Gtk.TreePath) -> None:
|
||||
mod, it = self.get_mod_from_tree_path(path)
|
||||
mod, it = self.model_man.get_mod_from_tree_path(path)
|
||||
cmd = self.query_config(Preferences.CLIENT)
|
||||
open_workshop_page(mod, cmd)
|
||||
|
||||
# TODO: put in model manager (dedicated manager for mod store)
|
||||
def get_mod_from_tree_path(
|
||||
self, tree_path: Gtk.TreePath
|
||||
) -> tuple[str, Gtk.TreeIter]:
|
||||
model = self.model_man.get_mod_store()
|
||||
tree_iter = model.get_iter(tree_path)
|
||||
mod = model.get(tree_iter, 2)[0]
|
||||
return mod, tree_iter
|
||||
#def get_mod_from_tree_path(
|
||||
# self, tree_path: Gtk.TreePath
|
||||
#) -> tuple[str, Gtk.TreeIter]:
|
||||
# model = self.model_man.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(self, tree_path: Gtk.TreePath) -> None:
|
||||
config = self.prefs.paths.config
|
||||
|
||||
mod, it = self.get_mod_from_tree_path(tree_path)
|
||||
mod, it = self.model_man.get_mod_from_tree_path(tree_path)
|
||||
|
||||
path = lookup(config, Preferences.DEFAULT)
|
||||
steam_path = Path(path)
|
||||
@ -502,8 +502,6 @@ class Controller(GObject.GObject):
|
||||
# TODO: unimplemented
|
||||
case ContextMenu.ADD_SERVER:
|
||||
pass
|
||||
case ContextMenu.ADD_FAV:
|
||||
pass
|
||||
case ContextMenu.ADD_NOTE:
|
||||
pass
|
||||
case ContextMenu.COPY_CLIPBOARD:
|
||||
@ -516,6 +514,17 @@ class Controller(GObject.GObject):
|
||||
pass
|
||||
case ContextMenu.REMOVE_SERVER:
|
||||
pass
|
||||
case ContextMenu.SET_FAV:
|
||||
treeview = self.get_active_treeview()
|
||||
name = treeview.get_value_at_index(0)
|
||||
record = treeview.get_record_string()
|
||||
|
||||
self.update_config(Preferences.FAV_LBL, name)
|
||||
self.update_config(Preferences.FAV_SRV, record)
|
||||
# TODO: consider a failure dialog here
|
||||
|
||||
simple_ip = treeview.get_simplified_ip()
|
||||
self.emitter.emit("fav_server_changed", name, simple_ip)
|
||||
case ContextMenu.SHOW_DETAILS:
|
||||
pass
|
||||
case ContextMenu.SHOW_MODS:
|
||||
@ -611,6 +620,8 @@ class Controller(GObject.GObject):
|
||||
)
|
||||
self.push_data(data, FilterMode.INITIAL, success=True)
|
||||
|
||||
# TODO: eg cleanup on failure, cleanup on sucess
|
||||
# separate methods
|
||||
def cleanup(self) -> None:
|
||||
treeview = self.get_active_treeview()
|
||||
|
||||
@ -759,7 +770,7 @@ class Controller(GObject.GObject):
|
||||
return self.mediator.statusbar
|
||||
|
||||
@call_on_thread
|
||||
def thread_data_func(self, func: Callable) -> None:
|
||||
def run_query_func(self, func: Callable) -> None:
|
||||
func()
|
||||
|
||||
@call_on_thread
|
||||
@ -789,12 +800,11 @@ class Controller(GObject.GObject):
|
||||
if func is None:
|
||||
self.emitter.emit("servers_loaded", treeview.get_enum())
|
||||
return
|
||||
# TODO: on legacy version, model clearing happens in thread
|
||||
# (compare)
|
||||
# TODO:
|
||||
# manager = treeview.get_filter_man()
|
||||
# manager.clear_model()
|
||||
self.set_callback(None, None)
|
||||
self.thread_data_func(func)
|
||||
self.run_query_func(func)
|
||||
|
||||
def get_favorite(self) -> tuple[str, str] | tuple[None, None]:
|
||||
fav = str(self.query_config(Preferences.FAV_LBL))
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
- Boldface breadcrumbs
|
||||
- Bold labels inside frames
|
||||
- Unsticky keys when clicking sidebar
|
||||
- Copy IP copies IP:queryport only instead of IP:gameport:queryport, mimics syntax needed by add by ip method
|
||||
|
||||
## Fixed
|
||||
- Longstanding issue with left clicks not registering as tree selection changes after spamming keyboard input
|
||||
|
||||
@ -2,9 +2,11 @@ from dataclasses import dataclass
|
||||
from dzgui.const.enum import HELP_MENU_ROWS
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository.Gtk import ListStore # noqa E402
|
||||
from gi.repository import GObject, GLib # noqa E402
|
||||
from gi.repository import GLib, GObject, Gtk # noqa E402
|
||||
|
||||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class ModCols:
|
||||
@ -40,6 +42,7 @@ class ModelManager:
|
||||
"""
|
||||
Manager for miscellaneous ListStores
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
self.map_store = ListStore(str)
|
||||
@ -77,3 +80,11 @@ class ModelManager:
|
||||
|
||||
def append_map(self, row: list) -> None:
|
||||
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
|
||||
|
||||
@ -268,6 +268,7 @@ class Crumbs:
|
||||
servers: str
|
||||
thanks: str
|
||||
developers: str
|
||||
default: str
|
||||
|
||||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
@ -453,6 +454,7 @@ crumbs = Crumbs(
|
||||
servers="Servers > Server browser",
|
||||
thanks="Help > Special thanks",
|
||||
developers="Options > Developers",
|
||||
default="Servers > ",
|
||||
)
|
||||
|
||||
checkmark = "✓"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from typing import Literal, Self, TYPE_CHECKING
|
||||
from typing import Callable, Literal, Self, TYPE_CHECKING
|
||||
|
||||
from dzgui.util.strings import atomic_buttons, connect_panel
|
||||
from dzgui.const.constants import (
|
||||
@ -11,6 +11,7 @@ from dzgui.const.constants import (
|
||||
)
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, GLib # noqa E402
|
||||
|
||||
@ -21,7 +22,8 @@ if TYPE_CHECKING:
|
||||
|
||||
class Icon(Gtk.Image):
|
||||
def __init__(self, name: str, l_margin: int = 0) -> None:
|
||||
super().__init__(icon_name=name,
|
||||
super().__init__(
|
||||
icon_name=name,
|
||||
icon_size=Gtk.IconSize.BUTTON,
|
||||
margin_start=l_margin,
|
||||
ypad=2,
|
||||
@ -30,9 +32,8 @@ class Icon(Gtk.Image):
|
||||
|
||||
class LargeIcon(Gtk.Image):
|
||||
def __init__(self, name: str, l_margin: int = 5) -> None:
|
||||
super().__init__(icon_name=name,
|
||||
icon_size=Gtk.IconSize.LARGE_TOOLBAR,
|
||||
margin_start=l_margin
|
||||
super().__init__(
|
||||
icon_name=name, icon_size=Gtk.IconSize.LARGE_TOOLBAR, margin_start=l_margin
|
||||
)
|
||||
|
||||
|
||||
@ -59,14 +60,15 @@ class LargeIconTextButton(IconButton):
|
||||
|
||||
|
||||
class ClipboardButton(IconTextButton):
|
||||
def __init__(self, controller: "Controller", data: str) -> None:
|
||||
def __init__(self, controller: "Controller", func: Callable) -> None:
|
||||
super().__init__(CLIPBOARD, atomic_buttons.copy)
|
||||
self.controller = controller
|
||||
self.connect("clicked", self._on_button_clicked, data)
|
||||
self.connect("clicked", self._on_button_clicked, func)
|
||||
|
||||
self.set_tooltip_text("Copy IP to clipboard")
|
||||
|
||||
def _on_button_clicked(self, button: Self, data: str) -> None:
|
||||
def _on_button_clicked(self, button: Self, func: Callable) -> None:
|
||||
data = func()
|
||||
self.controller.copy_clipboard(data)
|
||||
|
||||
|
||||
|
||||
@ -73,12 +73,14 @@ class FavPanel(Gtk.Frame):
|
||||
self.set_label_widget(label)
|
||||
|
||||
self.controller = controller
|
||||
emitter = self.controller.get_emitter()
|
||||
emitter.connect("fav_server_changed", self._on_fav_server_changed)
|
||||
|
||||
# TODO: improve upon this, cache fav ip when changed globally
|
||||
user_fav, self.fav_ip = self.controller.get_favorite()
|
||||
self.server_name, self.server_ip = self.controller.get_favorite()
|
||||
server_name = (
|
||||
f"{user_fav} ({self.fav_ip})"
|
||||
if user_fav is not None
|
||||
f"{self.server_name} ({self.server_ip})"
|
||||
if self.server_name is not None
|
||||
else connect_panel.no_fav
|
||||
)
|
||||
self.fav_label = Gtk.Label(
|
||||
@ -94,9 +96,8 @@ class FavPanel(Gtk.Frame):
|
||||
self.fav_button = SteamConnectButton()
|
||||
if server_name is None:
|
||||
self.fav_button.set_sensitive(False)
|
||||
copy = ClipboardButton(self.controller, self.get_fav_ip())
|
||||
copy = ClipboardButton(self.controller, self.get_fav_ip)
|
||||
|
||||
# FIXME: height of connect buttons is not equivalent
|
||||
grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
|
||||
grid.attach(scrollable_label, 0, 0, 3, ROWS)
|
||||
grid.attach_next_to(copy, scrollable_label, Gtk.PositionType.RIGHT, COLS, ROWS)
|
||||
@ -105,11 +106,16 @@ class FavPanel(Gtk.Frame):
|
||||
self.add(grid)
|
||||
|
||||
def get_fav_ip(self) -> str:
|
||||
return self.fav_ip
|
||||
return self.server_ip
|
||||
|
||||
def set_fav_label(self, text: str) -> None:
|
||||
# TODO: called by controller when changing fav
|
||||
self.fav_label.set_text(text)
|
||||
from dzgui.api.servers import Record
|
||||
|
||||
def _on_fav_server_changed(
|
||||
self, emitter: "Emitter", name: str, record: str
|
||||
) -> None:
|
||||
self.server_name = name
|
||||
self.server_ip = record
|
||||
self.fav_label.set_text(f"{name} ({record})")
|
||||
|
||||
|
||||
class AddPanel(Gtk.Frame):
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from dzgui.const.enum import NotebookPage
|
||||
from dzgui.util.strings import label_main_menu
|
||||
from dzgui.util.strings import label_main_menu, crumbs
|
||||
from dzgui.util.format import embolden
|
||||
|
||||
import gi
|
||||
@ -43,9 +43,8 @@ class Breadcrumbs(Gtk.Label):
|
||||
crumbs = enum.dict["crumbs"]
|
||||
self.set_crumbs(crumbs)
|
||||
|
||||
def set_server_crumbs(self, crumbs: str) -> None:
|
||||
# TODO: strings
|
||||
self.set_crumbs("Servers > " + crumbs)
|
||||
def set_server_crumbs(self, suffix: str) -> None:
|
||||
self.set_crumbs(crumbs.default + suffix)
|
||||
|
||||
def set_crumbs(self, crumbs: str) -> None:
|
||||
text = embolden(crumbs)
|
||||
|
||||
@ -149,7 +149,8 @@ class FilterPanel(Gtk.Box):
|
||||
filters.append(k)
|
||||
return tuple(filters)
|
||||
|
||||
# TODO: currently unused
|
||||
# TODO: should be used when switching ServerTab contexts
|
||||
# use signals here
|
||||
# def reinit_panel(self) -> None:
|
||||
# self.keyword_entry.set_text("")
|
||||
# self.keyword_filter = ""
|
||||
|
||||
@ -64,6 +64,8 @@ class ModSelectionPanel(Gtk.Box):
|
||||
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)
|
||||
|
||||
@ -77,6 +79,7 @@ class ModSelectionPanel(Gtk.Box):
|
||||
def _on_button_clicked(self, button: EnumeratedModButton) -> None:
|
||||
match button.enum:
|
||||
case ModButton.SELECT_ALL:
|
||||
# TODO: signals
|
||||
self.controller.toggle_mod_selection(True)
|
||||
case ModButton.UNSELECT_ALL:
|
||||
self.controller.toggle_mod_selection(False)
|
||||
|
||||
@ -75,6 +75,7 @@ class ConfirmationDialog(GenericDialog):
|
||||
secondary=secondary,
|
||||
)
|
||||
|
||||
|
||||
class IgnoreDialog(GenericDialog):
|
||||
def __init__(self, controller: "Controller", secondary: str):
|
||||
super().__init__(
|
||||
@ -88,7 +89,6 @@ class IgnoreDialog(GenericDialog):
|
||||
cancel.set_label("Ignore")
|
||||
|
||||
|
||||
|
||||
class NotifyDialog(GenericDialog):
|
||||
def __init__(self, controller: "Controller", secondary: str):
|
||||
super().__init__(
|
||||
@ -169,6 +169,7 @@ class ExceptionDialog(GenericDialog):
|
||||
secondary=strings.something_wrong,
|
||||
)
|
||||
|
||||
self.trace = trace
|
||||
# NOTE: box expands to end of content area
|
||||
scrollable = Gtk.ScrolledWindow(
|
||||
propagate_natural_height=True, max_content_height=500
|
||||
@ -177,7 +178,7 @@ class ExceptionDialog(GenericDialog):
|
||||
textview = Gtk.TextView(
|
||||
wrap_mode=Gtk.WrapMode.WORD, editable=False, left_margin=10, right_margin=10
|
||||
)
|
||||
textview.set_buffer(Gtk.TextBuffer(text=trace))
|
||||
textview.set_buffer(Gtk.TextBuffer(text=self.trace))
|
||||
box.pack_start(textview, EXPAND, FILL, 10)
|
||||
scrollable.add(box)
|
||||
|
||||
@ -186,7 +187,7 @@ class ExceptionDialog(GenericDialog):
|
||||
# FIXME: padding around top of content area when traceback is long
|
||||
content.add(scrollable)
|
||||
|
||||
copy_button = ClipboardButton(controller, trace)
|
||||
copy_button = ClipboardButton(controller, self.get_trace)
|
||||
self.add_action_widget(copy_button, Gtk.ResponseType.NONE)
|
||||
self.add_button("OK", Gtk.ResponseType.OK)
|
||||
|
||||
@ -194,6 +195,9 @@ class ExceptionDialog(GenericDialog):
|
||||
self.action_area.get_children()[1].grab_focus()
|
||||
self.connect("response", self._on_response)
|
||||
|
||||
def get_trace(self) -> str:
|
||||
return self.trace
|
||||
|
||||
def _on_response(
|
||||
self, dialog: Self, response: Gtk.ResponseType
|
||||
) -> None | Literal[True]:
|
||||
|
||||
@ -1,153 +0,0 @@
|
||||
from typing import Self
|
||||
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
|
||||
|
||||
from dzgui.const.constants import NO_EXPAND, NO_FILL, NO_PADDING
|
||||
from dzgui.util.import strings
|
||||
|
||||
class LanDialog(Gtk.MessageDialog):
|
||||
"""
|
||||
Performs integer validation on the provided port
|
||||
and blocks if out of range. Returns None if user cancels
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
super().__init__(
|
||||
transient_for=AppNav.window, #FIXME
|
||||
flags=0,
|
||||
message_type=Gtk.MessageType.INFO,
|
||||
buttons=Gtk.ButtonsType.OK_CANCEL,
|
||||
text=strings.scan_servers,
|
||||
secondary_text=strings.select_port,
|
||||
title=strings.dialog_header,
|
||||
modal=True,
|
||||
)
|
||||
|
||||
self.set_size_request(500, 0)
|
||||
self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
|
||||
|
||||
buttons = [
|
||||
(strings.default_port, Port.DEFAULT),
|
||||
(strings.custom_port, Port.CUSTOM),
|
||||
]
|
||||
|
||||
self.button_box = Gtk.Box()
|
||||
self.button_box.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.button_box.active_button = None
|
||||
|
||||
for k, v in buttons:
|
||||
button = Gtk.RadioButton(label=k)
|
||||
button.port = v
|
||||
button.connect("toggled", self._on_button_toggled)
|
||||
self.button_box.add(button)
|
||||
if v == Port.DEFAULT:
|
||||
self.button_box.active_button = button
|
||||
else:
|
||||
button.join_group(self.button_box.active_button)
|
||||
|
||||
self.entry = Gtk.Entry()
|
||||
self.button_box.add(self.entry)
|
||||
self.entry.set_no_show_all(True)
|
||||
|
||||
# TODO: strings
|
||||
self.warn_label = Gtk.Label(label="Invalid port")
|
||||
self.warn_label.set_no_show_all(True)
|
||||
self.button_box.add(self.warn_label)
|
||||
|
||||
content = self.get_content_area()
|
||||
content.pack_start(self.button_box, NO_EXPAND, NO_FILL, NO_PADDING)
|
||||
content.set_margin_start(30)
|
||||
content.set_margin_end(30)
|
||||
content.show_all()
|
||||
|
||||
self.action_area.set_layout(Gtk.ButtonBoxStyle.CENTER)
|
||||
self.action_area.set_margin_bottom(20)
|
||||
|
||||
self.port = None
|
||||
self.ok = self.action_area.get_children()[1]
|
||||
|
||||
self.connect("response", self._on_dialog_response)
|
||||
self.connect("key-press-event", self._on_keypress)
|
||||
self.connect("delete-event", self.restore_context)
|
||||
|
||||
self.entry.connect("insert-text", self._on_text_typed)
|
||||
self.entry.get_property("buffer").connect(
|
||||
"deleted-text", self._on_text_deleted
|
||||
)
|
||||
|
||||
def _validate(self, text: str) -> None:
|
||||
state = ip.is_valid_port(text)
|
||||
self.ok.set_sensitive(not state)
|
||||
self.warn_label.set_visible(state)
|
||||
|
||||
# TODO: can put in validation method
|
||||
if len(text) == 0:
|
||||
self.warn_label.set_visible(False)
|
||||
|
||||
def _on_text_deleted(
|
||||
self, buffer: Gtk.EntryBuffer, position: int, chars: int
|
||||
) -> None:
|
||||
text = buffer.get_text()
|
||||
self._validate(text)
|
||||
|
||||
def _on_text_typed(
|
||||
self, entry: Gtk.Entry, text: str, length: int, pos: int) -> None:
|
||||
self._validate(entry.get_text() + text)
|
||||
|
||||
def restore_context(self, *args: Any) -> None:
|
||||
context = WindowContext.MAIN_MENU
|
||||
AppNav.treeview.set_view(context)
|
||||
|
||||
def _on_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None:
|
||||
if event.keyval == Gdk.KEY_Return:
|
||||
if self.ok.is_sensitive():
|
||||
self.response(Gtk.ResponseType.OK)
|
||||
if self.button_box.get_children()[0].is_focus():
|
||||
self.response(Gtk.ResponseType.OK)
|
||||
else:
|
||||
self.restore_context()
|
||||
|
||||
if event.keyval == Gdk.KEY_Up:
|
||||
self.ok.set_sensitive(True)
|
||||
self.entry.set_text("")
|
||||
self.button_box.get_children()[0].grab_focus()
|
||||
|
||||
def _on_dialog_response(
|
||||
self, dialog: Self, response: Gtk.ResponseType
|
||||
) -> None:
|
||||
cancel_events = [
|
||||
Gtk.ResponseType.CLOSE,
|
||||
Gtk.ResponseType.CANCEL,
|
||||
Gtk.ResponseType.DELETE_EVENT,
|
||||
]
|
||||
|
||||
if response in cancel_events:
|
||||
self.restore_context()
|
||||
return
|
||||
|
||||
string = self.entry.get_text()
|
||||
port = self.button_box.active_button.port
|
||||
|
||||
match port:
|
||||
case Port.DEFAULT:
|
||||
self.port = UDP_PORT
|
||||
case Port.CUSTOM:
|
||||
if ip.is_valid_port(string):
|
||||
self.stop_emission_by_name("response")
|
||||
else:
|
||||
self.port = int(string)
|
||||
|
||||
def get_selected_port(self) -> int:
|
||||
return self.port
|
||||
|
||||
def _on_button_toggled(self, button: Gtk.Button) -> None:
|
||||
if button.get_active():
|
||||
self.button_box.active_button = button
|
||||
match button.port:
|
||||
case Port.DEFAULT:
|
||||
self.entry.set_visible(False)
|
||||
case Port.CUSTOM:
|
||||
self.entry.set_visible(True)
|
||||
self.entry.grab_focus()
|
||||
self.ok.set_sensitive(False)
|
||||
@ -18,7 +18,8 @@ class ContextMixin(TreeView):
|
||||
widget: Gtk.Widget,
|
||||
event: Gdk.EventButton | Gdk.EventKey,
|
||||
) -> None:
|
||||
|
||||
# FIXME: double click causes issue
|
||||
# split into present by click and present by key
|
||||
if self.is_selection_empty():
|
||||
return False
|
||||
|
||||
|
||||
@ -61,7 +61,6 @@ class ServerNotebook(Gtk.ScrolledWindow):
|
||||
self.emitter.emit("server_page_toggled", True)
|
||||
# FIXME: only applies to server notebook, not atomic page
|
||||
# this can be delegated to the map/unmap signal of the ServerTreeView itself
|
||||
# print("page changed, starting queue checker")
|
||||
# self.get_active_treeview().start_timeout()
|
||||
|
||||
def _on_unmap(self, widget: Self) -> None:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import logging
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from warnings import deprecated
|
||||
|
||||
from dzgui.const.constants import SEPARATOR
|
||||
from dzgui.util.keys import is_navkey
|
||||
@ -39,8 +40,6 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
|
||||
self.selected_row.connect("changed", self._on_tree_selection_changed)
|
||||
self.connect("row-activated", self._on_row_activated)
|
||||
|
||||
self.connect("button-press-event", lambda x, y: print(self.sel_blocked))
|
||||
|
||||
self.connect("key-press-event", self._on_keypress)
|
||||
self.connect("key-release-event", self._on_key_release)
|
||||
|
||||
@ -56,12 +55,12 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
def _separate(self, model: Gtk.ListStore, iter_: Gtk.TreeIter) -> bool:
|
||||
if model[iter_][0] == SEPARATOR:
|
||||
def _separate(self, model: Gtk.ListStore, _iter: Gtk.TreeIter) -> bool:
|
||||
if model[_iter][0] == SEPARATOR:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_current_iter(self) -> Gtk.TreeIter | None:
|
||||
def get_current_iter(self) -> Optional[Gtk.TreeIter]:
|
||||
it = self.get_selection().get_selected()[1]
|
||||
return it
|
||||
|
||||
@ -82,7 +81,6 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
|
||||
return [model[row] for row in rows]
|
||||
|
||||
def _on_keypress(self, treeview: Gtk.TreeView, event: Gdk.EventKey) -> None:
|
||||
|
||||
if is_navkey(event.keyval):
|
||||
if self.get_model() is None:
|
||||
return
|
||||
@ -98,9 +96,9 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
|
||||
return
|
||||
|
||||
def _on_key_release(self, treeview: Gtk.TreeView, event: Gdk.EventKey) -> None:
|
||||
# TODO: explain this better
|
||||
"""
|
||||
Suppresses spamming on keydown
|
||||
TODO: explain this better
|
||||
"""
|
||||
# TODO: multisel
|
||||
# if event.keyval is Gdk.KEY_space:
|
||||
@ -139,9 +137,7 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
|
||||
self.set_cursor(0)
|
||||
|
||||
def get_value_at_index(self, index: int) -> str:
|
||||
select = self.get_selection()
|
||||
sels = select.get_selected_rows()
|
||||
(model, pathlist) = sels
|
||||
(model, pathlist) = self.get_model_and_pathlist()
|
||||
if len(pathlist) < 1:
|
||||
return ""
|
||||
path = pathlist[0]
|
||||
@ -157,16 +153,20 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
|
||||
sel = self.get_selection()
|
||||
self._on_tree_selection_changed(sel)
|
||||
|
||||
def get_mpath(self) -> Gtk.TreePath | None:
|
||||
def get_model_and_pathlist(self) -> tuple:
|
||||
select = self.get_selection()
|
||||
sels = select.get_selected_rows()
|
||||
(model, pathlist) = sels
|
||||
return (model, pathlist)
|
||||
|
||||
@deprecated("Currently unused")
|
||||
def get_mpath(self) -> Optional[Gtk.TreePath]:
|
||||
(model, pathlist) = self.get_model_and_pathlist()
|
||||
if len(pathlist) < 1:
|
||||
return None
|
||||
path = pathlist[0]
|
||||
return path
|
||||
|
||||
# @signal_emission
|
||||
def _on_row_activated(
|
||||
self,
|
||||
treeview: Gtk.TreeView,
|
||||
@ -176,15 +176,12 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
|
||||
self.emit("generic_row_activated", path, col)
|
||||
|
||||
def is_selection_empty(self) -> bool:
|
||||
# TODO: reduce duplicated methods
|
||||
sel = self.get_selection()
|
||||
sels = sel.get_selected_rows()
|
||||
(model, pathlist) = sels
|
||||
(model, pathlist) = self.get_model_and_pathlist()
|
||||
if len(pathlist) < 1:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_selected_row(self) -> Gtk.TreeModelRow | None:
|
||||
def get_selected_row(self) -> Optional[Gtk.TreeModelRow]:
|
||||
ind = self.get_selected_row_index()
|
||||
model = self.get_model()
|
||||
if model is None:
|
||||
|
||||
@ -307,13 +307,19 @@ class ServerTreeView(ContextMixin, TreeView):
|
||||
return
|
||||
self.start_distcalc()
|
||||
|
||||
def get_simplified_ip(self) -> str:
|
||||
addr = self.get_value_at_index(7)
|
||||
qport = self.get_value_at_index(8)
|
||||
ip = addr.split(":")[0]
|
||||
return f"{ip}:{qport}"
|
||||
|
||||
def get_record_string(self) -> str:
|
||||
addr = self.get_value_at_index(7)
|
||||
qport = self.get_value_at_index(8)
|
||||
return f"{addr}:{qport}"
|
||||
|
||||
def get_record(self) -> Record | None:
|
||||
# TODO: delegate to controller
|
||||
# TODO: use tree_base.get_selected_row()
|
||||
select = self.get_selection()
|
||||
sels = select.get_selected_rows()
|
||||
(model, pathlist) = sels
|
||||
|
||||
Loading…
Reference in New Issue
Block a user