refactor: implement UI code optimization and refactoring

This commit implements the comprehensive UI code refactoring plan to improve
code quality, reduce duplication, and enhance maintainability.

Phase 1: High Priority Improvements
- Create BaseDialog class to eliminate window centering code duplication
  across ProgressDialog, DeleteProgressWindow, LoginDialog, and
  UserSelectionDialog (~30 lines of duplicate code removed)
- Unify log color configuration with LogTheme class in gui/log_config.py
- Create permission check decorators (@require_admin, @require_permission,
  @require_user_type, @handle_errors)
- Update all dialog classes to use unified patterns

Phase 2: Architecture Improvements
- Create input validation framework (ValidationResult, Validator,
  ValidatedWidget classes)
- Implement StateManager with observer pattern for component state sharing
- Create unified ErrorHandler for consistent error handling
- Extract CheckboxTreeview into reusable component

New Modules:
- gui/widgets/base_dialog.py - Base dialog class with modal setup and centering
- gui/utils/decorators.py - Permission and error handling decorators
- gui/utils/error_handler.py - Unified error handling with user-friendly messages
- gui/utils/state_manager.py - State management with observer pattern
- gui/utils/validators.py - Input validation framework
- gui/material_validation/checkbox_treeview.py - Reusable checkbox table

Modified Files:
- gui/log_config.py - Added LogTheme class for centralized styling
- gui/widgets/log_text.py - Use LogTheme.COLORS
- gui/widgets/progress_dialog.py - Inherit from BaseDialog
- gui/widgets/delete_progress_window.py - Inherit from BaseDialog, use LogTheme
- gui/widgets/__init__.py - Add new exports, optional imports
- gui/login_dialog.py - Use unified centering pattern
- gui/user_selection_dialog.py - Use unified centering pattern
- gui/material_validation_tab.py - Import CheckboxTreeview from new module

Benefits:
- Reduced code duplication by ~200 lines
- Improved maintainability through centralized configuration
- Better abstraction with 5 new reusable base classes
- Enhanced type safety with type hints
- Future-proof theming support via LogTheme

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Misaka Server
2026-02-26 18:40:26 +08:00
parent 3a9c6f0978
commit f715cb97e3
16 changed files with 1735 additions and 313 deletions

159
gui/utils/decorators.py Normal file
View File

@@ -0,0 +1,159 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Decorators - GUI 装饰器集合
提供常用的 GUI 相关装饰器,用于权限检查、异常处理等
"""
from functools import wraps
from typing import Callable, Optional
try:
from auth.session_manager import SessionManager
except ImportError:
SessionManager = None
from tkinter import messagebox
def require_admin(func: Callable) -> Callable:
"""
装饰器:要求管理员权限
如果当前用户不是管理员,显示警告消息并阻止函数执行
Usage:
@require_admin
def _open_admin_panel(self):
# 只有管理员可以执行
pass
Args:
func: 被装饰的函数
Returns:
包装后的函数
"""
@wraps(func)
def wrapper(self, *args, **kwargs):
if SessionManager is None:
# 如果没有 SessionManager直接执行向后兼容
return func(self, *args, **kwargs)
session = SessionManager.get_instance()
if not session.is_admin():
messagebox.showwarning("权限不足", "此功能需要管理员权限")
return
return func(self, *args, **kwargs)
return wrapper
def require_permission(permission: str):
"""
装饰器:要求特定权限
如果当前用户缺少指定权限,显示警告消息并阻止函数执行
Usage:
@require_permission("delete_materials")
def _delete_materials(self):
# 只有具有 delete_materials 权限的用户可以执行
pass
Args:
permission: 所需的权限名称
Returns:
装饰器函数
"""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(self, *args, **kwargs):
if SessionManager is None:
# 如果没有 SessionManager直接执行向后兼容
return func(self, *args, **kwargs)
session = SessionManager.get_instance()
if not session.has_permission(permission):
messagebox.showwarning("权限不足", f"缺少权限: {permission}")
return
return func(self, *args, **kwargs)
return wrapper
return decorator
def require_user_type(user_type: str):
"""
装饰器:要求特定用户类型
如果当前用户不是指定类型,显示警告消息并阻止函数执行
Usage:
@require_user_type("Admin")
def _admin_function(self):
# 只有 Admin 类型用户可以执行
pass
Args:
user_type: 所需的用户类型
Returns:
装饰器函数
"""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(self, *args, **kwargs):
if SessionManager is None:
# 如果没有 SessionManager直接执行向后兼容
return func(self, *args, **kwargs)
session = SessionManager.get_instance()
current_user_type = session.get_current_user_type()
if current_user_type != user_type:
messagebox.showwarning(
"权限不足",
f"此功能仅限 {user_type} 用户使用"
)
return
return func(self, *args, **kwargs)
return wrapper
return decorator
def handle_errors(
show_user: bool = True,
default_return=None,
log_context: str = ""
):
"""
装饰器:统一错误处理
捕获函数中的异常并使用 ErrorHandler 进行处理
Usage:
@handle_errors(show_user=True, log_context="Deleting materials")
def _delete_materials(self):
# 可能抛出异常的操作
pass
Args:
show_user: 是否向用户显示错误消息
default_return: 发生异常时的默认返回值
log_context: 日志上下文信息
Returns:
装饰器函数
"""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(self, *args, **kwargs):
try:
return func(self, *args, **kwargs)
except Exception as e:
from gui.utils.error_handler import ErrorHandler
context = log_context or f"{func.__name__}"
ErrorHandler.handle(e, context, show_user)
return default_return
return wrapper
return decorator