742 lines
26 KiB
Python
742 lines
26 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Tool - Module Reload Tool
|
||
Provides module reloading functionality for the plugin, supporting hot updates
|
||
|
||
用法说明:
|
||
1. 在Maya中直接运行:
|
||
import scripts.ReloadModules
|
||
scripts.ReloadModules.main()
|
||
|
||
2. 从命令行重新加载所有模块:
|
||
import scripts.ReloadModules
|
||
scripts.ReloadModules.reload_all()
|
||
|
||
3. 重新加载特定模块:
|
||
import scripts.ReloadModules
|
||
scripts.ReloadModules.ModuleReloader.reload_module('module_name')
|
||
|
||
4. 在开发过程中使用:
|
||
- 当修改了代码后,运行此模块可以热更新所有更改
|
||
- 无需重启Maya即可测试新功能
|
||
- 支持UI和命令行两种方式
|
||
|
||
注意事项:
|
||
- 某些深度依赖的模块可能需要手动重启Maya
|
||
- 如果遇到导入错误,请检查模块路径是否正确
|
||
- 重新加载可能不会影响已经创建的对象实例
|
||
"""
|
||
|
||
import sys
|
||
import importlib
|
||
import os
|
||
import traceback
|
||
import shutil
|
||
from maya import cmds
|
||
|
||
# 设置工具路径
|
||
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
if TOOL_PATH not in sys.path:
|
||
sys.path.insert(0, TOOL_PATH)
|
||
|
||
# 设置脚本路径
|
||
SCRIPTS_PATH = os.path.dirname(os.path.abspath(__file__))
|
||
if SCRIPTS_PATH not in sys.path:
|
||
sys.path.insert(0, SCRIPTS_PATH)
|
||
|
||
# 导入主配置 - 多级尝试导入策略
|
||
def import_main_config():
|
||
"""尝试多种方式导入主配置文件"""
|
||
global TOOL_NAME, TOOL_VERSION, TOOL_AUTHOR, TOOL_PATH, SCRIPTS_PATH
|
||
global UI_PATH, STYLE_FILE, ICONS_PATH, ASSETS_PATH, DNA_FILE_PATH, Config
|
||
|
||
# 尝试直接导入
|
||
try:
|
||
import config
|
||
importlib.reload(config) # 确保获取最新配置
|
||
# 从主配置文件导入路径和设置
|
||
TOOL_NAME = config.TOOL_NAME
|
||
TOOL_VERSION = config.TOOL_VERSION
|
||
TOOL_AUTHOR = config.TOOL_AUTHOR
|
||
TOOL_PATH = config.TOOL_PATH
|
||
SCRIPTS_PATH = config.SCRIPTS_PATH
|
||
UI_PATH = config.UI_PATH
|
||
STYLE_FILE = config.STYLE_FILE
|
||
ICONS_PATH = config.ICONS_PATH
|
||
ASSETS_PATH = config.ASSETS_PATH
|
||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||
|
||
print(f"成功从主配置文件导入配置")
|
||
return True
|
||
except ImportError as e:
|
||
print(f"直接导入主配置文件失败: {str(e)}")
|
||
|
||
# 尝试从上级目录导入
|
||
parent_dir = os.path.dirname(TOOL_PATH)
|
||
if parent_dir not in sys.path:
|
||
sys.path.insert(0, parent_dir)
|
||
|
||
try:
|
||
import config
|
||
importlib.reload(config) # 确保获取最新配置
|
||
# 从主配置文件导入路径和设置
|
||
TOOL_NAME = config.TOOL_NAME
|
||
TOOL_VERSION = config.TOOL_VERSION
|
||
TOOL_AUTHOR = config.TOOL_AUTHOR
|
||
TOOL_PATH = config.TOOL_PATH
|
||
SCRIPTS_PATH = config.SCRIPTS_PATH
|
||
UI_PATH = config.UI_PATH
|
||
STYLE_FILE = config.STYLE_FILE
|
||
ICONS_PATH = config.ICONS_PATH
|
||
ASSETS_PATH = config.ASSETS_PATH
|
||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||
|
||
print(f"成功从上级目录导入主配置文件")
|
||
return True
|
||
except ImportError as e:
|
||
print(f"从上级目录导入主配置文件失败: {str(e)}")
|
||
if parent_dir in sys.path:
|
||
sys.path.remove(parent_dir)
|
||
|
||
return False
|
||
|
||
# 尝试导入主配置
|
||
if not import_main_config():
|
||
print("警告: 无法导入主配置文件,使用默认配置")
|
||
# 使用默认路径
|
||
TOOL_NAME = "Delos"
|
||
TOOL_VERSION = "Alpha v1.0.0"
|
||
TOOL_AUTHOR = "Virtuos Games"
|
||
TOOL_PATH = TOOL_PATH
|
||
UI_PATH = os.path.join(SCRIPTS_PATH, 'ui')
|
||
STYLE_FILE = os.path.join(SCRIPTS_PATH, 'ui', 'style.qss')
|
||
ICONS_PATH = os.path.join(TOOL_PATH, 'icons')
|
||
ASSETS_PATH = os.path.join(TOOL_PATH, 'assets')
|
||
DNA_FILE_PATH = os.path.join(TOOL_PATH, 'assets', 'dna')
|
||
|
||
# 尝试导入Config模块
|
||
try:
|
||
from scripts.utils import Config
|
||
except ImportError:
|
||
try:
|
||
from utils import Config
|
||
except ImportError:
|
||
try:
|
||
import Config
|
||
except ImportError:
|
||
print("警告: 无法导入Config模块")
|
||
Config = None
|
||
|
||
# 创建默认Config对象
|
||
class DefaultConfig:
|
||
# 使用TOOL_PATH而不是ROOT_DIR
|
||
DNA_CONFIG = {
|
||
'DNA_PATH': os.path.join(TOOL_PATH, 'assets', 'dna'),
|
||
'DNA_FILE_PATH': os.path.join(TOOL_PATH, 'assets', 'dna', 'default.dna'),
|
||
'DNA_VERSION': 'DNAv4',
|
||
'LOD_LEVELS': [0, 1, 2, 3, 4],
|
||
'DEFAULT_MESH_INDICES': [0],
|
||
'GUI_PATH': os.path.join(TOOL_PATH, 'ui'),
|
||
'ASSEMBLE_SCRIPT': os.path.join(TOOL_PATH, 'scripts', 'assemble.py')
|
||
}
|
||
DNA_LIB_PATHS = [
|
||
os.path.join(TOOL_PATH, 'lib'),
|
||
os.path.join(TOOL_PATH, 'lib', 'windows' if sys.platform == 'win32' else 'linux')
|
||
]
|
||
Config = DefaultConfig()
|
||
|
||
|
||
# 尝试导入 Qt 模块
|
||
# 首先尝试使用项目中的 Qt.py 兼容层
|
||
try:
|
||
# 添加父目录到路径中以确保可以导入 Qt.py
|
||
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
if parent_dir not in sys.path:
|
||
sys.path.append(parent_dir)
|
||
|
||
# 尝试导入 Qt.py
|
||
from Qt import QtWidgets, QtCore, QtGui
|
||
from Qt.QtCompat import wrapInstance
|
||
|
||
# 获取 Maya 主窗口
|
||
def getMayaMainWindow():
|
||
from maya import OpenMayaUI as omui
|
||
mainWindowPtr = omui.MQtUtil.mainWindow()
|
||
return wrapInstance(int(mainWindowPtr), QtWidgets.QWidget)
|
||
|
||
HAS_QT = True
|
||
print("Successfully imported Qt modules using Qt.py compatibility layer")
|
||
|
||
except ImportError:
|
||
# 如果无法导入 Qt.py,尝试直接导入 PySide2/PySide6
|
||
try:
|
||
from PySide2 import QtWidgets, QtCore, QtGui
|
||
from shiboken2 import wrapInstance
|
||
from maya import OpenMayaUI as omui
|
||
|
||
def getMayaMainWindow():
|
||
mainWindowPtr = omui.MQtUtil.mainWindow()
|
||
return wrapInstance(int(mainWindowPtr), QtWidgets.QWidget)
|
||
|
||
HAS_QT = True
|
||
print("Successfully imported Qt modules using PySide2")
|
||
|
||
except ImportError:
|
||
try:
|
||
from PySide6 import QtWidgets, QtCore, QtGui
|
||
from shiboken6 import wrapInstance
|
||
from maya import OpenMayaUI as omui
|
||
|
||
def getMayaMainWindow():
|
||
mainWindowPtr = omui.MQtUtil.mainWindow()
|
||
return wrapInstance(int(mainWindowPtr), QtWidgets.QWidget)
|
||
|
||
HAS_QT = True
|
||
print("Successfully imported Qt modules using PySide6")
|
||
|
||
except ImportError:
|
||
# 如果所有导入尝试都失败,设置标志并显示警告
|
||
HAS_QT = False
|
||
cmds.warning("Failed to import Qt modules. UI functionality will be limited to command line only.")
|
||
|
||
|
||
def clean_pycache(root_dir):
|
||
"""Delete all __pycache__ directories and .pyc files under the given root directory
|
||
|
||
Args:
|
||
root_dir (str): Root directory to search for __pycache__ folders and .pyc files
|
||
|
||
Returns:
|
||
int: Number of __pycache__ directories and .pyc files removed
|
||
"""
|
||
count = 0
|
||
try:
|
||
# 首先确保目录存在
|
||
if not os.path.exists(root_dir) or not os.path.isdir(root_dir):
|
||
print(f"Warning: Directory does not exist or is not a directory: {root_dir}")
|
||
return count
|
||
|
||
print(f"Cleaning __pycache__ in directory: {root_dir}")
|
||
|
||
# 收集所有需要删除的路径,避免在遍历时修改目录结构
|
||
pycache_dirs = []
|
||
pyc_files = []
|
||
|
||
# 首先收集所有 __pycache__ 目录和 .pyc 文件
|
||
for root, dirs, files in os.walk(root_dir):
|
||
# 收集 __pycache__ 目录
|
||
if "__pycache__" in dirs:
|
||
pycache_path = os.path.join(root, "__pycache__")
|
||
pycache_dirs.append(pycache_path)
|
||
|
||
# 收集 .pyc 文件
|
||
for file in files:
|
||
if file.endswith(".pyc"):
|
||
file_path = os.path.join(root, file)
|
||
pyc_files.append(file_path)
|
||
|
||
# 优先使用批处理命令删除 __pycache__ 目录(更可靠)
|
||
if os.name == 'nt': # Windows
|
||
# 创建临时批处理文件
|
||
temp_bat = os.path.join(os.environ.get('TEMP', '.'), 'clean_pycache_temp.bat')
|
||
with open(temp_bat, 'w') as f:
|
||
f.write('@echo off\n')
|
||
# 添加删除 __pycache__ 目录的命令
|
||
for pycache_path in pycache_dirs:
|
||
f.write(f'if exist "{pycache_path}" rd /s /q "{pycache_path}"\n')
|
||
# 添加删除 .pyc 文件的命令
|
||
for file_path in pyc_files:
|
||
f.write(f'if exist "{file_path}" del /f /q "{file_path}"\n')
|
||
|
||
# 执行批处理文件
|
||
os.system(f'"{temp_bat}"')
|
||
|
||
# 删除临时批处理文件
|
||
try:
|
||
os.remove(temp_bat)
|
||
except:
|
||
pass
|
||
|
||
# 验证是否删除成功
|
||
remaining_pycache = 0
|
||
for pycache_path in pycache_dirs:
|
||
if not os.path.exists(pycache_path):
|
||
count += 1
|
||
else:
|
||
remaining_pycache += 1
|
||
|
||
remaining_pyc = 0
|
||
for file_path in pyc_files:
|
||
if not os.path.exists(file_path):
|
||
count += 1
|
||
else:
|
||
remaining_pyc += 1
|
||
|
||
if remaining_pycache > 0 or remaining_pyc > 0:
|
||
print(f"Warning: {remaining_pycache} __pycache__ directories and {remaining_pyc} .pyc files could not be removed")
|
||
else: # Unix/Linux
|
||
# 使用系统命令删除 __pycache__ 目录
|
||
for pycache_path in pycache_dirs:
|
||
if os.system(f'rm -rf "{pycache_path}"') == 0:
|
||
print(f"Removed __pycache__ directory: {pycache_path}")
|
||
count += 1
|
||
else:
|
||
print(f"Failed to remove {pycache_path}")
|
||
|
||
# 使用系统命令删除 .pyc 文件
|
||
for file_path in pyc_files:
|
||
if os.system(f'rm -f "{file_path}"') == 0:
|
||
print(f"Removed .pyc file: {file_path}")
|
||
count += 1
|
||
else:
|
||
print(f"Failed to remove {file_path}")
|
||
|
||
except Exception as error:
|
||
print(f"Error cleaning __pycache__ directories: {str(error)}")
|
||
print(f"Removed {count} files/directories: {len(pycache_dirs)} __pycache__ directories and {len(pyc_files)} .pyc files")
|
||
traceback.print_exc()
|
||
|
||
return count
|
||
|
||
|
||
class ModuleReloader(object):
|
||
"""Class for reloading modules in the Plugin"""
|
||
|
||
@staticmethod
|
||
def get_package_modules(package_name):
|
||
"""
|
||
Get all modules in a package
|
||
|
||
Args:
|
||
package_name (str): Name of the package
|
||
|
||
Returns:
|
||
list: List of module names
|
||
"""
|
||
package_modules = []
|
||
try:
|
||
# 尝试导入包
|
||
package = importlib.import_module(package_name)
|
||
package_path = os.path.dirname(package.__file__)
|
||
|
||
# 遍历包目录查找模块
|
||
for root, dirs, files in os.walk(package_path):
|
||
for file in files:
|
||
if file.endswith('.py') and file != '__init__.py':
|
||
# 计算相对路径
|
||
rel_path = os.path.relpath(os.path.join(root, file), package_path)
|
||
# 转换为模块路径格式
|
||
module_path = os.path.splitext(rel_path)[0].replace(os.sep, '.')
|
||
# 构建完整模块名
|
||
module_name = f"{package_name}.{module_path}"
|
||
package_modules.append(module_name)
|
||
|
||
# 添加子包
|
||
for dir_name in dirs:
|
||
init_file = os.path.join(root, dir_name, '__init__.py')
|
||
if os.path.exists(init_file):
|
||
rel_path = os.path.relpath(os.path.join(root, dir_name), package_path)
|
||
module_name = f"{package_name}.{rel_path.replace(os.sep, '.')}"
|
||
package_modules.append(module_name)
|
||
|
||
return package_modules
|
||
except Exception as e:
|
||
print(f"错误: 无法导入包 {package_name}: {str(e)}")
|
||
traceback.print_exc()
|
||
return []
|
||
|
||
@staticmethod
|
||
def reload_module(module_name):
|
||
"""Reload a specific module
|
||
|
||
Args:
|
||
module_name (str): Name of the module to reload
|
||
|
||
Returns:
|
||
bool: True if successful, False otherwise
|
||
"""
|
||
try:
|
||
# 尝试导入模块
|
||
try:
|
||
module = __import__(module_name, fromlist=["*"])
|
||
except ImportError:
|
||
# 如果失败,尝试将点替换为斜杠
|
||
module_path = module_name.replace('.', '/')
|
||
if os.path.exists(os.path.join(TOOL_PATH, module_path + '.py')):
|
||
sys_path_modified = False
|
||
if TOOL_PATH not in sys.path:
|
||
sys.path.insert(0, TOOL_PATH)
|
||
sys_path_modified = True
|
||
|
||
module = __import__(module_name, fromlist=["*"])
|
||
|
||
if sys_path_modified:
|
||
sys.path.remove(TOOL_PATH)
|
||
else:
|
||
raise ImportError(f"Module {module_name} not found")
|
||
|
||
# 重新加载模块
|
||
importlib.reload(module)
|
||
|
||
print(f"成功重新加载模块: {module_name}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"重新加载模块 {module_name} 时出错: {str(e)}")
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
@classmethod
|
||
def reload_all_modules(cls):
|
||
"""
|
||
Reload all Plugin modules
|
||
|
||
Returns:
|
||
dict: Results of reloading each module
|
||
"""
|
||
# 首先声明全局变量
|
||
global TOOL_NAME, TOOL_VERSION, TOOL_AUTHOR, TOOL_PATH, SCRIPTS_PATH
|
||
global UI_PATH, STYLE_FILE, ICONS_PATH, ASSETS_PATH, DNA_FILE_PATH
|
||
|
||
results = {}
|
||
|
||
# 清理缓存文件
|
||
clean_pycache(TOOL_PATH)
|
||
|
||
# 首先尝试重新加载主配置文件
|
||
try:
|
||
# 尝试直接导入主配置
|
||
if 'config' in sys.modules:
|
||
config_module = sys.modules['config']
|
||
importlib.reload(config_module)
|
||
print("成功重新加载主配置文件")
|
||
results['config'] = True
|
||
|
||
TOOL_NAME = config_module.TOOL_NAME
|
||
TOOL_VERSION = config_module.TOOL_VERSION
|
||
TOOL_AUTHOR = config_module.TOOL_AUTHOR
|
||
TOOL_PATH = config_module.TOOL_PATH
|
||
SCRIPTS_PATH = config_module.SCRIPTS_PATH
|
||
UI_PATH = config_module.UI_PATH
|
||
STYLE_FILE = config_module.STYLE_FILE
|
||
ICONS_PATH = config_module.ICONS_PATH
|
||
ASSETS_PATH = config_module.ASSETS_PATH
|
||
DNA_FILE_PATH = config_module.DNA_FILE_PATH
|
||
else:
|
||
# 尝试重新导入
|
||
import_main_config()
|
||
results['config'] = True
|
||
except Exception as e:
|
||
print(f"重新加载主配置文件时出错: {str(e)}")
|
||
results['config'] = False
|
||
|
||
# 定义要重新加载的模块
|
||
modules_to_reload = [
|
||
"scripts.utils.Config", # 首先重新加载配置
|
||
"scripts.utils",
|
||
"scripts.ui",
|
||
"scripts.Main"
|
||
]
|
||
|
||
# 获取所有子模块
|
||
all_modules = []
|
||
for module in modules_to_reload:
|
||
all_modules.append(module)
|
||
try:
|
||
submodules = cls.get_package_modules(module)
|
||
if submodules:
|
||
all_modules.extend(submodules)
|
||
except Exception as e:
|
||
print(f"获取模块 {module} 的子模块时出错: {str(e)}")
|
||
|
||
# 去除重复项并排序
|
||
all_modules = sorted(list(set(all_modules)))
|
||
|
||
# 按照依赖关系对模块进行排序
|
||
# 确保配置模块先重新加载
|
||
priority_modules = []
|
||
normal_modules = []
|
||
|
||
for module in all_modules:
|
||
if "Config" in module or module.endswith(".config"):
|
||
priority_modules.append(module)
|
||
else:
|
||
normal_modules.append(module)
|
||
|
||
# 先重新加载优先级模块,然后是普通模块
|
||
for module in priority_modules + normal_modules:
|
||
results[module] = cls.reload_module(module)
|
||
|
||
return results
|
||
|
||
|
||
def reload_all():
|
||
"""Reload all Plugin modules and display results"""
|
||
print("\n" + "-"*50)
|
||
print("Reloading Plugin modules...")
|
||
print("-"*50)
|
||
|
||
# 获取插件根目录 - 使用config中定义的TOOL_PATH
|
||
try:
|
||
import config
|
||
TOOL_PATH = config.TOOL_PATH
|
||
except ImportError:
|
||
# 如果无法导入config,则使用相对路径
|
||
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
print(f"Plugin root directory: {TOOL_PATH}")
|
||
|
||
# 清理 __pycache__ 目录
|
||
print("Cleaning __pycache__ directories...")
|
||
pycache_count = clean_pycache(TOOL_PATH)
|
||
print(f"Removed {pycache_count} __pycache__ directories and .pyc files")
|
||
|
||
# Reload modules
|
||
results = ModuleReloader.reload_all_modules()
|
||
|
||
success_count = sum(1 for success in results.values() if success)
|
||
total_count = len(results)
|
||
|
||
print("\nReload Summary:")
|
||
print(f"Successfully reloaded {success_count} of {total_count} modules")
|
||
|
||
if success_count < total_count:
|
||
print("\nFailed modules:")
|
||
for module, success in results.items():
|
||
if not success:
|
||
print(f" - {module}")
|
||
|
||
print("-"*50)
|
||
return results
|
||
|
||
|
||
def show_reload_ui():
|
||
"""Show a UI for reloading modules"""
|
||
# 检查是否有Qt模块可用
|
||
if not 'HAS_QT' in globals() or not HAS_QT:
|
||
cmds.warning("Qt modules not available. Falling back to command line reload.")
|
||
return reload_all()
|
||
|
||
try:
|
||
# 创建对话框
|
||
dialog = QtWidgets.QDialog(getMayaMainWindow())
|
||
dialog.setWindowTitle("Plugin Reload UI")
|
||
dialog.setMinimumWidth(450)
|
||
dialog.setWindowFlags(dialog.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
|
||
|
||
# 创建布局
|
||
layout = QtWidgets.QVBoxLayout(dialog)
|
||
|
||
# 创建信息标签
|
||
info_label = QtWidgets.QLabel("Reload Plugin modules, no need to restart Maya.")
|
||
layout.addWidget(info_label)
|
||
|
||
# 创建模块选择区域
|
||
module_group = QtWidgets.QGroupBox("Select Modules to Reload")
|
||
module_layout = QtWidgets.QVBoxLayout(module_group)
|
||
|
||
# 创建全选复选框
|
||
all_modules_cb = QtWidgets.QCheckBox("All Modules")
|
||
all_modules_cb.setChecked(True)
|
||
module_layout.addWidget(all_modules_cb)
|
||
|
||
# 创建模块类别复选框
|
||
module_cbs = {}
|
||
module_categories = [
|
||
("Core Modules", [
|
||
"scripts",
|
||
"scripts.Main",
|
||
"scripts.ReloadModules"
|
||
]
|
||
),
|
||
("UI Modules", [
|
||
"scripts.ui",
|
||
"scripts.ui.toolbar",
|
||
"scripts.ui.geometry",
|
||
"scripts.ui.rigging",
|
||
"scripts.ui.behaviour",
|
||
"scripts.ui.definition"
|
||
]
|
||
),
|
||
("Utility Modules", [
|
||
"scripts.utils",
|
||
"scripts.utils.utils_toolbar",
|
||
"scripts.utils.utils_geometry",
|
||
"scripts.utils.utils_rigging",
|
||
"scripts.utils.utils_behaviour",
|
||
"scripts.utils.utils_definition"
|
||
]
|
||
),
|
||
("Config", ["config"])
|
||
]
|
||
for category, modules in module_categories:
|
||
category_cb = QtWidgets.QCheckBox(category)
|
||
category_cb.setChecked(True)
|
||
category_cb.setEnabled(False)
|
||
module_layout.addWidget(category_cb)
|
||
module_cbs[category] = (category_cb, modules)
|
||
|
||
# 全选/取消全选逻辑
|
||
def toggle_all_modules():
|
||
checked = all_modules_cb.isChecked()
|
||
for category, (cb, _) in module_cbs.items():
|
||
cb.setChecked(checked)
|
||
cb.setEnabled(not checked)
|
||
|
||
all_modules_cb.toggled.connect(toggle_all_modules)
|
||
|
||
layout.addWidget(module_group)
|
||
|
||
# 创建操作按钮区域
|
||
button_layout = QtWidgets.QHBoxLayout()
|
||
|
||
# 创建重载按钮
|
||
reload_button = QtWidgets.QPushButton("Reload Selected Modules")
|
||
reload_button.setMinimumHeight(30)
|
||
button_layout.addWidget(reload_button)
|
||
|
||
# 创建清理缓存按钮
|
||
clean_button = QtWidgets.QPushButton("Clean Caches Only")
|
||
clean_button.setMinimumHeight(30)
|
||
button_layout.addWidget(clean_button)
|
||
|
||
layout.addLayout(button_layout)
|
||
|
||
# 创建结果文本区域
|
||
results_text = QtWidgets.QTextEdit()
|
||
results_text.setReadOnly(True)
|
||
results_text.setMinimumHeight(300)
|
||
layout.addWidget(results_text)
|
||
|
||
# 创建关闭按钮
|
||
close_button = QtWidgets.QPushButton("Close")
|
||
close_button.setMinimumHeight(30)
|
||
close_button.clicked.connect(dialog.close)
|
||
layout.addWidget(close_button)
|
||
|
||
# 重载并更新UI的函数
|
||
def reload_and_update_ui(text_widget):
|
||
text_widget.clear()
|
||
text_widget.append("Reloading modules...\n")
|
||
|
||
# 获取插件根目录 - 使用config中定义的TOOL_PATH
|
||
try:
|
||
import config
|
||
TOOL_PATH = config.TOOL_PATH
|
||
except ImportError:
|
||
# 如果无法导入config,则使用相对路径
|
||
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
text_widget.append(f"Plugin root directory: {TOOL_PATH}")
|
||
|
||
# 清理 __pycache__ 目录
|
||
text_widget.append("Cleaning __pycache__ directories...")
|
||
pycache_count = clean_pycache(TOOL_PATH)
|
||
text_widget.append(f"Removed {pycache_count} __pycache__ directories and .pyc files\n")
|
||
|
||
# 确定要重载的模块
|
||
results = {}
|
||
|
||
if all_modules_cb.isChecked():
|
||
# 重载所有模块
|
||
results = ModuleReloader.reload_all_modules()
|
||
else:
|
||
# 重载选定的模块类别
|
||
selected_categories = []
|
||
for category, (cb, modules) in module_cbs.items():
|
||
if cb.isChecked():
|
||
selected_categories.extend(modules)
|
||
|
||
if not selected_categories:
|
||
text_widget.append("No module was selected, the operation was canceled.")
|
||
return
|
||
|
||
# 获取所有模块
|
||
all_modules = []
|
||
for package in selected_categories:
|
||
if package.startswith("scripts."):
|
||
all_modules.extend(ModuleReloader.get_package_modules(package))
|
||
else:
|
||
all_modules.append(package)
|
||
|
||
# 重载选定的模块
|
||
results = {}
|
||
for module in all_modules:
|
||
results[module] = ModuleReloader.reload_module(module)
|
||
|
||
# 更新UI显示结果
|
||
success_count = sum(1 for success in results.values() if success)
|
||
total_count = len(results)
|
||
|
||
text_widget.append(f"Successfully reloaded {success_count}/{total_count} modules\n")
|
||
|
||
# 显示成功重载的模块
|
||
text_widget.append("Successfully reloaded modules:")
|
||
for module, success in results.items():
|
||
if success:
|
||
text_widget.append(f" - {module}")
|
||
|
||
# 显示失败的模块(如果有)
|
||
if success_count < total_count:
|
||
text_widget.append("\nFailed to reload modules:")
|
||
for module, success in results.items():
|
||
if not success:
|
||
text_widget.append(f" - {module}")
|
||
|
||
# 提示用户重载完成
|
||
text_widget.append("\nReload operation completed!")
|
||
|
||
# 仅清理缓存的函数
|
||
def clean_cache_only(text_widget):
|
||
text_widget.clear()
|
||
text_widget.append("Cleaning caches only...\n")
|
||
|
||
# 获取插件根目录
|
||
try:
|
||
import config
|
||
TOOL_PATH = config.TOOL_PATH
|
||
except ImportError:
|
||
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
text_widget.append(f"Plugin root directory: {TOOL_PATH}")
|
||
|
||
# 清理 __pycache__ 目录
|
||
pycache_count = clean_pycache(TOOL_PATH)
|
||
text_widget.append(f"Removed {pycache_count} __pycache__ directories and .pyc files")
|
||
text_widget.append("\nCache cleaning operation completed!")
|
||
|
||
# 连接按钮信号
|
||
reload_button.clicked.connect(lambda: reload_and_update_ui(results_text))
|
||
clean_button.clicked.connect(lambda: clean_cache_only(results_text))
|
||
|
||
# 显示对话框
|
||
dialog.show()
|
||
|
||
except Exception as e:
|
||
traceback.print_exc()
|
||
cmds.warning(f"Failed to show UI: {str(e)}. Falling back to command line reload.")
|
||
return reload_all()
|
||
|
||
|
||
# Main function to be called from Maya
|
||
def main():
|
||
"""Main function to be called from Maya"""
|
||
try:
|
||
if HAS_QT:
|
||
show_reload_ui()
|
||
else:
|
||
reload_all()
|
||
|
||
print("Modules reloaded successfully!")
|
||
return True
|
||
except Exception as e:
|
||
print(f"Error during module reload: {str(e)}")
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
|
||
# Allow running this script directly
|
||
if __name__ == "__main__":
|
||
main()
|