Files
WQ_GUI/src/gui/core/config_manager.py
2026-07-01 09:57:27 +08:00

177 lines
6.4 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.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
配置管理器
接管主窗口中所有配置读写逻辑:
- new_config() 清空所有面板配置
- load_config(file_path) 从 JSON 文件加载配置并回填面板
- save_config(file_path) 将当前配置保存为 JSON 文件
- get_current_config() 遍历 PanelFactory 收集配置(懒加载安全)
懒加载兼容原则:
- get_current_config() 仅遍历已加载面板,未加载面板返回空字典 {}
- 绝不为了拿配置而强行唤醒/渲染所有 Panel
- 如需全量配置(如保存),调用方应先执行 panel_factory.preload_all()
"""
import json
import os
from typing import Dict, Optional
from PyQt5.QtCore import QObject
from PyQt5.QtWidgets import QMessageBox, QFileDialog
from src.gui.core.event_bus import global_event_bus
class ConfigManager(QObject):
"""配置管理器。
用法::
cfg_mgr = ConfigManager(panel_factory, parent=self)
cfg_mgr.new_config() # 清空配置
cfg_mgr.load_config(path) # 加载 JSON
cfg_mgr.save_config(path) # 保存 JSON
config = cfg_mgr.get_current_config() # 收集当前配置
"""
def __init__(self, panel_factory, parent=None):
"""
Args:
panel_factory: PanelFactory 实例
parent: 父 QObject(用于弹窗定位)
"""
super().__init__(parent)
self._panel_factory = panel_factory
# ═══════════════════════════════════════════════════════════
# 公开 API
# ═══════════════════════════════════════════════════════════
def new_config(self):
"""清空所有面板配置(需用户确认)。"""
reply = QMessageBox.question(
self.parent(), "新建配置", "是否清空当前配置?",
QMessageBox.Yes | QMessageBox.No
)
if reply != QMessageBox.Yes:
return
for panel in self._panel_factory.get_loaded_panels().values():
if hasattr(panel, 'clear_config'):
panel.clear_config()
global_event_bus.publish('LogMessage', {
'message': '已清空配置',
'level': 'info',
})
def load_config(self, file_path: str = None):
"""从 JSON 文件加载配置并回填面板。
Args:
file_path: JSON 文件路径。若为 None,弹出文件选择对话框。
"""
if file_path is None:
file_path, _ = QFileDialog.getOpenFileName(
self.parent(), "加载配置", "",
"JSON Files (*.json);;All Files (*.*)"
)
if not file_path:
return
try:
with open(file_path, 'r', encoding='utf-8') as f:
config = json.load(f)
except Exception as e:
QMessageBox.critical(
self.parent(), "加载失败",
f"无法读取配置文件:\n{file_path}\n\n错误: {e}"
)
return
# ★ 验证 JSON 结构:必须是 dict 类型
if not isinstance(config, dict):
QMessageBox.critical(
self.parent(), "配置格式错误",
f"配置文件格式不正确(期望 JSON 对象,实际为 {type(config).__name__})。\n请确认选择了正确的配置文件。"
)
return
# 回填已加载面板
loaded_count = 0
for step_id, panel in self._panel_factory.get_loaded_panels().items():
if step_id in config and hasattr(panel, 'set_config'):
try:
panel.set_config(config[step_id])
loaded_count += 1
except Exception as e:
global_event_bus.publish('LogMessage', {
'message': f'[警告] 面板 {step_id} 加载配置失败: {e}',
'level': 'warning',
})
global_event_bus.publish('LogMessage', {
'message': f'已加载配置: {file_path}(回填 {loaded_count} 个面板)',
'level': 'info',
})
def save_config(self, file_path: str = None):
"""将当前配置保存为 JSON 文件。
注意:保存前会强制加载所有面板(preload_all),确保配置完整。
Args:
file_path: 目标 JSON 文件路径。若为 None,弹出保存对话框。
"""
if file_path is None:
file_path, _ = QFileDialog.getSaveFileName(
self.parent(), "保存配置", "config.json",
"JSON Files (*.json);;All Files (*.*)"
)
if not file_path:
return
# 保存前强制加载所有面板,确保配置完整
self._panel_factory.preload_all()
config = self.get_current_config()
try:
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2, ensure_ascii=False)
except Exception as e:
QMessageBox.critical(
self.parent(), "保存失败",
f"无法保存配置文件:\n{file_path}\n\n错误: {e}"
)
return
global_event_bus.publish('LogMessage', {
'message': f'已保存配置: {file_path}',
'level': 'info',
})
def get_current_config(self) -> Dict[str, dict]:
"""收集当前所有步骤的配置。
懒加载安全:仅遍历已加载面板,未加载面板返回空字典 {}。
绝不为了拿配置而强行唤醒/渲染所有 Panel。
Returns:
{step_id: panel_config_dict}
"""
config = {}
for step_id, panel in self._panel_factory.get_loaded_panels().items():
if hasattr(panel, 'get_config'):
try:
config[step_id] = panel.get_config()
except Exception as e:
config[step_id] = {}
global_event_bus.publish('LogMessage', {
'message': f'[警告] 面板 {step_id} 获取配置失败: {e}',
'level': 'warning',
})
return config