mirror of
https://github.com/aclist/dztui.git
synced 2026-11-01 07:32:44 +01:00
feat: reimplement server mod dialog
This commit is contained in:
1 parent
4022b4c6b6
commit
6393265935
8 files changed
+179
-62
No files matched your search
@@ -109,6 +109,7 @@ def get_missing_mods(local: list, remote: list) -> list:
|
|||||||
return [mod for mod in remote if mod not in local]
|
return [mod for mod in remote if mod not in local]
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME: steam path is missing
|
||||||
def get_server_modlist(server: Record, steam: Path) -> list:
|
def get_server_modlist(server: Record, steam: Path) -> list:
|
||||||
try:
|
try:
|
||||||
rules = dayzquery.dayz_rules((server.ip, server.qport))
|
rules = dayzquery.dayz_rules((server.ip, server.qport))
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ def get_prereqs(ip: str, qport: int) -> Prereqs:
|
|||||||
return Prereqs(is_password, gameport, appid, version)
|
return Prereqs(is_password, gameport, appid, version)
|
||||||
|
|
||||||
|
|
||||||
def details(record: Record) -> Details:
|
def get_details(record: Record) -> Details:
|
||||||
ip = record.ip
|
ip = record.ip
|
||||||
qport = record.qport
|
qport = record.qport
|
||||||
default_str = strings.none_provided
|
default_str = strings.none_provided
|
||||||
@@ -448,9 +448,11 @@ def validate_ip(addr: str) -> Record:
|
|||||||
return record
|
return record
|
||||||
|
|
||||||
|
|
||||||
def get_rules(ip: str, qport: int) -> list[int]:
|
def get_rules(record: Record) -> list[int]:
|
||||||
|
ip = record.ip
|
||||||
|
qport = record.qport
|
||||||
try:
|
try:
|
||||||
mods = dayzquery.dayz_rules((ip, int(qport))).mods
|
mods = dayzquery.dayz_rules((ip, qport)).mods
|
||||||
return [mod for mod in mods]
|
return [mod for mod in mods]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.critical(e)
|
logger.critical(e)
|
||||||
|
|||||||
@@ -615,3 +615,6 @@ class Controller(GObject.GObject):
|
|||||||
|
|
||||||
def get_details(self, record: "Record") -> None:
|
def get_details(self, record: "Record") -> None:
|
||||||
ConnectionManager(self).query_details(record)
|
ConnectionManager(self).query_details(record)
|
||||||
|
|
||||||
|
def get_modlist(self, record: "Record") -> None:
|
||||||
|
ConnectionManager(self).query_modlist(record)
|
||||||
@@ -4,7 +4,7 @@ import dzgui.api.servers as Servers
|
|||||||
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 api_warn_msg, dialog, server_timeout
|
from dzgui.util.strings import api_warn_msg, dialog, server_timeout
|
||||||
from dzgui.views.dialogs.generic import ExceptionDialog
|
from dzgui.views.dialogs.generic import ExceptionDialog
|
||||||
from dzgui.views.dialogs.server_details import ServerDetailsDialog
|
from dzgui.views.dialogs.servers import ServerDetailsDialog, ServerModDialog
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ class ConnectionManager:
|
|||||||
|
|
||||||
@call_on_thread(dialog.querying)
|
@call_on_thread(dialog.querying)
|
||||||
def query_details(self, record: Servers.Record) -> None:
|
def query_details(self, record: Servers.Record) -> None:
|
||||||
details = Servers.details(record)
|
details = Servers.get_details(record)
|
||||||
if details.success is False:
|
if details.success is False:
|
||||||
self.thread_man.set_cleanup_func(
|
self.thread_man.set_cleanup_func(
|
||||||
StoredFunc(self._server_timeout), destroy_first=True
|
StoredFunc(self._server_timeout), destroy_first=True
|
||||||
@@ -67,6 +67,31 @@ class ConnectionManager:
|
|||||||
StoredFunc(self._present_details_dialog, details), destroy_first=True
|
StoredFunc(self._present_details_dialog, details), destroy_first=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@call_on_thread(dialog.querying)
|
||||||
|
def query_modlist(self, record: Servers.Record) -> None:
|
||||||
|
mods = Servers.get_rules(record)
|
||||||
|
# TODO: test if locally installed
|
||||||
|
# see api.mods for this same logic
|
||||||
|
# call controller to look up steam path from ConfigManager
|
||||||
|
if len(mods) == 0:
|
||||||
|
# TODO: message for no mods
|
||||||
|
# TODO: message for actual timeout
|
||||||
|
self.thread_man.set_cleanup_func(
|
||||||
|
StoredFunc(self._server_timeout), destroy_first=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
alpha_mods = [[mod.name, str(mod.workshop_id), "Test"] for mod in mods]
|
||||||
|
alpha_mods.sort(key=lambda x: x[0])
|
||||||
|
|
||||||
|
self.thread_man.set_cleanup_func(
|
||||||
|
StoredFunc(self._present_modlist_dialog, alpha_mods), destroy_first=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: data type is dayzquery.DayzMod
|
||||||
|
def _present_modlist_dialog(self, mods: list[str]) -> None:
|
||||||
|
dialog = ServerModDialog(self.controller, mods)
|
||||||
|
dialog.run()
|
||||||
|
|
||||||
def _present_details_dialog(self, details: Servers.Details) -> None:
|
def _present_details_dialog(self, details: Servers.Details) -> None:
|
||||||
dialog = ServerDetailsDialog(self.controller, details)
|
dialog = ServerDetailsDialog(self.controller, details)
|
||||||
dialog.run()
|
dialog.run()
|
||||||
@@ -74,8 +99,3 @@ class ConnectionManager:
|
|||||||
def _server_timeout(self) -> None:
|
def _server_timeout(self) -> None:
|
||||||
dialog = ExceptionDialog(self.controller, server_timeout)
|
dialog = ExceptionDialog(self.controller, server_timeout)
|
||||||
dialog.run()
|
dialog.run()
|
||||||
|
|
||||||
# def _connection_failure(self) -> None:
|
|
||||||
# # FIXME: returns api warning, but this is more likely a localized server issue
|
|
||||||
# dialog = ExceptionDialog(self.controller, api_warn_msg)
|
|
||||||
# dialog.run()
|
|
||||||
@@ -81,8 +81,8 @@ class ContextMenuManager:
|
|||||||
record = self.treeview.get_record()
|
record = self.treeview.get_record()
|
||||||
self.controller.get_details(record)
|
self.controller.get_details(record)
|
||||||
case ContextMenu.SHOW_MODS:
|
case ContextMenu.SHOW_MODS:
|
||||||
print("DEBUG: unimplemented")
|
record = self.treeview.get_record()
|
||||||
pass
|
self.controller.get_modlist(record)
|
||||||
|
|
||||||
def copy_server_ip(self) -> None:
|
def copy_server_ip(self) -> None:
|
||||||
if not isinstance(self.treeview, ServerTreeView):
|
if not isinstance(self.treeview, ServerTreeView):
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class LogCols:
|
|||||||
@dataclass(slots=True, frozen=True)
|
@dataclass(slots=True, frozen=True)
|
||||||
class ServerModCols:
|
class ServerModCols:
|
||||||
name: str
|
name: str
|
||||||
uid: int # GObject.TYPE_INT64
|
uid: str
|
||||||
installed: str
|
installed: str
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,48 @@
|
|||||||
import gi
|
import gi
|
||||||
|
import textwrap
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from dzgui.const.constants import EXPAND, FILL
|
||||||
|
from dzgui.model.model_factory import ModelFactory
|
||||||
|
from dzgui.util import strings
|
||||||
|
from dzgui.views.dialogs.generic import GenericDialog
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
|
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
|
||||||
|
|
||||||
class ModDialog(GenericDialog):
|
if TYPE_CHECKING:
|
||||||
def __init__(self, record: str):
|
from dzgui.api.servers import Record
|
||||||
|
|
||||||
|
|
||||||
|
class ServerModDialog(GenericDialog):
|
||||||
|
def __init__(self, controller, mods: list[str]):
|
||||||
|
|
||||||
# TODO: center secondary text
|
# TODO: center secondary text
|
||||||
msg = strings.workshop
|
msg = textwrap.dedent(strings.workshop)
|
||||||
super().__init__(textwrap.dedent(msg), Popup.MODLIST)
|
super().__init__(
|
||||||
|
controller=controller,
|
||||||
|
text=msg,
|
||||||
|
buttons="Gtk.ButtonsType.OK",
|
||||||
|
mtype="Gtk.MessageType.INFO",
|
||||||
|
secondary="",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mod_store = ModelFactory().make_server_mod_store()
|
||||||
|
|
||||||
dialogBox = self.get_content_area()
|
dialogBox = self.get_content_area()
|
||||||
self.set_default_response(Gtk.ResponseType.OK)
|
self.set_default_response(Gtk.ResponseType.OK)
|
||||||
self.set_size_request(800, 500)
|
self.set_size_request(800, 700)
|
||||||
|
|
||||||
self.scrollable = Gtk.ScrolledWindow()
|
self.scrollable = Gtk.ScrolledWindow()
|
||||||
self.view = Gtk.TreeView(
|
self.view = Gtk.TreeView(
|
||||||
enable_search=False, search_column=-1, fixed_height_mode=True
|
enable_search=False, search_column=-1, fixed_height_mode=True
|
||||||
)
|
)
|
||||||
self.scrollable.add(self.view)
|
self.scrollable.add(self.view)
|
||||||
set_surrounding_margins(self.scrollable, 20)
|
|
||||||
|
|
||||||
|
# set_surrounding_margins(self.scrollable, 20)
|
||||||
|
self.connect("response", self._on_response)
|
||||||
self.view.connect("row-activated", self._on_row_activated)
|
self.view.connect("row-activated", self._on_row_activated)
|
||||||
|
self.view.set_model(self.mod_store)
|
||||||
|
|
||||||
for i, column_title in enumerate(strings.server_mod_cols):
|
for i, column_title in enumerate(strings.server_mod_cols):
|
||||||
renderer = Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END)
|
renderer = Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END)
|
||||||
@@ -36,46 +59,20 @@ class ModDialog(GenericDialog):
|
|||||||
pass
|
pass
|
||||||
dialogBox.pack_end(self.scrollable, EXPAND, FILL, 0)
|
dialogBox.pack_end(self.scrollable, EXPAND, FILL, 0)
|
||||||
|
|
||||||
wait_dialog = GenericDialog(strings.modlist, Popup.WAIT)
|
mod_count = len(mods)
|
||||||
wait_dialog.show_all()
|
self.set_markup(f"Modlist ({mod_count} mods")
|
||||||
thread = threading.Thread(
|
for mod in mods:
|
||||||
target=self._background, args=(wait_dialog, record)
|
self.mod_store.append(mod)
|
||||||
)
|
|
||||||
thread.start()
|
|
||||||
|
|
||||||
# TODO: why are we passing record here?
|
self.show_all()
|
||||||
def _background(self, dialog: "GenericDialog", record: str) -> None:
|
|
||||||
def _load():
|
# TODO: handle response a la details dialog
|
||||||
dialog.destroy()
|
|
||||||
# TODO: natively implement
|
def _on_keypress(self, view: Gtk.TreeView, event: Gdk.EventKey) -> None:
|
||||||
#if data.returncode == 1:
|
if event.keyval == Gdk.KEY_Escape:
|
||||||
# AppNav.window.spawn_dialog(strings.server_error, Popup.NOTIFY)
|
|
||||||
# return
|
|
||||||
self.show_all()
|
|
||||||
self.set_markup(f"Modlist ({mod_count} mods)")
|
|
||||||
self.run()
|
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
return True
|
||||||
record = AppNav.treeview.get_record()
|
return False
|
||||||
if not record:
|
|
||||||
return
|
|
||||||
|
|
||||||
# TODO: thread
|
|
||||||
try:
|
|
||||||
# TODO: get default_steam_path from config
|
|
||||||
modlist = get_server_modlist(record)
|
|
||||||
mod_count = self._parse_modlist_rows(modlist)
|
|
||||||
except Exception:
|
|
||||||
# TODO: needs to pop error dialog
|
|
||||||
mod_count = 0
|
|
||||||
modlist_store.clear()
|
|
||||||
self.view.set_model(modlist_store)
|
|
||||||
GLib.idle_add(_load)
|
|
||||||
|
|
||||||
def _parse_modlist_rows(self, rows: list) -> bool | int:
|
|
||||||
for row in rows:
|
|
||||||
modlist_store.append(row)
|
|
||||||
return len(rows)
|
|
||||||
|
|
||||||
def _on_row_activated(
|
def _on_row_activated(
|
||||||
self,
|
self,
|
||||||
@@ -91,4 +88,5 @@ class ModDialog(GenericDialog):
|
|||||||
path = pathlist[0]
|
path = pathlist[0]
|
||||||
tree_iter = model.get_iter(path)
|
tree_iter = model.get_iter(path)
|
||||||
mod_id = model.get_value(tree_iter, 1)
|
mod_id = model.get_value(tree_iter, 1)
|
||||||
call_bash_func("open_workshop_page", mod_id)
|
print(mod_id)
|
||||||
|
# call_bash_func("open_workshop_page", mod_id)
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import gi
|
import textwrap
|
||||||
|
from typing import Self, TYPE_CHECKING
|
||||||
|
|
||||||
import dzgui.api.servers as Servers
|
|
||||||
from dzgui.const.constants import EXPAND, FILL, NO_PADDING
|
from dzgui.const.constants import EXPAND, FILL, NO_PADDING
|
||||||
from dzgui.const.enum import Popup
|
from dzgui.model.model_factory import ModelFactory
|
||||||
from dzgui.util import css
|
from dzgui.util import css
|
||||||
from dzgui.util import strings
|
from dzgui.util import strings
|
||||||
from dzgui.util.format import format_hyperlinks
|
from dzgui.util.format import format_hyperlinks
|
||||||
from dzgui.views.dialogs.generic import GenericDialog
|
from dzgui.views.dialogs.generic import GenericDialog
|
||||||
|
|
||||||
from typing import Self, TYPE_CHECKING
|
import gi
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
|
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
|
||||||
@@ -17,6 +17,7 @@ if TYPE_CHECKING:
|
|||||||
from dzgui.api.servers import Details
|
from dzgui.api.servers import Details
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: make a more generic base class
|
||||||
class ServerDetailsDialog(GenericDialog):
|
class ServerDetailsDialog(GenericDialog):
|
||||||
def __init__(self, controller, details: "Details"):
|
def __init__(self, controller, details: "Details"):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
@@ -99,3 +100,95 @@ class ServerDetailsDialog(GenericDialog):
|
|||||||
col: Gtk.TreeViewColumn,
|
col: Gtk.TreeViewColumn,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
|
def __init__(self, controller, details: "Details"):
|
||||||
|
super().__init__(
|
||||||
|
controller=controller,
|
||||||
|
text=details.name,
|
||||||
|
buttons=Gtk.ButtonsType.OK,
|
||||||
|
mtype=Gtk.MessageType.INFO,
|
||||||
|
secondary=strings.server_details,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: data type is dayzquery.DayzMod
|
||||||
|
|
||||||
|
|
||||||
|
class ServerModDialog(GenericDialog):
|
||||||
|
def __init__(self, controller, mods: list[str]):
|
||||||
|
|
||||||
|
# TODO: center secondary text
|
||||||
|
msg = textwrap.dedent(strings.workshop)
|
||||||
|
super().__init__(
|
||||||
|
controller=controller,
|
||||||
|
text=msg,
|
||||||
|
buttons=Gtk.ButtonsType.OK,
|
||||||
|
mtype=Gtk.MessageType.INFO,
|
||||||
|
secondary="",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mod_store = ModelFactory().make_server_mod_store()
|
||||||
|
|
||||||
|
dialogBox = self.get_content_area()
|
||||||
|
self.set_default_response(Gtk.ResponseType.OK)
|
||||||
|
self.set_size_request(800, 700)
|
||||||
|
|
||||||
|
self.scrollable = Gtk.ScrolledWindow()
|
||||||
|
self.view = Gtk.TreeView(
|
||||||
|
enable_search=False, search_column=-1, fixed_height_mode=True
|
||||||
|
)
|
||||||
|
self.scrollable.add(self.view)
|
||||||
|
|
||||||
|
# set_surrounding_margins(self.scrollable, 20)
|
||||||
|
self.connect("response", self._on_response)
|
||||||
|
self.view.connect("row-activated", self._on_row_activated)
|
||||||
|
self.view.set_model(self.mod_store)
|
||||||
|
|
||||||
|
for i, column_title in enumerate(strings.server_mod_cols):
|
||||||
|
renderer = Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END)
|
||||||
|
column = Gtk.TreeViewColumn(column_title, renderer, text=i)
|
||||||
|
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
|
||||||
|
self.view.append_column(column)
|
||||||
|
column.set_sort_column_id(i)
|
||||||
|
# FIXME: do not recycle generic string vars
|
||||||
|
match column_title:
|
||||||
|
case strings.mod:
|
||||||
|
column.set_fixed_width(350)
|
||||||
|
case strings._id:
|
||||||
|
column.set_fixed_width(200)
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
|
dialogBox.pack_end(self.scrollable, EXPAND, FILL, 0)
|
||||||
|
|
||||||
|
mod_count = len(mods)
|
||||||
|
self.set_markup(f"Modlist ({mod_count} mods)")
|
||||||
|
for mod in mods:
|
||||||
|
self.mod_store.append(mod)
|
||||||
|
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
|
def _on_response(self, dialog: Self, response: Gtk.ResponseType) -> None:
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def _on_keypress(self, view: Gtk.TreeView, event: Gdk.EventKey) -> None:
|
||||||
|
if event.keyval == Gdk.KEY_Escape:
|
||||||
|
self.destroy()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _on_row_activated(
|
||||||
|
self,
|
||||||
|
treeview: Gtk.TreeView,
|
||||||
|
tree_iter: Gtk.TreeIter,
|
||||||
|
col: Gtk.TreeViewColumn,
|
||||||
|
) -> None:
|
||||||
|
select = treeview.get_selection()
|
||||||
|
sels = select.get_selected_rows()
|
||||||
|
(model, pathlist) = sels
|
||||||
|
if len(pathlist) < 1:
|
||||||
|
return
|
||||||
|
path = pathlist[0]
|
||||||
|
tree_iter = model.get_iter(path)
|
||||||
|
mod_id = model.get_value(tree_iter, 1)
|
||||||
|
print(mod_id)
|
||||||
|
# call_bash_func("open_workshop_page", mod_id)
|
||||||
Reference in new issue
Block a user