ModelCheckerForMaya/modelSanityChecker.py

457 lines
12 KiB
Python
Raw Permalink Normal View History

2024-10-01 19:54:21 +08:00
"""
module docstring here
"""
from PySide2 import QtCore, QtWidgets, QtGui
from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
from maya import cmds
from . import checker
from . import framelayout
try:
from importlib import reload
except ImportError:
# if python2, use build-in reload
pass
reload(framelayout)
reload(checker)
class Separator(QtWidgets.QWidget):
def __init__(self, category="", checkers=None):
super(Separator, self).__init__()
self.checkerWidgets = checkers
self.category = category
self.checkbox = QtWidgets.QCheckBox()
self.checkbox.setChecked(True)
self.checkbox.stateChanged.connect(self.checkboxToggle)
line = QtWidgets.QFrame()
line.setFrameShape(QtWidgets.QFrame.HLine)
line.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
label = QtWidgets.QLabel(" " + category)
font = QtGui.QFont()
font.setItalic(True)
font.setCapitalization(QtGui.QFont.AllUppercase)
font.setBold(True)
label.setFont(font)
layout = QtWidgets.QHBoxLayout()
layout.addWidget(self.checkbox)
layout.addWidget(line)
layout.addWidget(label)
# layout.setSpacing(0)
layout.setContentsMargins(2, 2, 2, 2)
self.setLayout(layout)
def checkboxToggle(self, *args):
state = args[0]
for w in self.checkerWidgets:
if self.category == w.checker.category:
if state == 2:
w.setEnabled(True)
else:
w.setEnabled(False)
class CheckerWidget(QtWidgets.QWidget):
def __init__(self, chk, parent, settings=None):
# type: (checker.BaseChecker)
super(CheckerWidget, self).__init__()
self.checker = chk
self.settings = settings
self.createUI()
def createUI(self):
layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.LeftToRight)
layout.setContentsMargins(2, 2, 2, 2)
layout.setSpacing(2)
self.frame = framelayout.FrameLayout(self.checker.name)
self.checkbox = QtWidgets.QCheckBox()
self.checkbox.stateChanged.connect(self.toggleEnable)
self.checkButton = QtWidgets.QPushButton("Check")
# self.checkButton.setSizePolicy(
# QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Expanding)
self.checkButton.clicked.connect(self.check)
self.fixButton = QtWidgets.QPushButton("Fix")
self.fixButton.clicked.connect(self.fix)
if self.checker.isFixable is not True:
self.fixButton.setEnabled(False)
self.selectAllButton = QtWidgets.QPushButton('Select')
self.selectAllButton.clicked.connect(self.selectAll)
buttonLayout = QtWidgets.QHBoxLayout()
buttonLayout.addWidget(self.checkButton)
buttonLayout.addWidget(self.fixButton)
buttonLayout.addWidget(self.selectAllButton)
self.errorList = QtWidgets.QListWidget()
self.errorList.itemClicked.connect(self.errorSelected)
self.frame.addWidget(self.errorList)
self.frame.addLayout(buttonLayout)
layout.addWidget(self.checkbox, alignment=QtCore.Qt.AlignTop)
layout.addWidget(self.frame)
self.setLayout(layout)
if self.checker.isEnabled:
self.setEnabled(True)
else:
self.setEnabled(False)
def setEnabled(self, state):
if state is True:
self.checkbox.setChecked(True)
self.frame.setEnabled(True)
self.checker.isEnabled = True
else:
self.checkbox.setChecked(False)
self.frame.setEnabled(False)
self.frame.collapse()
self.checker.isEnabled = False
def check(self, path=None, dummy=None):
if not self.checker.isEnabled:
return
root = self.parent().parent().parent().parent().rootLE.text()
if root != "":
path = root
if path is None:
sel = cmds.ls(sl=True, fl=True, long=True)
if not sel:
cmds.warning("Nothing is selected")
return
path = sel[0]
self.doCheck(path)
def toggleEnable(self, *args):
state = args[0]
if state == 2:
self.setEnabled(True)
else:
self.setEnabled(False)
def doCheck(self, obj):
# Clear list items
self.errorList.clear()
errs = self.checker.checkIt(obj, self.settings)
if errs:
for err in errs:
self.errorList.addItem(err)
if self.checker.isWarning:
self.frame.setStatusIcon("warning")
else:
self.frame.setStatusIcon("bad")
else:
self.frame.setStatusIcon("good")
def fix(self):
if not self.checker.isEnabled:
return
self.checker.fixIt()
# Re-check
self.check()
def errorSelected(self, *args):
"""
Select error components
"""
err = args[0]
if err.components is None:
cmds.select(err.longName, r=True)
else:
cmds.select(err.components, r=True)
def selectAll(self):
errs = [i.longName for i in self.checker.errors]
cmds.select(errs, r=True)
class Settings(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Settings, self).__init__(parent)
self.createUI()
def createUI(self):
self.maxFaceArea = QtWidgets.QLineEdit("0.000001")
layout = QtWidgets.QGridLayout()
layout.setAlignment(QtCore.Qt.AlignTop)
layout.addWidget(QtWidgets.QLabel("Max face area"), 0, 0)
layout.addWidget(self.maxFaceArea, 0, 1)
self.setLayout(layout)
def getSettings(self):
data = {
"maxFaceArea": float(self.maxFaceArea.text())
}
return data
class ModelSanityChecker(QtWidgets.QWidget):
""" Main sanity checker class """
def __init__(self, settings=None, parent=None):
super(ModelSanityChecker, self).__init__(parent)
checkerObjs = [i() for i in checker.CHECKERS]
checkerObjs.sort()
self.checkerWidgets = [CheckerWidget(i, self, settings) for i in checkerObjs]
self.separators = []
self.createUI()
def createUI(self):
"""
GUI method
"""
mainLayout = QtWidgets.QVBoxLayout()
mainLayout.setContentsMargins(0, 0, 0, 0)
scroll = QtWidgets.QScrollArea()
scroll.setWidgetResizable(1)
scrollLayout = QtWidgets.QVBoxLayout()
currentCategory = self.checkerWidgets[0].checker.category
sep = Separator(currentCategory, self.checkerWidgets)
self.separators.append(sep)
scrollLayout.addWidget(sep)
for widget in self.checkerWidgets:
if currentCategory != widget.checker.category:
cat = widget.checker.category
currentCategory = cat
sep = Separator(cat, self.checkerWidgets)
self.separators.append(sep)
scrollLayout.addWidget(sep)
scrollLayout.addWidget(widget)
content = QtWidgets.QWidget()
content.setLayout(scrollLayout)
scroll.setWidget(content)
self.rootLE = QtWidgets.QLineEdit()
setButton = QtWidgets.QPushButton("Set Selected")
setButton.clicked.connect(self.setSelected)
checkboxAll = QtWidgets.QCheckBox("Select All")
checkboxAll.setChecked(True)
checkboxAll.stateChanged.connect(self.selectAllToggle)
checkAllButton = QtWidgets.QPushButton("Check All")
checkAllButton.clicked.connect(self.checkAll)
fixAllButton = QtWidgets.QPushButton("Fix All")
fixAllButton.clicked.connect(self.fixAll)
rootLayout = QtWidgets.QHBoxLayout()
rootLayout.addWidget(self.rootLE)
rootLayout.addWidget(setButton)
mainLayout.addLayout(rootLayout)
mainLayout.addWidget(checkboxAll)
mainLayout.addWidget(scroll)
mainLayout.addWidget(checkAllButton)
mainLayout.addWidget(fixAllButton)
self.setLayout(mainLayout)
def selectAllToggle(self, *args):
state = args[0]
for s in self.separators:
if state == 2:
s.checkbox.setChecked(True)
else:
s.checkbox.setChecked(False)
def setSelected(self):
sel = cmds.ls(sl=True, fl=True, long=True)
if sel:
root = sel[0]
self.rootLE.setText(root)
def checkAll(self):
"""
Check all
"""
node = self.rootLE.text()
progDialog = QtWidgets.QProgressDialog(
"Now Checking...",
"Cancel",
0,
len(self.checkerWidgets),
self)
progDialog.setWindowTitle("Building library")
# progDialog.setWindowModality(QtCore.Qt.WindowModal)
progDialog.show()
for num, widget in enumerate(self.checkerWidgets):
checkerName = widget.checker.name
if widget.checker.isEnabled:
print("Running {} checker".format(checkerName))
if node == "":
widget.check()
else:
widget.check(node)
else:
print("{} checker is disabled. Skipped".format(checkerName))
progDialog.setValue(num+1)
progDialog.setLabel(QtWidgets.QLabel(
r'Now checking "{}"'.format(widget.checker.name)))
QtCore.QCoreApplication.processEvents()
progDialog.close()
def fixAll(self):
"""
Fix all
"""
for widget in self.checkerWidgets:
widget.fix()
class CentralWidget(QtWidgets.QWidget):
""" Central widget """
def __init__(self, parent=None):
""" Init """
super(CentralWidget, self).__init__(parent)
self.createUI()
self.layoutUI()
def createUI(self):
""" Crete widgets """
settings = Settings(self)
checker = ModelSanityChecker(settings, self)
self.tabWidget = QtWidgets.QTabWidget()
self.tabWidget.addTab(checker, "SanityChecker")
self.tabWidget.addTab(settings, "Settings")
def layoutUI(self):
""" Layout widgets """
mainLayout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.TopToBottom)
mainLayout.setContentsMargins(5, 5, 5, 5)
mainLayout.addWidget(self.tabWidget)
self.setLayout(mainLayout)
class MainWindow(MayaQWidgetDockableMixin, QtWidgets.QMainWindow):
"""
Main window
"""
def __init__(self, parent=None):
""" init """
super(MainWindow, self).__init__(parent)
self.thisObjectName = "sanityCheckerWindow"
self.winTitle = "Sanity Checker"
self.workspaceControlName = self.thisObjectName + "WorkspaceControl"
self.setObjectName(self.thisObjectName)
self.setWindowTitle(self.winTitle)
self.setWindowFlags(QtCore.Qt.Window)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
# Create and set central widget
self.cWidget = CentralWidget()
self.setCentralWidget(self.cWidget)
self.setupMenu()
def setupMenu(self):
""" Setup menu """
menu = self.menuBar()
# About
aboutAction = QtWidgets.QAction("&About", self)
aboutAction.setStatusTip('About this script')
aboutAction.triggered.connect(self.showAbout)
menu.addAction("File")
helpMenu = menu.addMenu("&Help")
helpMenu.addAction(aboutAction)
def showAbout(self):
"""
About message
"""
QtWidgets.QMessageBox.about(self, 'About ', 'test\n')
def run(self):
try:
cmds.deleteUI(self.workspaceControlName)
except RuntimeError:
pass
self.show(dockable=True)
cmds.workspaceControl(
self.workspaceControlName,
edit=True,
initialWidth=270,
minimumWidth=270,
dockToControl=['Outliner', 'right'])
self.raise_()
def main():
window = MainWindow()
window.run()
if __name__ == "__main__":
main()