Files
MetaFusion/Install.py
2025-05-02 00:14:28 +08:00

766 lines
27 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 -*-
#===================================== 1. Module Imports =====================================
import maya.OpenMayaUI as omui
import maya.cmds as cmds
import maya.mel as mel
import webbrowser
import sys
import os
# Import configuration module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
import config
try:
from PySide2 import QtCore, QtGui, QtWidgets
from shiboken2 import wrapInstance
print("Loading Qt and shiboken2 from PySide2")
except ImportError:
try:
from PySide6 import QtCore, QtGui, QtWidgets
from shiboken6 import wrapInstance
print("Loading Qt and shiboken6 from PySide6")
except ImportError:
try:
from PySide import QtCore, QtGui, QtWidgets
from shiboken import wrapInstance
print("Loading Qt and shiboken from PySide")
except ImportError as error:
print(f"Qt loading failed: {str(error)}")
QtCore = QtGui = QtWidgets = None
wrapInstance = None
# Use config directly instead of duplicating variables
# This ensures we always use the latest values from config
# and reduces maintenance overhead
TOOL_NAME = config.TOOL_NAME
TOOL_VERSION = config.TOOL_VERSION
TOOL_AUTHOR = config.TOOL_AUTHOR
TOOL_PATH = config.TOOL_PATH
UI_PATH = config.UI_PATH
SCRIPTS_PATH = config.SCRIPTS_PATH
ASSETS_PATH = config.ASSETS_PATH
ICONS_PATH = config.ICONS_PATH
PLUGINS_PATH = config.PLUGINS_PATH
PYDNA_PATH = config.PYDNA_PATH
SYSTEM_OS = config.SYSTEM_OS
MAYA_VERSION = config.MAYA_VERSION
PYVERSION_DIR = config.PYVERSION_DIR
DNA_FILE_PATH = config.DNA_FILE_PATH
DNA_IMG_PATH = config.DNA_IMG_PATH
STYLE_FILE = config.STYLE_FILE
TOOL_ICON = config.TOOL_ICON
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
TOOL_WSCL_NAME = config.TOOL_WSCL_NAME
TOOL_YEAR = config.TOOL_YEAR
TOOL_MOD_FILENAME = config.TOOL_MOD_FILENAME
TOOL_LANG = config.TOOL_LANG
TOOL_MAIN_SCRIPT = config.TOOL_MAIN_SCRIPT
TOOL_HELP_URL = config.TOOL_HELP_URL
print("=" * 50)
print(f"TOOL_NAME: {TOOL_NAME}")
print(f"TOOL_VERSION: {TOOL_VERSION}")
print(f"TOOL_YEAR: {TOOL_YEAR}")
print(f"SYSTEM_OS: {SYSTEM_OS}")
print(f"MAYA_VERSION: {MAYA_VERSION}")
print(f"TOOL_AUTHOR: {TOOL_AUTHOR}")
print(f"TOOL_LANG: {TOOL_LANG}")
print(f"PYVERSION_DIR: {PYVERSION_DIR}")
print(f"TOOL_WSCL_NAME: {TOOL_WSCL_NAME}")
print(f"TOOL_MOD_FILENAME: {TOOL_MOD_FILENAME}")
print(f"TOOL_HELP_URL: {TOOL_HELP_URL}")
print(f"TOOL_PATH: {TOOL_PATH}")
print(f"PLUGINS_PATH: {PLUGINS_PATH}")
print(f"PYDNA_PATH: {PYDNA_PATH}")
print(f"SCRIPTS_PATH: {SCRIPTS_PATH}")
print(f"TOOL_MAIN_SCRIPT: {TOOL_MAIN_SCRIPT}")
print(f"UI_PATH: {UI_PATH}")
print(f"STYLE_FILE: {STYLE_FILE}")
print(f"ICONS_PATH: {ICONS_PATH}")
print(f"TOOL_ICON: {TOOL_ICON}")
print(f"TOOL_COMMAND_ICON: {TOOL_COMMAND_ICON}")
print(f"ASSETS_PATH: {ASSETS_PATH}")
print(f"DNA_FILE_PATH: {DNA_FILE_PATH}")
print(f"DNA_IMG_PATH: {DNA_IMG_PATH}")
print("=" * 50)
#===================================== 3. Utility Functions =====================================
def maya_main_window():
"""Get Maya main window"""
main_window_ptr = omui.MQtUtil.mainWindow()
if main_window_ptr:
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
return None
def ensure_directory(directory_path):
"""Ensure directory exists"""
if directory_path and isinstance(directory_path, str):
if not os.path.exists(directory_path):
os.makedirs(directory_path)
print(f"Created directory: {directory_path}")
return directory_path
def get_maya_modules_dir():
"""Get Maya modules directory"""
maya_app_dir = cmds.internalVar(userAppDir=True)
if maya_app_dir and isinstance(maya_app_dir, str):
return ensure_directory(os.path.join(maya_app_dir, "modules"))
return None
#===================================== 4. UI Component Classes =====================================
class SetButton(QtWidgets.QPushButton):
"""Custom styled button for installation interface"""
def __init__(self, text):
super(SetButton, self).__init__(text)
#===================================== 5. Main Window Class =====================================
class InstallDialog(QtWidgets.QDialog):
def __init__(self, parent=maya_main_window()):
super(InstallDialog, self).__init__(parent)
self.load_stylesheet()
self.setup_ui()
def load_stylesheet(self):
try:
with open(STYLE_FILE, 'r', encoding='utf-8') as f:
style = f.read()
self.setStyleSheet(style)
except Exception as error:
print(f"Error loading stylesheet: {error}")
# Use a default style if the file can't be loaded
self.setStyleSheet("QDialog { background-color: #333333; color: #CCCCCC; }")
def setup_ui(self):
"""Initialize and setup UI components"""
self.setWindowTitle(f"{TOOL_NAME} Installation")
self.setFixedSize(220, 120)
self.setup_window_icon()
self.create_widgets()
self.create_layouts()
self.create_connections()
def setup_window_icon(self):
"""Setup window icon if available"""
if os.path.exists(TOOL_ICON):
self.setWindowIcon(QtGui.QIcon(TOOL_ICON))
else:
print(f"Warning: Icon file not found: {TOOL_ICON}")
#----------------- 5.1 UI Methods -----------------
def create_widgets(self):
self.new_shelf_toggle = QtWidgets.QCheckBox(f"{TOOL_NAME} Installation")
self.install_button = SetButton("Install " + TOOL_NAME)
self.uninstall_button = SetButton("Uninstall " + TOOL_NAME)
def create_layouts(self):
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setContentsMargins(10, 2, 10, 5)
main_layout.setSpacing(5)
header_layout = QtWidgets.QHBoxLayout()
header_layout.setSpacing(5)
welcome_label = QtWidgets.QLabel("Welcome to " + TOOL_NAME + "!")
welcome_label.setStyleSheet("font-size: 11px; padding: 0px; margin: 0px;")
header_layout.addWidget(welcome_label)
header_layout.addStretch()
main_layout.addLayout(header_layout)
main_layout.addWidget(self.install_button)
main_layout.addWidget(self.uninstall_button)
self.install_button.setFixedHeight(30)
self.uninstall_button.setFixedHeight(30)
def create_connections(self):
self.install_button.clicked.connect(self.install)
self.uninstall_button.clicked.connect(self.uninstall)
def create_styled_message_box(self, title, text):
msg_box = QtWidgets.QMessageBox(self)
msg_box.setWindowTitle(title)
msg_box.setText(text)
msg_box.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
# 自定义样式,去掉提示文字的边框
custom_style = self.styleSheet() + """
QMessageBox { background-color: #333333; color: #CCCCCC; }
QLabel { border: none; background-color: transparent; color: #CCCCCC; }
QPushButton { min-width: 80px; min-height: 24px; }
"""
msg_box.setStyleSheet(custom_style)
return msg_box
#----------------- 5.2 Event Handler Methods -----------------
def event(self, event):
if event.type() == QtCore.QEvent.EnterWhatsThisMode:
QtWidgets.QWhatsThis.leaveWhatsThisMode()
self.open_help_url()
return True
return QtWidgets.QDialog.event(self, event)
def closeEvent(self, event):
"""Handle window close event"""
try:
super(InstallDialog, self).closeEvent(event)
except Exception as error:
print(f"Error closing window: {error}")
event.accept()
def helpEvent(self, event):
self.open_help_url()
event.accept()
#----------------- 5.3 Utility Methods -----------------
def open_help_url(self):
webbrowser.open(TOOL_HELP_URL)
QtWidgets.QApplication.restoreOverrideCursor()
def get_script_path():
maya_script = mel.eval('getenv("MAYA_SCRIPT_NAME")')
if maya_script and os.path.exists(maya_script):
return os.path.dirname(maya_script)
for sys_path in sys.path:
install_path = os.path.join(sys_path, "install.py")
if os.path.exists(install_path):
return os.path.dirname(install_path)
return os.getcwd()
def get_maya_modules_dir(self):
"""Get Maya modules directory"""
# Try to get module directory from Maya environment variable
try:
maya_app_dir = mel.eval('getenv("MAYA_APP_DIR")')
if maya_app_dir:
modules_dir = os.path.join(maya_app_dir, "modules")
if not os.path.exists(modules_dir):
os.makedirs(modules_dir)
return modules_dir
except Exception as error:
print(f"Error getting Maya modules directory from environment: {error}")
# If environment variable is not available, use default path
user_home = os.path.expanduser("~")
maya_version = MAYA_VERSION
# Windows path
if SYSTEM_OS == "Windows":
modules_dir = os.path.join(user_home, "Documents", "maya", maya_version, "modules")
# Linux path
else:
modules_dir = os.path.join(user_home, "maya", maya_version, "modules")
# Make sure the path exists
if not os.path.exists(modules_dir):
try:
os.makedirs(modules_dir)
except Exception as error:
print(f"Error creating modules directory: {error}")
return modules_dir
#----------------- 5.4 Installation Methods -----------------
def install(self):
"""Handle install request with error handling"""
if not self._validate_paths():
return
msg_box = self.create_styled_message_box(
"Confirm Installation",
f"Are you sure you want to install {TOOL_NAME}?"
)
if msg_box.exec_() == QtWidgets.QMessageBox.Yes:
try:
self.install_tool()
self.close()
except Exception as error:
error_msg = f"Error during installation: {error}"
print(error_msg)
QtWidgets.QMessageBox.critical(self, "Error", error_msg)
def uninstall(self, *args):
"""Handle uninstall request"""
msg_box = self.create_styled_message_box(
"Confirm Uninstallation",
f"Are you sure you want to uninstall {TOOL_NAME}?"
)
if msg_box.exec_() == QtWidgets.QMessageBox.Yes:
try:
self.uninstall_tool()
self.close()
except Exception as error:
error_msg = f"Error during uninstallation: {error}"
print(error_msg)
QtWidgets.QMessageBox.critical(self, "Error", error_msg)
else:
print("Uninstallation cancelled")
def clean_pycache(self):
"""Clean __pycache__ directories and .pyc files"""
count = 0
try:
for root, dirs, files in os.walk(TOOL_PATH):
# Remove __pycache__ directories
if "__pycache__" in dirs:
pycache_path = os.path.join(root, "__pycache__")
try:
import shutil
shutil.rmtree(pycache_path)
print(f"Removed __pycache__ directory: {pycache_path}")
count += 1
except Exception as error:
print(f"Failed to remove {pycache_path}: {error}")
# Remove .pyc files
for file in files:
if file.endswith(".pyc"):
try:
os.remove(os.path.join(root, file))
print(f"Removed .pyc file: {os.path.join(root, file)}")
count += 1
except Exception as error:
print(f"Failed to remove {os.path.join(root, file)}: {error}")
except Exception as error:
print(f"Error cleaning __pycache__ directories: {error}")
return count
def create_mod_file(self):
"""Create or update Maya's .mod file"""
modules_dir = self.get_maya_modules_dir()
# Get all Maya versions and their corresponding Python versions
version_map = {
"2022": "python3",
"2023": "python397",
"2024": "python3108",
"2025": "python311"
}
# System mapping
os_paths = {
"win64": "Windows",
"linux": "Linux"
}
# Create mod file content
mod_content = f"""+ {TOOL_NAME} {TOOL_VERSION} {TOOL_PATH}
"""
# Add each Maya version's configuration
for maya_version, python_version in version_map.items():
# Add each operating system's configuration
for os_name, os_path in os_paths.items():
mod_content += f"""
if MAYA_VERSION == {maya_version} && PLATFORM == {os_name}
scripts: {SCRIPTS_PATH}
plug-ins: {os.path.join(PLUGINS_PATH, os_path)}
XBMLANGPATH+:={ICONS_PATH}
PATH+:={os.path.join(PLUGINS_PATH, os_path)}
PATH+:={os.path.join(PLUGINS_PATH, os_path, "pydna", python_version)}
PYTHONPATH+:={SCRIPTS_PATH}
PYTHONPATH+:={os.path.join(PLUGINS_PATH, os_path, "pydna", python_version)}
endif
"""
# Write mod file
mod_file_path = os.path.join(modules_dir, TOOL_MOD_FILENAME)
try:
with open(mod_file_path, "w", encoding="utf-8") as f:
f.write(mod_content)
print(f"Created mod file: {mod_file_path}")
except Exception as error:
print(f"Error creating mod file {mod_file_path}: {error}")
def uninstall_mod_file(self):
modules_dir = self.get_maya_modules_dir()
mod_file_path = os.path.join(modules_dir, TOOL_MOD_FILENAME)
if os.path.exists(mod_file_path):
try:
os.remove(mod_file_path)
print(f"{TOOL_NAME}.mod file deleted")
except Exception as error:
print(f"Error deleting {TOOL_NAME}.mod file: {error}")
def clean_existing_buttons(self):
if cmds.shelfLayout(TOOL_NAME, exists=True):
buttons = cmds.shelfLayout(TOOL_NAME, query=True, childArray=True) or []
for btn in buttons:
if cmds.shelfButton(btn, query=True, exists=True):
label = cmds.shelfButton(btn, query=True, label=True)
if label == TOOL_NAME:
cmds.deleteUI(btn)
print(f"Deleted existing {TOOL_NAME} button: {btn}")
def install_tool(self):
"""Install the tool to Maya"""
if not os.path.exists(SCRIPTS_PATH):
print(f"Error: Scripts path does not exist: {SCRIPTS_PATH}")
return
if not os.path.exists(TOOL_MAIN_SCRIPT):
print(f"Error: Main script file not found: {TOOL_MAIN_SCRIPT}")
return
# Clean __pycache__ directories
print("Cleaning __pycache__ directories...")
pycache_count = self.clean_pycache()
print(f"Removed {pycache_count} __pycache__ directories and .pyc files")
# Add scripts path to Python path
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
# Create shelf and button
self._create_shelf_button()
self.create_mod_file()
# 安装完成后不需要在这里切换到对应shelf因为在_create_shelf_button函数中已经处理了
print(f"Successfully created {TOOL_NAME} shelf and buttons")
self._show_install_success_message()
def _create_shelf_button(self):
"""Create shelf button for the tool"""
shelf_layout = mel.eval('$tmpVar=$gShelfTopLevel')
# Create shelf if not exists
if not cmds.shelfLayout(TOOL_NAME, exists=True):
cmds.shelfLayout(TOOL_NAME, parent=shelf_layout)
# Clean existing buttons
self.clean_existing_buttons()
# Create main button
icon_path = TOOL_ICON if os.path.exists(TOOL_ICON) else TOOL_COMMAND_ICON
command = self._get_shelf_button_command()
cmds.shelfButton(
parent=TOOL_NAME,
image1=icon_path,
label=TOOL_NAME,
command=command,
sourceType="python",
annotation=f"{TOOL_NAME} {TOOL_VERSION}",
noDefaultPopup=True,
style="iconOnly"
)
# Create reload modules button
reload_icon_path = os.path.join(ICONS_PATH, "reload.png")
if not os.path.exists(reload_icon_path):
reload_icon_path = icon_path # 如果没有专用图标,使用主图标
reload_command = self._get_reload_modules_command()
cmds.shelfButton(
parent=TOOL_NAME,
image1=reload_icon_path,
label="ReloadModules",
command=reload_command,
sourceType="python",
annotation=f"重新加载 {TOOL_NAME} 模块",
noDefaultPopup=True,
style="iconOnly"
)
# 自动切换到工具架
cmds.shelfTabLayout("ShelfLayout", edit=True, selectTab=TOOL_NAME)
def _get_reload_modules_command(self):
"""Get the command string for the reload modules button"""
return f"""
import sys
import os
import importlib
# 首先导入主配置文件
TOOL_PATH = r'{TOOL_PATH}'
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
try:
# 导入主配置文件
import config
importlib.reload(config)
# 使用主配置文件中的路径
if config.SCRIPTS_PATH not in sys.path:
sys.path.insert(0, config.SCRIPTS_PATH)
# 导入并运行重载模块脚本
import scripts.ReloadModules
importlib.reload(scripts.ReloadModules)
scripts.ReloadModules.main()
except ImportError:
# 备用方案:如果无法导入主配置,使用硬编码路径
SCRIPTS_PATH = r'{SCRIPTS_PATH}'
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
try:
import scripts.ReloadModules
importlib.reload(scripts.ReloadModules)
scripts.ReloadModules.main()
except Exception as error:
import maya.cmds as cmds
error_msg = f"Error reloading modules: {{str(error)}}"
print(error_msg)
cmds.warning(error_msg)
except Exception as error:
import maya.cmds as cmds
error_msg = f"Error reloading modules: {{str(error)}}"
print(error_msg)
cmds.warning(error_msg)
"""
def _get_shelf_button_command(self):
"""Get the command string for the shelf button"""
return f"""
import sys
import os
import importlib
# 首先导入主配置文件
TOOL_PATH = r'{TOOL_PATH}'
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
try:
# 导入主配置文件
import config
importlib.reload(config)
# 使用主配置文件中的路径
if config.SCRIPTS_PATH not in sys.path:
sys.path.insert(0, config.SCRIPTS_PATH)
# 尝试导入并运行主模块
try:
# 从scripts包导入Main
from scripts import Main
importlib.reload(Main)
Main.main()
except ImportError:
# 尝试直接导入Main
import Main
importlib.reload(Main)
Main.main()
except Exception as e:
import maya.cmds as cmds
error_msg = f"Error loading {TOOL_NAME}: {{str(e)}}"
print(error_msg)
cmds.warning(error_msg)
print(f"Scripts path: {{config.SCRIPTS_PATH}}")
print("sys.path:", sys.path)
print(f"Contents of Scripts folder: {{os.listdir(config.SCRIPTS_PATH)}}")
except ImportError:
# 备用方案:如果无法导入主配置,使用硬编码路径
SCRIPTS_PATH = r'{SCRIPTS_PATH}'
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
try:
# 尝试从scripts包导入Main
from scripts import Main
importlib.reload(Main)
Main.main()
except ImportError:
# 尝试直接导入Main
try:
import Main
importlib.reload(Main)
Main.main()
except Exception as e:
import maya.cmds as cmds
error_msg = f"Error loading {TOOL_NAME}: {{str(e)}}"
print(error_msg)
cmds.warning(error_msg)
print(f"Scripts path: {{SCRIPTS_PATH}}")
print("sys.path:", sys.path)
print(f"Contents of Scripts folder: {{os.listdir(SCRIPTS_PATH)}}")
except Exception as e:
import maya.cmds as cmds
error_msg = f"Error loading {TOOL_NAME}: {{str(e)}}"
print(error_msg)
cmds.warning(error_msg)
"""
def _get_reload_modules_command(self):
"""Get the command string for the reload modules button"""
return f"""
import sys
import os
import importlib
# Set tool path
TOOL_PATH = r'{TOOL_PATH}'
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
# Set scripts path
SCRIPTS_PATH = r'{SCRIPTS_PATH}'
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
# Try to import and reload modules
try:
# Import ReloadModules directly
from scripts import ReloadModules
importlib.reload(ReloadModules)
ReloadModules.show_reload_ui()
except Exception as e:
import maya.cmds as cmds
error_msg = f"Error loading ReloadModules: {{str(e)}}"
print(error_msg)
cmds.warning(error_msg)
print(f"Scripts path: {{SCRIPTS_PATH}}")
print("sys.path:", sys.path)
"""
def uninstall_tool(self):
"""Uninstall the tool from Maya"""
window_name = f"{TOOL_NAME}Window"
dock_name = f"{TOOL_NAME}WindowDock"
shelf_file = f"shelf_{TOOL_NAME}.mel"
# Clean __pycache__ directories
print("Cleaning __pycache__ directories...")
pycache_count = self.clean_pycache()
print(f"Removed {pycache_count} __pycache__ directories and .pyc files")
if cmds.window(window_name, exists=True):
try:
cmds.deleteUI(window_name)
except Exception as error:
print(f"Error closing {TOOL_NAME} window: {error}")
if cmds.dockControl(dock_name, exists=True):
try:
cmds.deleteUI(dock_name)
except Exception as error:
print(f"Error closing docked {TOOL_NAME} window: {error}")
self.uninstall_mod_file()
# Get the current shelf before removing it
current_shelf = cmds.shelfTabLayout("ShelfLayout", query=True, selectTab=True)
# Delete Shelves and Buttons
if cmds.shelfLayout(TOOL_NAME, exists=True):
try:
cmds.deleteUI(TOOL_NAME, layout=True)
except Exception as error:
print(f"Error deleting {TOOL_NAME} shelf: {error}")
self._clean_all_shelf_buttons()
# Remove from Python path
if SCRIPTS_PATH in sys.path:
sys.path.remove(SCRIPTS_PATH)
# Deleting Shelf Files
shelf_path = os.path.join(
cmds.internalVar(userAppDir=True),
cmds.about(version=True),
"prefs",
"shelves",
f"shelf_{TOOL_NAME}.mel"
)
if os.path.exists(shelf_path):
try:
os.remove(shelf_path)
except Exception as error:
print(f"Error deleting shelf file: {error}")
# If the current tool shelf is a deleted tool shelf, switch to another tool shelf
if current_shelf == TOOL_NAME:
shelves = cmds.shelfTabLayout("ShelfLayout", query=True, childArray=True)
if shelves and len(shelves) > 0:
cmds.shelfTabLayout("ShelfLayout", edit=True, selectTab=shelves[0])
self._show_uninstall_success_message()
def _clean_all_shelf_buttons(self):
"""Clean up all shelf buttons related to the tool"""
all_shelves = cmds.shelfTabLayout("ShelfLayout", query=True, childArray=True) or []
for shelf in all_shelves:
shelf_buttons = cmds.shelfLayout(shelf, query=True, childArray=True) or []
for btn in shelf_buttons:
if cmds.shelfButton(btn, query=True, exists=True):
if cmds.shelfButton(btn, query=True, label=True) == TOOL_NAME:
cmds.deleteUI(btn)
def _show_uninstall_success_message(self):
"""Show uninstallation success message"""
msg_box = QtWidgets.QMessageBox(self)
msg_box.setWindowTitle("Uninstallation Successful")
msg_box.setText(f"{TOOL_NAME} has been successfully uninstalled!")
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
msg_box.setWindowIcon(QtGui.QIcon(TOOL_ICON))
msg_box.setStyleSheet(self.styleSheet())
msg_box.exec_()
def _show_install_success_message(self):
msg_box = QtWidgets.QMessageBox(self)
msg_box.setWindowTitle("Installation Successful")
msg_box.setText(f"{TOOL_NAME} has been successfully installed!")
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
msg_box.setWindowIcon(QtGui.QIcon(TOOL_ICON))
msg_box.setStyleSheet(self.styleSheet())
msg_box.exec_()
def _validate_paths(self):
"""Validate all required paths exist"""
paths = {
"Root": TOOL_PATH,
"Scripts": SCRIPTS_PATH,
"Icons": ICONS_PATH
}
for name, path in paths.items():
if not os.path.exists(path):
error_msg = f"Error: {name} path does not exist: {path}"
print(error_msg)
QtWidgets.QMessageBox.critical(self, "Error", error_msg)
return False
return True
def _log(self, message, error=False):
"""Log messages with timestamp"""
from datetime import datetime
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
log_message = f"[{timestamp}] {message}"
print(log_message)
if error:
QtWidgets.QMessageBox.critical(self, "Error", message)
def _load_mel_shelf(self):
"""Load mel shelf file with error handling"""
try:
mel.eval(f'loadNewShelf "shelf_{TOOL_NAME}.mel"')
except Exception as error:
self._log(f"Error loading shelf file: {error}", error=True)
#===================================== 6. Main Function =====================================
def main():
"""Main entry point for the installer"""
try:
dialog = InstallDialog()
dialog.show()
except Exception as error:
print(f"Error launching installer: {error}")
return -1
return dialog
if __name__ == "__main__":
main()