mirror of
https://github.com/blw1138/Zordon.git
synced 2026-02-05 13:46:10 +00:00
* Initial commit for settings window * More WIP for the Settings panel * Added Local Files section to Settings * More WIP on Settings * Add ability to ignore system builds * Improvements to Launch and Delete buttons * Fix issue where icons were not loading * Network password settings WIP * Update label * Import and naming fixes * Speed improvements to launch * Update requirements.txt * Update Windows CPU name lookup * Add missing default values to a few settings * More settings fixes * Fix Windows Path issue * Added hard types for getting settings values * More UI cleanup * Correctly refresh Engines list after downloading new engine * Improve downloader with UI progress * More download improvements * Add Settings Button to Toolbar
554 lines
26 KiB
Python
554 lines
26 KiB
Python
import os
|
|
import socket
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
import humanize
|
|
from PyQt6 import QtCore
|
|
from PyQt6.QtCore import Qt, QSettings, pyqtSignal as Signal, QThread, pyqtSignal, QTimer
|
|
from PyQt6.QtGui import QIcon
|
|
from PyQt6.QtWidgets import QApplication, QMainWindow, QListWidget, QListWidgetItem, QStackedWidget, QVBoxLayout, \
|
|
QWidget, QLabel, QCheckBox, QLineEdit, \
|
|
QPushButton, QHBoxLayout, QGroupBox, QTableWidget, QAbstractItemView, QTableWidgetItem, QHeaderView, \
|
|
QMessageBox, QProgressBar
|
|
|
|
from src.api.server_proxy import RenderServerProxy
|
|
from src.engines.engine_manager import EngineManager
|
|
from src.utilities.config import Config
|
|
from src.utilities.misc_helper import launch_url, system_safe_path
|
|
from src.version import APP_AUTHOR, APP_NAME
|
|
|
|
settings = QSettings(APP_AUTHOR, APP_NAME)
|
|
|
|
class GetEngineInfoWorker(QThread):
|
|
"""
|
|
The GetEngineInfoWorker class fetches engine information from a server in a background thread.
|
|
|
|
Attributes:
|
|
done: A signal emitted when the engine information is retrieved.
|
|
|
|
Methods:
|
|
run(self): Fetches engine information from the server.
|
|
"""
|
|
done = pyqtSignal(object) # emits the result when finished
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.parent = parent
|
|
|
|
def run(self):
|
|
data = RenderServerProxy(socket.gethostname()).get_engine_info()
|
|
self.done.emit(data)
|
|
|
|
class SettingsWindow(QMainWindow):
|
|
"""
|
|
The SettingsWindow class provides a user interface for managing engine settings.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.engine_download_progress_bar = None
|
|
self.engines_last_update_label = None
|
|
self.check_for_engine_updates_checkbox = None
|
|
self.delete_engine_button = None
|
|
self.launch_engine_button = None
|
|
self.show_password_button = None
|
|
self.network_password_line = None
|
|
self.enable_network_password_checkbox = None
|
|
self.check_for_new_engines_button = None
|
|
|
|
if not EngineManager.engines_path: # fix issue where sometimes path was not set
|
|
EngineManager.engines_path = system_safe_path(
|
|
os.path.join(os.path.join(os.path.expanduser(Config.upload_folder),
|
|
'engines')))
|
|
|
|
self.installed_engines_table = None
|
|
|
|
self.setWindowTitle("Settings")
|
|
|
|
# Create the main layout
|
|
main_layout = QVBoxLayout()
|
|
|
|
# Create the sidebar (QListWidget) for navigation
|
|
self.sidebar = QListWidget()
|
|
self.sidebar.setFixedWidth(150)
|
|
|
|
# Set the icon size
|
|
self.sidebar.setIconSize(QtCore.QSize(32, 32)) # Increase the icon size to 32x32 pixels
|
|
|
|
# Adjust the font size for the sidebar items
|
|
font = self.sidebar.font()
|
|
font.setPointSize(12) # Increase the font size
|
|
self.sidebar.setFont(font)
|
|
|
|
# Add items with icons to the sidebar
|
|
resources_dir = os.path.join(Path(__file__).resolve().parent.parent.parent, 'resources')
|
|
self.add_sidebar_item("General", os.path.join(resources_dir, "Gear.png"))
|
|
self.add_sidebar_item("Server", os.path.join(resources_dir, "Server.png"))
|
|
self.add_sidebar_item("Engines", os.path.join(resources_dir, "Blender.png"))
|
|
self.sidebar.setCurrentRow(0)
|
|
|
|
# Create the stacked widget to hold different settings pages
|
|
self.stacked_widget = QStackedWidget()
|
|
|
|
# Create pages for each section
|
|
general_page = self.create_general_page()
|
|
network_page = self.create_network_page()
|
|
engines_page = self.create_engines_page()
|
|
|
|
# Add pages to the stacked widget
|
|
self.stacked_widget.addWidget(general_page)
|
|
self.stacked_widget.addWidget(network_page)
|
|
self.stacked_widget.addWidget(engines_page)
|
|
|
|
# Connect the sidebar to the stacked widget
|
|
self.sidebar.currentRowChanged.connect(self.stacked_widget.setCurrentIndex)
|
|
|
|
# Create a horizontal layout to hold the sidebar and stacked widget
|
|
content_layout = QHBoxLayout()
|
|
content_layout.addWidget(self.sidebar)
|
|
content_layout.addWidget(self.stacked_widget)
|
|
|
|
# Add the content layout to the main layout
|
|
main_layout.addLayout(content_layout)
|
|
|
|
# Add the "OK" button at the bottom
|
|
ok_button = QPushButton("OK")
|
|
ok_button.clicked.connect(self.close)
|
|
ok_button.setFixedWidth(80)
|
|
ok_button.setDefault(True)
|
|
main_layout.addWidget(ok_button, alignment=Qt.AlignmentFlag.AlignRight)
|
|
|
|
# Create a central widget and set the layout
|
|
central_widget = QWidget()
|
|
central_widget.setLayout(main_layout)
|
|
self.setCentralWidget(central_widget)
|
|
|
|
self.setMinimumSize(700, 400)
|
|
|
|
# timers for background download UI updates
|
|
self.timer = QTimer(self)
|
|
self.timer.timeout.connect(self.update_engine_download_status)
|
|
|
|
def add_sidebar_item(self, name, icon_path):
|
|
"""Add an item with an icon to the sidebar."""
|
|
item = QListWidgetItem(QIcon(icon_path), name)
|
|
self.sidebar.addItem(item)
|
|
|
|
def create_general_page(self):
|
|
"""Create the General settings page."""
|
|
page = QWidget()
|
|
layout = QVBoxLayout()
|
|
|
|
# Startup Settings Group
|
|
startup_group = QGroupBox("Startup Settings")
|
|
startup_layout = QVBoxLayout()
|
|
# startup_layout.addWidget(QCheckBox("Start application on system startup"))
|
|
check_for_updates_checkbox = QCheckBox("Check for updates automatically")
|
|
check_for_updates_checkbox.setChecked(settings.value("auto_check_for_updates", True, type=bool))
|
|
check_for_updates_checkbox.stateChanged.connect(lambda state: settings.setValue("auto_check_for_updates", bool(state)))
|
|
startup_layout.addWidget(check_for_updates_checkbox)
|
|
startup_group.setLayout(startup_layout)
|
|
|
|
# Local Files Group
|
|
data_path = Path(Config.upload_folder).expanduser()
|
|
path_size = sum(f.stat().st_size for f in Path(data_path).rglob('*') if f.is_file())
|
|
database_group = QGroupBox("Local Files")
|
|
database_layout = QVBoxLayout()
|
|
database_layout.addWidget(QLabel(f"Local Directory: {data_path}"))
|
|
database_layout.addWidget(QLabel(f"Size: {humanize.naturalsize(path_size, binary=True)}"))
|
|
open_database_path_button = QPushButton("Open Directory")
|
|
open_database_path_button.clicked.connect(lambda: launch_url(data_path))
|
|
open_database_path_button.setFixedWidth(200)
|
|
database_layout.addWidget(open_database_path_button)
|
|
database_group.setLayout(database_layout)
|
|
|
|
|
|
# Render Settings Group
|
|
render_settings_group = QGroupBox("Render Engine Settings")
|
|
render_settings_layout = QVBoxLayout()
|
|
render_settings_layout.addWidget(QLabel("Restrict to render nodes with same:"))
|
|
require_same_engine_checkbox = QCheckBox("Renderer Version")
|
|
require_same_engine_checkbox.setChecked(settings.value("render_require_same_engine_version", False, type=bool))
|
|
require_same_engine_checkbox.stateChanged.connect(lambda state: settings.setValue("render_require_same_engine_version", bool(state)))
|
|
render_settings_layout.addWidget(require_same_engine_checkbox)
|
|
require_same_cpu_checkbox = QCheckBox("CPU Architecture")
|
|
require_same_cpu_checkbox.setChecked(settings.value("render_require_same_cpu_type", False, type=bool))
|
|
require_same_cpu_checkbox.stateChanged.connect(lambda state: settings.setValue("render_require_same_cpu_type", bool(state)))
|
|
render_settings_layout.addWidget(require_same_cpu_checkbox)
|
|
require_same_os_checkbox = QCheckBox("Operating System")
|
|
require_same_os_checkbox.setChecked(settings.value("render_require_same_os", False, type=bool))
|
|
require_same_os_checkbox.stateChanged.connect(lambda state: settings.setValue("render_require_same_os", bool(state)))
|
|
render_settings_layout.addWidget(require_same_os_checkbox)
|
|
render_settings_group.setLayout(render_settings_layout)
|
|
|
|
layout.addWidget(startup_group)
|
|
layout.addWidget(database_group)
|
|
layout.addWidget(render_settings_group)
|
|
|
|
layout.addStretch() # Add a stretch to push content to the top
|
|
page.setLayout(layout)
|
|
return page
|
|
|
|
def create_network_page(self):
|
|
"""Create the Network settings page."""
|
|
page = QWidget()
|
|
layout = QVBoxLayout()
|
|
|
|
# Sharing Settings Group
|
|
sharing_group = QGroupBox("Sharing Settings")
|
|
sharing_layout = QVBoxLayout()
|
|
|
|
enable_sharing_checkbox = QCheckBox("Enable other computers on the network to render to this machine")
|
|
enable_sharing_checkbox.setChecked(settings.value("enable_network_sharing", False, type=bool))
|
|
enable_sharing_checkbox.stateChanged.connect(self.toggle_render_sharing)
|
|
sharing_layout.addWidget(enable_sharing_checkbox)
|
|
|
|
password_enabled = (settings.value("enable_network_sharing", False, type=bool) and
|
|
settings.value("enable_network_password", False, type=bool))
|
|
|
|
password_layout = QHBoxLayout()
|
|
password_layout.setContentsMargins(0, 0, 0, 0)
|
|
self.enable_network_password_checkbox = QCheckBox("Enable network password:")
|
|
self.enable_network_password_checkbox.setChecked(settings.value("enable_network_password", False, type=bool))
|
|
self.enable_network_password_checkbox.stateChanged.connect(self.enable_network_password_changed)
|
|
self.enable_network_password_checkbox.setEnabled(settings.value("enable_network_sharing", False, type=bool))
|
|
sharing_layout.addWidget(self.enable_network_password_checkbox)
|
|
self.network_password_line = QLineEdit()
|
|
self.network_password_line.setPlaceholderText("Enter a password")
|
|
self.network_password_line.setEchoMode(QLineEdit.EchoMode.Password)
|
|
self.network_password_line.setEnabled(password_enabled)
|
|
password_layout.addWidget(self.network_password_line)
|
|
self.show_password_button = QPushButton("Show")
|
|
self.show_password_button.setEnabled(password_enabled)
|
|
self.show_password_button.clicked.connect(self.show_password_button_pressed)
|
|
password_layout.addWidget(self.show_password_button)
|
|
sharing_layout.addLayout(password_layout)
|
|
|
|
sharing_group.setLayout(sharing_layout)
|
|
|
|
layout.addWidget(sharing_group)
|
|
|
|
layout.addStretch() # Add a stretch to push content to the top
|
|
page.setLayout(layout)
|
|
return page
|
|
|
|
def toggle_render_sharing(self, enable_sharing):
|
|
settings.setValue("enable_network_sharing", enable_sharing)
|
|
self.enable_network_password_checkbox.setEnabled(enable_sharing)
|
|
enable_password = enable_sharing and settings.value("enable_network_password", False, type=bool)
|
|
self.network_password_line.setEnabled(enable_password)
|
|
self.show_password_button.setEnabled(enable_password)
|
|
|
|
def enable_network_password_changed(self, new_value):
|
|
settings.setValue("enable_network_password", new_value)
|
|
self.network_password_line.setEnabled(new_value)
|
|
self.show_password_button.setEnabled(new_value)
|
|
|
|
def show_password_button_pressed(self):
|
|
# toggle showing / hiding the password
|
|
show_pass = self.show_password_button.text() == "Show"
|
|
self.show_password_button.setText("Hide" if show_pass else "Show")
|
|
self.network_password_line.setEchoMode(QLineEdit.EchoMode.Normal if show_pass else QLineEdit.EchoMode.Password)
|
|
|
|
def create_engines_page(self):
|
|
"""Create the Engines settings page."""
|
|
page = QWidget()
|
|
layout = QVBoxLayout()
|
|
|
|
# Installed Engines Group
|
|
installed_group = QGroupBox("Installed Engines")
|
|
installed_layout = QVBoxLayout()
|
|
|
|
# Setup table
|
|
self.installed_engines_table = EngineTableWidget()
|
|
self.installed_engines_table.row_selected.connect(self.engine_table_selected)
|
|
installed_layout.addWidget(self.installed_engines_table)
|
|
|
|
# Ignore system installs
|
|
engine_ignore_system_installs_checkbox = QCheckBox("Ignore system installs")
|
|
engine_ignore_system_installs_checkbox.setChecked(settings.value("engines_ignore_system_installs", False, type=bool))
|
|
engine_ignore_system_installs_checkbox.stateChanged.connect(self.change_ignore_system_installs)
|
|
installed_layout.addWidget(engine_ignore_system_installs_checkbox)
|
|
|
|
# Engine Launch / Delete buttons
|
|
installed_buttons_layout = QHBoxLayout()
|
|
self.launch_engine_button = QPushButton("Launch")
|
|
self.launch_engine_button.setEnabled(False)
|
|
self.launch_engine_button.clicked.connect(self.launch_selected_engine)
|
|
self.delete_engine_button = QPushButton("Delete")
|
|
self.delete_engine_button.setEnabled(False)
|
|
self.delete_engine_button.clicked.connect(self.delete_selected_engine)
|
|
|
|
installed_buttons_layout.addWidget(self.launch_engine_button)
|
|
installed_buttons_layout.addWidget(self.delete_engine_button)
|
|
installed_layout.addLayout(installed_buttons_layout)
|
|
installed_group.setLayout(installed_layout)
|
|
|
|
# Engine Updates Group
|
|
engine_updates_group = QGroupBox("Auto-Install")
|
|
engine_updates_layout = QVBoxLayout()
|
|
|
|
engine_download_layout = QHBoxLayout()
|
|
engine_download_layout.addWidget(QLabel("Enable Downloads for:"))
|
|
|
|
at_least_one_downloadable = False
|
|
for engine in EngineManager.downloadable_engines():
|
|
engine_download_check = QCheckBox(engine.name())
|
|
is_checked = settings.value(f"engine_download-{engine.name()}", False, type=bool)
|
|
at_least_one_downloadable |= is_checked
|
|
engine_download_check.setChecked(is_checked)
|
|
# Capture the checkbox correctly using a default argument in lambda
|
|
engine_download_check.clicked.connect(
|
|
lambda state, checkbox=engine_download_check: self.engine_download_settings_changed(state, checkbox.text())
|
|
)
|
|
engine_download_layout.addWidget(engine_download_check)
|
|
|
|
engine_updates_layout.addLayout(engine_download_layout)
|
|
|
|
self.check_for_engine_updates_checkbox = QCheckBox("Check for new versions on launch")
|
|
self.check_for_engine_updates_checkbox.setChecked(settings.value('check_for_engine_updates_on_launch', True, type=bool))
|
|
self.check_for_engine_updates_checkbox.setEnabled(at_least_one_downloadable)
|
|
self.check_for_engine_updates_checkbox.stateChanged.connect(
|
|
lambda state: settings.setValue("check_for_engine_updates_on_launch", bool(state)))
|
|
engine_updates_layout.addWidget(self.check_for_engine_updates_checkbox)
|
|
self.engines_last_update_label = QLabel()
|
|
self.update_last_checked_label()
|
|
self.engines_last_update_label.setEnabled(at_least_one_downloadable)
|
|
engine_updates_layout.addWidget(self.engines_last_update_label)
|
|
self.engine_download_progress_bar = QProgressBar()
|
|
engine_updates_layout.addWidget(self.engine_download_progress_bar)
|
|
self.engine_download_progress_bar.setHidden(True)
|
|
self.check_for_new_engines_button = QPushButton("Check for New Versions...")
|
|
self.check_for_new_engines_button.setEnabled(at_least_one_downloadable)
|
|
self.check_for_new_engines_button.clicked.connect(self.check_for_new_engines)
|
|
engine_updates_layout.addWidget(self.check_for_new_engines_button)
|
|
engine_updates_group.setLayout(engine_updates_layout)
|
|
|
|
layout.addWidget(installed_group)
|
|
layout.addWidget(engine_updates_group)
|
|
|
|
layout.addStretch() # Add a stretch to push content to the top
|
|
page.setLayout(layout)
|
|
return page
|
|
|
|
def change_ignore_system_installs(self, value):
|
|
settings.setValue("engines_ignore_system_installs", bool(value))
|
|
self.installed_engines_table.update_engines_table()
|
|
|
|
def update_last_checked_label(self):
|
|
"""Retrieve the last check timestamp and return a human-friendly string."""
|
|
last_checked_str = settings.value("engines_last_update_time", None)
|
|
if not last_checked_str:
|
|
time_string = "Never"
|
|
else:
|
|
last_checked_dt = datetime.fromisoformat(last_checked_str)
|
|
now = datetime.now()
|
|
time_string = humanize.naturaltime(now - last_checked_dt)
|
|
self.engines_last_update_label.setText(f"Last Updated: {time_string}")
|
|
|
|
def engine_download_settings_changed(self, state, engine_name):
|
|
settings.setValue(f"engine_download-{engine_name}", state)
|
|
|
|
at_least_one_downloadable = False
|
|
for engine in EngineManager.downloadable_engines():
|
|
at_least_one_downloadable |= settings.value(f"engine_download-{engine.name()}", False, type=bool)
|
|
self.check_for_new_engines_button.setEnabled(at_least_one_downloadable)
|
|
self.check_for_engine_updates_checkbox.setEnabled(at_least_one_downloadable)
|
|
self.engines_last_update_label.setEnabled(at_least_one_downloadable)
|
|
|
|
def delete_selected_engine(self):
|
|
engine_info = self.installed_engines_table.selected_engine_data()
|
|
reply = QMessageBox.question(self, f"Delete {engine_info['engine']} {engine_info['version']}?",
|
|
f"Do you want to delete {engine_info['engine']} {engine_info['version']}?",
|
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
|
|
|
if reply is not QMessageBox.StandardButton.Yes:
|
|
return
|
|
|
|
delete_result = EngineManager.delete_engine_download(engine_info.get('engine'),
|
|
engine_info.get('version'),
|
|
engine_info.get('system_os'),
|
|
engine_info.get('cpu'))
|
|
self.installed_engines_table.update_engines_table(use_cached=False)
|
|
if delete_result:
|
|
QMessageBox.information(self, f"{engine_info['engine']} {engine_info['version']} Deleted",
|
|
f"{engine_info['engine']} {engine_info['version']} deleted successfully",
|
|
QMessageBox.StandardButton.Ok)
|
|
else:
|
|
QMessageBox.warning(self, f"Unknown Error",
|
|
f"Unknown error while deleting {engine_info['engine']} {engine_info['version']}.",
|
|
QMessageBox.StandardButton.Ok)
|
|
|
|
def launch_selected_engine(self):
|
|
engine_info = self.installed_engines_table.selected_engine_data()
|
|
if engine_info:
|
|
launch_url(engine_info['path'])
|
|
|
|
def engine_table_selected(self):
|
|
engine_data = self.installed_engines_table.selected_engine_data()
|
|
if engine_data:
|
|
self.launch_engine_button.setEnabled(bool(engine_data.get('path') or True))
|
|
self.delete_engine_button.setEnabled(engine_data.get('type') == 'managed')
|
|
else:
|
|
self.launch_engine_button.setEnabled(False)
|
|
self.delete_engine_button.setEnabled(False)
|
|
|
|
def check_for_new_engines(self):
|
|
|
|
ignore_system = settings.value("engines_ignore_system_installs", False, type=bool)
|
|
messagebox_shown = False
|
|
for engine in EngineManager.downloadable_engines():
|
|
if settings.value(f'engine_download-{engine.name()}', False, type=bool):
|
|
result = EngineManager.is_engine_update_available(engine, ignore_system_installs=ignore_system)
|
|
if result:
|
|
result['name'] = engine.name()
|
|
msg_box = QMessageBox()
|
|
msg_box.setWindowTitle(f"{result['name']} ({result['version']}) Available")
|
|
msg_box.setText(f"A new version of {result['name']} is available ({result['version']}).\n\n"
|
|
f"Would you like to download it now?")
|
|
msg_box.setIcon(QMessageBox.Icon.Question)
|
|
msg_box.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
|
msg_result = msg_box.exec()
|
|
messagebox_shown = True
|
|
if msg_result == QMessageBox.StandardButton.Yes:
|
|
EngineManager.download_engine(engine=engine.name(), version=result['version'], background=True,
|
|
ignore_system=ignore_system)
|
|
self.engine_download_progress_bar.setHidden(False)
|
|
self.engine_download_progress_bar.setValue(0)
|
|
self.engine_download_progress_bar.setMaximum(100)
|
|
self.check_for_new_engines_button.setEnabled(False)
|
|
self.timer.start(1000)
|
|
|
|
if not messagebox_shown:
|
|
msg_box = QMessageBox()
|
|
msg_box.setWindowTitle("No Updates Available")
|
|
msg_box.setText("No Updates Available.")
|
|
msg_box.setIcon(QMessageBox.Icon.Information)
|
|
msg_box.setStandardButtons(QMessageBox.StandardButton.Ok)
|
|
msg_box.exec()
|
|
|
|
settings.setValue("engines_last_update_time", datetime.now().isoformat())
|
|
self.update_engine_download_status()
|
|
|
|
def update_engine_download_status(self):
|
|
|
|
running_tasks = EngineManager.active_downloads()
|
|
if not running_tasks:
|
|
self.timer.stop()
|
|
self.engine_download_progress_bar.setHidden(True)
|
|
self.installed_engines_table.update_engines_table(use_cached=False)
|
|
self.update_last_checked_label()
|
|
self.check_for_new_engines_button.setEnabled(True)
|
|
return
|
|
|
|
percent_complete = int(running_tasks[0].percent_complete * 100)
|
|
self.engine_download_progress_bar.setValue(percent_complete)
|
|
if percent_complete == 100:
|
|
status_update = f"Installing {running_tasks[0].engine.capitalize()} {running_tasks[0].version}..."
|
|
else:
|
|
status_update = f"Downloading {running_tasks[0].engine.capitalize()} {running_tasks[0].version}..."
|
|
self.engines_last_update_label.setText(status_update)
|
|
|
|
|
|
class EngineTableWidget(QWidget):
|
|
"""
|
|
The EngineTableWidget class displays a table of installed engines.
|
|
|
|
Attributes:
|
|
table: A table widget displaying engine information.
|
|
|
|
Methods:
|
|
on_selection_changed(self): Emits a signal when the user selects a different row in the table.
|
|
"""
|
|
|
|
row_selected = Signal()
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.__get_engine_info_worker = None
|
|
self.table = QTableWidget(0, 4)
|
|
self.table.setHorizontalHeaderLabels(["Engine", "Version", "Type", "Path"])
|
|
self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
|
self.table.verticalHeader().setVisible(False)
|
|
# self.table_widget.itemSelectionChanged.connect(self.engine_picked)
|
|
self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
|
self.table.selectionModel().selectionChanged.connect(self.on_selection_changed)
|
|
|
|
layout = QVBoxLayout(self)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
layout.setSpacing(0)
|
|
layout.addWidget(self.table)
|
|
|
|
self.raw_server_data = None
|
|
|
|
def showEvent(self, event):
|
|
"""Runs when the widget is about to be shown."""
|
|
self.update_engines_table()
|
|
super().showEvent(event) # Ensure normal event processing
|
|
|
|
def engine_data_ready(self, raw_server_data):
|
|
self.raw_server_data = raw_server_data
|
|
self.update_engines_table()
|
|
|
|
def update_engines_table(self, use_cached=True):
|
|
if not self.raw_server_data or not use_cached:
|
|
self.__get_engine_info_worker = GetEngineInfoWorker(self)
|
|
self.__get_engine_info_worker.done.connect(self.engine_data_ready)
|
|
self.__get_engine_info_worker.start()
|
|
if not self.raw_server_data:
|
|
return
|
|
|
|
table_data = [] # convert the data into a flat list
|
|
for _, engine_data in self.raw_server_data.items():
|
|
table_data.extend(engine_data['versions'])
|
|
|
|
if settings.value("engines_ignore_system_installs", False, type=bool):
|
|
table_data = [x for x in table_data if x['type'] != 'system']
|
|
|
|
self.table.clear()
|
|
self.table.setRowCount(len(table_data))
|
|
self.table.setColumnCount(4)
|
|
|
|
self.table.setHorizontalHeaderLabels(['Engine', 'Version', 'Type', 'Path'])
|
|
self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.Fixed)
|
|
self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed)
|
|
self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Fixed)
|
|
self.table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
|
|
|
|
for row, engine in enumerate(table_data):
|
|
self.table.setItem(row, 0, QTableWidgetItem(engine['engine']))
|
|
self.table.setItem(row, 1, QTableWidgetItem(engine['version']))
|
|
self.table.setItem(row, 2, QTableWidgetItem(engine['type']))
|
|
self.table.setItem(row, 3, QTableWidgetItem(engine['path']))
|
|
|
|
self.table.selectRow(0)
|
|
|
|
def selected_engine_data(self):
|
|
"""Returns the data from the selected row as a dictionary."""
|
|
row = self.table.currentRow() # Get the selected row index
|
|
|
|
if row < 0 or not len(self.table.selectedItems()): # No row selected
|
|
return None
|
|
|
|
data = {
|
|
"engine": self.table.item(row, 0).text(),
|
|
"version": self.table.item(row, 1).text(),
|
|
"type": self.table.item(row, 2).text(),
|
|
"path": self.table.item(row, 3).text(),
|
|
}
|
|
|
|
return data
|
|
|
|
def on_selection_changed(self):
|
|
self.row_selected.emit()
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app = QApplication([])
|
|
window = SettingsWindow()
|
|
window.show()
|
|
app.exec() |