Files
FRAISEMOE-Addons-Installer-…/source/core/managers/ui_manager.py
hyb-oyqq e82e5dcd63 feat(core): 优化UI管理器,增强组件初始化和菜单构建
- 移除不再使用的UI组件和方法,简化代码结构。
- 引入新的UI组件管理类,提升UI组件的初始化和菜单构建逻辑。
- 更新加载对话框和消息框的创建逻辑,确保使用统一的对话框工厂方法。
- 保留向后兼容性,添加委托方法以支持旧功能,提升用户体验。
2025-08-13 12:38:37 +08:00

377 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QMessageBox
import os
import logging
import subprocess
from utils import load_base64_image, resource_path
from config.config import APP_NAME, APP_VERSION
from ui.components import FontStyleManager, DialogFactory, ExternalLinksHandler, MenuBuilder
logger = logging.getLogger(__name__)
class UIManager:
def __init__(self, main_window):
"""初始化UI管理器
Args:
main_window: 主窗口实例用于设置UI元素
"""
self.main_window = main_window
# 使用getattr获取ui属性如果不存在则为None
self.ui = getattr(main_window, 'ui', None)
# 获取主窗口的IPv6Manager实例
self.ipv6_manager = getattr(main_window, 'ipv6_manager', None)
# 初始化UI组件
self.font_style_manager = FontStyleManager()
self.dialog_factory = DialogFactory(main_window)
self.external_links_handler = ExternalLinksHandler(main_window, self.dialog_factory)
self.menu_builder = MenuBuilder(main_window, self.font_style_manager, self.external_links_handler, self.dialog_factory)
# 保留一些快捷访问属性以保持兼容性
self.debug_action = None
self.disable_auto_restore_action = None
self.disable_pre_hash_action = None
def setup_ui(self):
"""设置UI元素包括窗口图标、标题和菜单"""
# 设置窗口图标
icon_path = resource_path(os.path.join("assets", "images", "ICO", "icon.png"))
if os.path.exists(icon_path):
self.main_window.setWindowIcon(QIcon(icon_path))
# 获取当前离线模式状态
is_offline_mode = False
if hasattr(self.main_window, 'offline_mode_manager'):
is_offline_mode = self.main_window.offline_mode_manager.is_in_offline_mode()
# 设置窗口标题和UI标题标签
mode_indicator = "[离线模式]" if is_offline_mode else "[在线模式]"
self.main_window.setWindowTitle(f"{APP_NAME} v{APP_VERSION} {mode_indicator}")
# 更新UI中的标题标签
if hasattr(self.main_window, 'ui') and hasattr(self.main_window.ui, 'title_label'):
self.main_window.ui.title_label.setText(f"{APP_NAME} v{APP_VERSION} {mode_indicator}")
# 使用新的菜单构建器设置所有菜单
self.menu_builder.setup_all_menus()
# 保持对一些重要UI元素的引用以确保兼容性
self.debug_action = self.menu_builder.debug_action
self.disable_auto_restore_action = self.menu_builder.disable_auto_restore_action
self.disable_pre_hash_action = self.menu_builder.disable_pre_hash_action
# 为了向后兼容性,添加委托方法
def create_progress_window(self, title, initial_text="准备中..."):
"""创建进度窗口委托给dialog_factory"""
return self.dialog_factory.create_progress_window(title, initial_text)
def show_loading_dialog(self, message):
"""显示加载对话框委托给dialog_factory"""
return self.dialog_factory.show_loading_dialog(message)
def hide_loading_dialog(self):
"""隐藏加载对话框委托给dialog_factory"""
return self.dialog_factory.hide_loading_dialog()
def _create_message_box(self, title, message, buttons=QMessageBox.StandardButton.Ok):
"""创建消息框委托给dialog_factory"""
return self.dialog_factory.create_message_box(title, message, buttons)
def show_menu(self, menu, button):
"""显示菜单委托给menu_builder"""
return self.menu_builder.show_menu(menu, button)
def _handle_ipv6_toggle(self, enabled):
"""处理IPv6支持切换事件
Args:
enabled: 是否启用IPv6支持
"""
if not self.ipv6_manager:
# 显示错误提示
msg_box = self._create_message_box("错误", "\nIPv6管理器尚未初始化请稍后再试。\n")
msg_box.exec()
# 恢复复选框状态
self.ipv6_action.setChecked(not enabled)
return
if enabled:
# 先显示警告提示
warning_msg_box = self._create_message_box(
"警告",
"\n目前IPv6支持功能仍在测试阶段可能会发生意料之外的bug\n\n您确定需要启用吗?\n",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
response = warning_msg_box.exec()
# 如果用户选择不启用,直接返回
if response != QMessageBox.StandardButton.Yes:
# 恢复复选框状态
self.ipv6_action.setChecked(False)
return
# 显示正在校验IPv6的提示
msg_box = self._create_message_box("IPv6检测", "\n正在校验是否支持IPv6请稍候...\n")
msg_box.open() # 使用open而不是exec这样不会阻塞UI
# 处理消息队列,确保对话框显示
from PySide6.QtCore import QCoreApplication
QCoreApplication.processEvents()
# 检查IPv6是否可用
ipv6_available = self.ipv6_manager.check_ipv6_availability()
# 关闭提示对话框
msg_box.accept()
if not ipv6_available:
# 显示IPv6不可用的提示
error_msg_box = self._create_message_box(
"IPv6不可用",
"\n未检测到可用的IPv6连接无法启用IPv6支持。\n\n请确保您的网络环境支持IPv6且已正确配置。\n"
)
error_msg_box.exec()
# 恢复复选框状态
self.ipv6_action.setChecked(False)
return False
# 使用IPv6Manager处理切换
success = self.ipv6_manager.toggle_ipv6_support(enabled)
# 如果切换失败,恢复复选框状态
if not success:
self.ipv6_action.setChecked(not enabled)
def show_download_thread_settings(self):
"""显示下载线程设置对话框"""
if hasattr(self.main_window, 'download_manager'):
self.main_window.download_manager.show_download_thread_settings()
else:
# 如果下载管理器不可用,显示错误信息
self.dialog_factory.show_simple_message("错误", "\n下载管理器未初始化,无法修改下载线程设置。\n", "error")
def restore_hosts_backup(self):
"""还原软件备份的hosts文件"""
if hasattr(self.main_window, 'download_manager') and hasattr(self.main_window.download_manager, 'hosts_manager'):
try:
# 调用恢复hosts文件的方法
result = self.main_window.download_manager.hosts_manager.restore()
if result:
msg_box = self._create_message_box("成功", "\nhosts文件已成功还原为备份版本。\n")
else:
msg_box = self._create_message_box("警告", "\n还原hosts文件失败或没有找到备份文件。\n")
msg_box.exec()
except Exception as e:
msg_box = self._create_message_box("错误", f"\n还原hosts文件时发生错误\n\n{str(e)}\n")
msg_box.exec()
else:
msg_box = self._create_message_box("错误", "\n无法访问hosts管理器。\n")
msg_box.exec()
def clean_hosts_entries(self):
"""手动删除软件添加的hosts条目"""
if hasattr(self.main_window, 'download_manager') and hasattr(self.main_window.download_manager, 'hosts_manager'):
try:
# 调用清理hosts条目的方法强制清理即使禁用了自动还原
result = self.main_window.download_manager.hosts_manager.check_and_clean_all_entries(force_clean=True)
if result:
msg_box = self._create_message_box("成功", "\n已成功清理软件添加的hosts条目。\n")
else:
msg_box = self._create_message_box("提示", "\n未发现软件添加的hosts条目或清理操作失败。\n")
msg_box.exec()
except Exception as e:
msg_box = self._create_message_box("错误", f"\n清理hosts条目时发生错误\n\n{str(e)}\n")
msg_box.exec()
else:
msg_box = self._create_message_box("错误", "\n无法访问hosts管理器。\n")
msg_box.exec()
def open_hosts_file(self):
"""打开系统hosts文件"""
try:
# 获取hosts文件路径
hosts_path = os.path.join(os.environ['SystemRoot'], 'System32', 'drivers', 'etc', 'hosts')
# 检查文件是否存在
if os.path.exists(hosts_path):
# 使用操作系统默认程序打开hosts文件
if os.name == 'nt': # Windows
# 尝试以管理员权限打开记事本编辑hosts文件
try:
# 使用PowerShell以管理员身份启动记事本
subprocess.Popen(["powershell", "Start-Process", "notepad", hosts_path, "-Verb", "RunAs"])
except Exception as e:
# 如果失败,尝试直接打开
os.startfile(hosts_path)
else: # macOS 和 Linux
import subprocess
subprocess.call(['xdg-open', hosts_path])
else:
msg_box = self._create_message_box("错误", f"\nhosts文件不存在\n{hosts_path}\n")
msg_box.exec()
except Exception as e:
msg_box = self._create_message_box("错误", f"\n打开hosts文件时发生错误\n\n{str(e)}\n")
msg_box.exec()
def toggle_disable_auto_restore_hosts(self, checked):
"""切换禁用自动还原hosts的状态
Args:
checked: 是否禁用自动还原
"""
if hasattr(self.main_window, 'download_manager') and hasattr(self.main_window.download_manager, 'hosts_manager'):
try:
# 调用HostsManager的方法设置自动还原标志
result = self.main_window.download_manager.hosts_manager.set_auto_restore_disabled(checked)
if result:
# 同时更新内部配置,确保立即生效
if hasattr(self.main_window, 'config'):
self.main_window.config['disable_auto_restore_hosts'] = checked
# 显示成功提示
status = "禁用" if checked else "启用"
msg_box = self._create_message_box(
"设置已更新",
f"\n{status}关闭/重启时自动还原hosts。\n\n{'hosts将被保留' if checked else 'hosts将在关闭时自动还原'}\n"
)
msg_box.exec()
else:
# 如果设置失败,恢复复选框状态
self.disable_auto_restore_action.setChecked(not checked)
msg_box = self._create_message_box(
"设置失败",
"\n更新设置时发生错误,请稍后再试。\n"
)
msg_box.exec()
except Exception as e:
# 如果发生异常,恢复复选框状态
self.disable_auto_restore_action.setChecked(not checked)
msg_box = self._create_message_box(
"错误",
f"\n更新设置时发生异常:\n\n{str(e)}\n"
)
msg_box.exec()
else:
# 如果hosts管理器不可用恢复复选框状态
self.disable_auto_restore_action.setChecked(not checked)
msg_box = self._create_message_box(
"错误",
"\nhosts管理器不可用无法更新设置。\n"
)
msg_box.exec()
def _handle_pre_hash_toggle(self, checked):
"""处理禁用安装前哈希预检查的切换
Args:
checked: 是否禁用安装前哈希预检查
"""
if hasattr(self.main_window, 'config_manager'):
success = self.main_window.config_manager.toggle_disable_pre_hash_check(self.main_window, checked)
if not success:
# 如果操作失败,恢复复选框状态
self.disable_pre_hash_action.setChecked(not checked)
else:
# 如果配置管理器不可用,恢复复选框状态并显示错误
self.disable_pre_hash_action.setChecked(not checked)
self._create_message_box("错误", "\n配置管理器未初始化。\n").exec()
def switch_work_mode(self, mode):
"""切换工作模式
Args:
mode: 要切换的模式,"online""offline"
"""
# 检查主窗口是否有离线模式管理器
if not hasattr(self.main_window, 'offline_mode_manager'):
# 如果没有离线模式管理器,创建提示
msg_box = self._create_message_box(
"错误",
"\n离线模式管理器未初始化,无法切换工作模式。\n"
)
msg_box.exec()
# 恢复选择状态
self.online_mode_action.setChecked(True)
self.offline_mode_action.setChecked(False)
return
if mode == "offline":
# 尝试切换到离线模式
success = self.main_window.offline_mode_manager.set_offline_mode(True)
if not success:
# 如果切换失败,恢复选择状态
self.online_mode_action.setChecked(True)
self.offline_mode_action.setChecked(False)
return
# 更新配置
self.main_window.config["offline_mode"] = True
self.main_window.save_config(self.main_window.config)
# 在离线模式下启用开始安装按钮
if hasattr(self.main_window, 'window_manager'):
self.main_window.window_manager.change_window_state(self.main_window.window_manager.STATE_READY)
# 清除版本警告标志
if hasattr(self.main_window, 'version_warning'):
self.main_window.version_warning = False
# 显示提示
msg_box = self._create_message_box(
"模式已切换",
"\n已切换到离线模式。\n\n将使用本地补丁文件进行安装,不会从网络下载补丁。\n"
)
msg_box.exec()
else:
# 切换到在线模式
self.main_window.offline_mode_manager.set_offline_mode(False)
# 更新配置
self.main_window.config["offline_mode"] = False
self.main_window.save_config(self.main_window.config)
# 重新获取云端配置
if hasattr(self.main_window, 'fetch_cloud_config'):
self.main_window.fetch_cloud_config()
# 如果当前版本过低,设置版本警告标志
if hasattr(self.main_window, 'last_error_message') and self.main_window.last_error_message == "update_required":
# 设置版本警告标志
if hasattr(self.main_window, 'version_warning'):
self.main_window.version_warning = True
# 显示提示
msg_box = self._create_message_box(
"模式已切换",
"\n已切换到在线模式。\n\n将从网络下载补丁进行安装。\n"
)
msg_box.exec()