mirror of
https://github.com/aclist/dztui.git
synced 2026-10-25 12:12:31 +01:00
353 lines
12 KiB
Python
353 lines
12 KiB
Python
from dataclasses import dataclass
|
|
from typing import Self, Sequence, TYPE_CHECKING
|
|
|
|
from dzgui.const.constants import (
|
|
ERROR,
|
|
WARNING,
|
|
)
|
|
from dzgui.const.enum import NotebookPage
|
|
from dzgui.util.css import add_class
|
|
from dzgui.util.keys import is_ctrl_mask
|
|
from dzgui.util.localize import number
|
|
from dzgui.strings.server_mods import checkmark
|
|
from dzgui.strings import preconnect
|
|
from dzgui.views.dialogs.generic import DebugDialog
|
|
from dzgui.views.components.frame import HeadingFrame
|
|
from dzgui.views.trees.tree_server_mods import ServerModTreeView
|
|
|
|
import gi
|
|
|
|
gi.require_version("Gtk", "3.0")
|
|
from gi.repository import Gdk, Gtk # noqa E402
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
from dzgui.managers.connection import Prerequisites
|
|
from dzgui.controllers.mc import Controller
|
|
from dzgui.controllers.emitter import Emitter
|
|
|
|
|
|
@dataclass
|
|
class Warnings:
|
|
passworded: bool
|
|
dayz_running: bool
|
|
no_steam: bool
|
|
wrong_version: bool
|
|
|
|
|
|
@dataclass
|
|
class Errors:
|
|
no_space: bool
|
|
no_dayz_exp: bool
|
|
no_dayz: bool
|
|
|
|
|
|
class Placeholder(Gtk.Label):
|
|
def __init__(self, text: str) -> None:
|
|
super().__init__(
|
|
label=text,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.START,
|
|
margin_start=10,
|
|
margin_bottom=5,
|
|
)
|
|
|
|
|
|
class MaskedTree(Gtk.TreeView):
|
|
def __init__(self, icon: str) -> None:
|
|
super().__init__(headers_visible=False, can_focus=False)
|
|
|
|
self.icon = icon
|
|
self.store = Gtk.ListStore(str, str)
|
|
self.set_model(self.store)
|
|
self.get_selection().set_mode(Gtk.SelectionMode.NONE)
|
|
|
|
icon_renderer = Gtk.CellRendererPixbuf()
|
|
# NOTE: adjust vertical offset between columns
|
|
icon_renderer.set_property("yalign", 0.6)
|
|
icon_column = Gtk.TreeViewColumn("", icon_renderer)
|
|
icon_column.add_attribute(icon_renderer, "icon-name", 0)
|
|
icon_column.set_fixed_width(50)
|
|
|
|
text_renderer = Gtk.CellRendererText()
|
|
text_column = Gtk.TreeViewColumn("", text_renderer, text=1)
|
|
|
|
self.append_column(icon_column)
|
|
self.append_column(text_column)
|
|
add_class(self, "masked-tree")
|
|
|
|
def append(self, item: Sequence[str]) -> None:
|
|
if len(item) > 1:
|
|
raise ValueError("This method only accepts one item")
|
|
self.store.append([self.icon, item])
|
|
|
|
def extend(self, items: list[str]) -> None:
|
|
self.store.clear()
|
|
for item in items:
|
|
self.store.append([self.icon, item])
|
|
|
|
|
|
class PreConnectionAssistant(Gtk.Box):
|
|
def __init__(self, controller: "Controller") -> None:
|
|
super().__init__(orientation=Gtk.Orientation.VERTICAL)
|
|
|
|
self.controller = controller
|
|
|
|
self.button_box = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.END,
|
|
valign=Gtk.Align.END,
|
|
hexpand=True,
|
|
vexpand=True,
|
|
spacing=10,
|
|
)
|
|
|
|
self.controller.register_widget("preconnect", self)
|
|
|
|
self.back = Gtk.Button(
|
|
label=preconnect.back, halign=Gtk.Align.END, hexpand=True
|
|
)
|
|
self.ok = Gtk.Button(label=preconnect.update_mods, halign=Gtk.Align.END)
|
|
self.connect_last = Gtk.Button(
|
|
label=preconnect.connect_last,
|
|
halign=Gtk.Align.END,
|
|
tooltip_text=preconnect.connect_last_tooltip,
|
|
)
|
|
|
|
self.button_box = Gtk.Box(
|
|
orientation=Gtk.Orientation.VERTICAL,
|
|
valign=Gtk.Align.END,
|
|
vexpand=True,
|
|
spacing=5,
|
|
)
|
|
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
|
|
|
|
# NOTE: -d flag
|
|
if self.controller.get_prefs().is_debug:
|
|
debug = Gtk.Button(label=preconnect.debug, halign=Gtk.Align.START)
|
|
debug.connect("clicked", self._on_debug_clicked)
|
|
box.add(debug)
|
|
for button in self.back, self.ok, self.connect_last:
|
|
box.add(button)
|
|
self.button_box.add(box)
|
|
|
|
self.back.connect("clicked", self._on_back_clicked)
|
|
self.ok.connect("clicked", self._on_ok_clicked)
|
|
self.connect_last.connect("clicked", self._on_connect_last_clicked)
|
|
|
|
self.title = Gtk.Label(label="")
|
|
add_class(self.title, "preconnect-heading")
|
|
|
|
self.tree = ServerModTreeView(self.controller)
|
|
self.mod_count = Gtk.Label(
|
|
label="",
|
|
halign=Gtk.Align.START,
|
|
margin_start=10,
|
|
margin_top=10,
|
|
margin_bottom=10,
|
|
)
|
|
self.progress_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=15)
|
|
self.progress_box.add(self.mod_count)
|
|
|
|
self.scrolled = Gtk.ScrolledWindow(margin_end=10)
|
|
self.scrolled.add(self.tree)
|
|
self.scrolled.set_size_request(600, 400)
|
|
|
|
self.tree_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
self.tree_box.add(self.scrolled)
|
|
self.tree_box.add(self.progress_box)
|
|
|
|
self.mods_placeholder = Placeholder(preconnect.placeholder_no_mods)
|
|
self.tree_box.add(self.mods_placeholder)
|
|
|
|
self.tree_frame = HeadingFrame.new_with_widget_and_label(
|
|
self.tree_box, preconnect.mods
|
|
)
|
|
|
|
# TODO: abstract into components
|
|
self.warning_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
self.warning_tree = MaskedTree(WARNING)
|
|
self.warning_placeholder = Placeholder(preconnect.placeholder_no_warnings)
|
|
self.warning_box.add(self.warning_tree)
|
|
self.warning_box.add(self.warning_placeholder)
|
|
self.warning_frame = HeadingFrame.new_with_widget_and_label(
|
|
self.warning_box, preconnect.warnings
|
|
)
|
|
|
|
self.error_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
self.error_tree = MaskedTree(ERROR)
|
|
self.error_placeholder = Placeholder(preconnect.no_errors)
|
|
self.error_box.add(self.error_tree)
|
|
self.error_box.add(self.error_placeholder)
|
|
self.error_frame = HeadingFrame.new_with_widget_and_label(
|
|
self.error_box, preconnect.errors
|
|
)
|
|
|
|
self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
|
|
self.box.add(self.title)
|
|
self.box.add(self.tree_frame)
|
|
self.box.add(self.warning_frame)
|
|
self.box.add(self.error_frame)
|
|
|
|
self.scrolled_box = Gtk.ScrolledWindow(
|
|
vexpand=True, propagate_natural_height=True
|
|
)
|
|
self.scrolled_box.add(self.box)
|
|
self.add(self.scrolled_box)
|
|
self.add(self.button_box)
|
|
|
|
emitter = self.controller.get_emitter()
|
|
emitter.connect("all_mods_synched", self._on_mods_synched)
|
|
self.connect("key-press-event", self._on_keypress)
|
|
self.connect("map", self._on_map)
|
|
|
|
def _on_mods_synched(self, emitter: "Emitter") -> None:
|
|
self.tree.mark_mods_synched()
|
|
|
|
def _on_map(self, widget: Self) -> None:
|
|
widgets = (
|
|
self.tree_frame,
|
|
self.progress_box,
|
|
self.error_placeholder,
|
|
self.warning_placeholder,
|
|
)
|
|
for child in widgets:
|
|
child.set_visible(True)
|
|
|
|
self.ok.set_sensitive(True)
|
|
self.ok.set_label(preconnect.update_mods)
|
|
|
|
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None:
|
|
if event.keyval == Gdk.KEY_Escape:
|
|
self.back.emit("clicked")
|
|
if is_ctrl_mask(event):
|
|
if event.keyval == Gdk.KEY_u:
|
|
self.ok.emit("clicked")
|
|
|
|
def _on_connect_last_clicked(self, button: Gtk.Button) -> None:
|
|
self.controller.update_and_load_to_menu()
|
|
|
|
def _on_debug_clicked(self, button: Gtk.Button) -> None:
|
|
args = self.controller.get_debug_args()
|
|
d = DebugDialog(self.controller, args)
|
|
d.show_all()
|
|
d.run()
|
|
|
|
def _on_ok_clicked(self, button: Gtk.Button) -> None:
|
|
self.controller.update_and_connect()
|
|
|
|
def _on_back_clicked(self, button: Gtk.Button) -> None:
|
|
self.controller.open_page(NotebookPage.SERVERS)
|
|
|
|
def _process_warnings(self, prereqs: "Prerequisites") -> None:
|
|
warnings: list[str] = []
|
|
errors: list[str] = []
|
|
|
|
resync_msg = preconnect.resync.format(prereqs.build)
|
|
|
|
"""Errors"""
|
|
if len(prereqs.invalid_mods) > 0:
|
|
pairs = [": ".join(sub) for sub in prereqs.invalid_mods]
|
|
lines = "\n".join(pairs)
|
|
msg = preconnect.invalid_mods.format(lines)
|
|
errors.append(msg)
|
|
if prereqs.binary_missing:
|
|
msg = preconnect.version_missing.format(prereqs.build)
|
|
msg += f"\n{resync_msg}"
|
|
errors.append(msg)
|
|
elif prereqs.local_version != prereqs.remote_version:
|
|
msg = preconnect.version_mismatch.format(
|
|
prereqs.local_version, prereqs.remote_version
|
|
)
|
|
msg += f"\n{resync_msg}"
|
|
errors.append(msg)
|
|
if prereqs.required_space > prereqs.available_space:
|
|
required_pretty = number(prereqs.required_space)
|
|
available_pretty = number(prereqs.available_space)
|
|
msg = preconnect.not_enough_space.format(required_pretty, available_pretty)
|
|
errors.append(msg)
|
|
if len(prereqs.mods) > 0 and prereqs.game_mode:
|
|
errors.append(preconnect.use_desktop_mode)
|
|
|
|
if prereqs.steam_proc.is_running is False:
|
|
client = prereqs.steam_proc.name
|
|
msg = preconnect.steam_not_running.format(client)
|
|
errors.append(msg)
|
|
|
|
"""Warnings"""
|
|
if prereqs.passworded:
|
|
warnings.append(preconnect.protected_server)
|
|
if prereqs.dayz_running is True:
|
|
warnings.append(preconnect.dayz_running)
|
|
if len(prereqs.mods) > 0 and prereqs.download_paused:
|
|
warnings.append(preconnect.downloads_paused)
|
|
|
|
allows_dl, running_app = prereqs.allows_downloads
|
|
if len(prereqs.mods) > 0 and allows_dl is False:
|
|
msg = preconnect.running_app.format(running_app)
|
|
warnings.append(msg)
|
|
|
|
self.add_warnings(warnings)
|
|
self.add_errors(errors)
|
|
|
|
if len(warnings) > 0:
|
|
self.warning_placeholder.set_visible(False)
|
|
if len(errors) > 0:
|
|
self.error_placeholder.set_visible(False)
|
|
self.ok.set_sensitive(False)
|
|
|
|
def _hide_mod_area(self) -> None:
|
|
self.scrolled.set_visible(False)
|
|
self.progress_box.set_visible(False)
|
|
self.mods_placeholder.set_visible(True)
|
|
|
|
def _show_mod_area(self) -> None:
|
|
self.scrolled.set_visible(True)
|
|
self.progress_box.set_visible(True)
|
|
self.mods_placeholder.set_visible(False)
|
|
|
|
def populate(self, prereqs: "Prerequisites") -> None:
|
|
mods = prereqs.mods
|
|
self.tree.populate(mods)
|
|
total_mods = len(mods)
|
|
|
|
name = prereqs.name
|
|
self.title.set_text(name)
|
|
|
|
if total_mods < 1:
|
|
self._hide_mod_area()
|
|
else:
|
|
self._show_mod_area()
|
|
msg = preconnect.up_to_date
|
|
self.mod_count.set_text(msg)
|
|
|
|
if prereqs.required_space != 0:
|
|
pretty = number(prereqs.required_space)
|
|
suffix = preconnect.required_space.format(pretty)
|
|
prefix = preconnect.total_mods
|
|
self.mod_count.set_text(f"{prefix}{str(total_mods)}.{suffix}")
|
|
else:
|
|
self.ok.set_label(preconnect.connect)
|
|
|
|
if prereqs.is_last_server:
|
|
self.connect_last.show()
|
|
else:
|
|
self.connect_last.hide()
|
|
|
|
self._process_warnings(prereqs)
|
|
self.tree.grab_focus()
|
|
|
|
def mark_finished(self) -> None:
|
|
self.mod_count.set_label(preconnect.all_updated)
|
|
model = self.tree.get_model()
|
|
if model is None:
|
|
return
|
|
for row in model:
|
|
row[2] = checkmark
|
|
|
|
def add_errors(self, errors: list[str]) -> None:
|
|
self.error_tree.extend(errors)
|
|
|
|
def add_warnings(self, warnings: list[str]) -> None:
|
|
self.warning_tree.extend(warnings)
|