Update
This commit is contained in:
@@ -0,0 +1,445 @@
|
||||
# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version. This library is distributed in the
|
||||
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import logging
|
||||
|
||||
from studiovendor.Qt import QtGui
|
||||
from studiovendor.Qt import QtCore
|
||||
|
||||
import studiolibrary
|
||||
|
||||
from studiolibrarymaya import basesavewidget
|
||||
from studiolibrarymaya import baseloadwidget
|
||||
|
||||
try:
|
||||
import mutils
|
||||
import mutils.gui
|
||||
import maya.cmds
|
||||
except ImportError as error:
|
||||
print(error)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseItemSignals(QtCore.QObject):
|
||||
""""""
|
||||
loadValueChanged = QtCore.Signal(object, object)
|
||||
|
||||
|
||||
class BaseItem(studiolibrary.LibraryItem):
|
||||
|
||||
_baseItemSignals = BaseItemSignals()
|
||||
|
||||
loadValueChanged = _baseItemSignals.loadValueChanged
|
||||
|
||||
"""Base class for anim, pose, mirror and sets transfer items."""
|
||||
SAVE_WIDGET_CLASS = basesavewidget.BaseSaveWidget
|
||||
LOAD_WIDGET_CLASS = baseloadwidget.BaseLoadWidget
|
||||
|
||||
TRANSFER_CLASS = None
|
||||
TRANSFER_BASENAME = ""
|
||||
|
||||
def createLoadWidget(self, parent=None):
|
||||
widget = self.LOAD_WIDGET_CLASS(item=self, parent=parent)
|
||||
return widget
|
||||
|
||||
@classmethod
|
||||
def createSaveWidget(cls, parent=None, item=None):
|
||||
item = item or cls()
|
||||
widget = cls.SAVE_WIDGET_CLASS(item=item, parent=parent)
|
||||
return widget
|
||||
|
||||
@classmethod
|
||||
def showSaveWidget(cls, libraryWindow=None, item=None):
|
||||
"""
|
||||
Overriding this method to set the destination location
|
||||
for the save widget.
|
||||
|
||||
Triggered when the user clicks the item action in the new item menu.
|
||||
|
||||
:type libraryWindow: studiolibrary.LibraryWindow
|
||||
:type item: studiolibrary.LibraryItem or None
|
||||
"""
|
||||
item = item or cls()
|
||||
widget = cls.SAVE_WIDGET_CLASS(item=item, parent=libraryWindow)
|
||||
|
||||
if libraryWindow:
|
||||
path = libraryWindow.selectedFolderPath()
|
||||
|
||||
widget.setFolderPath(path)
|
||||
widget.setLibraryWindow(libraryWindow)
|
||||
|
||||
libraryWindow.setCreateWidget(widget)
|
||||
libraryWindow.folderSelectionChanged.connect(widget.setFolderPath)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Initialise a new instance for the given path.
|
||||
|
||||
:type path: str
|
||||
:type args: list
|
||||
:type kwargs: dict
|
||||
"""
|
||||
self._transferObject = None
|
||||
self._currentLoadValues = {}
|
||||
|
||||
studiolibrary.LibraryItem.__init__(self, *args, **kwargs)
|
||||
|
||||
def emitLoadValueChanged(self, field, value):
|
||||
"""
|
||||
Emit the load value changed to be validated.
|
||||
|
||||
:type field: str
|
||||
:type value: object
|
||||
"""
|
||||
self.loadValueChanged.emit(field, value)
|
||||
|
||||
def namespaces(self):
|
||||
"""
|
||||
Return the namesapces for this item depending on the namespace option.
|
||||
|
||||
:rtype: list[str] or None
|
||||
"""
|
||||
return self.currentLoadValue("namespaces")
|
||||
|
||||
def namespaceOption(self):
|
||||
"""
|
||||
Return the namespace option for this item.
|
||||
|
||||
:rtype: NamespaceOption or None
|
||||
"""
|
||||
return self.currentLoadValue("namespaceOption")
|
||||
|
||||
def doubleClicked(self):
|
||||
"""
|
||||
This method is called when the user double clicks the item.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
self.loadFromCurrentValues()
|
||||
|
||||
def transferPath(self):
|
||||
"""
|
||||
Return the disc location to transfer path.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
if self.TRANSFER_BASENAME:
|
||||
return os.path.join(self.path(), self.TRANSFER_BASENAME)
|
||||
else:
|
||||
return self.path()
|
||||
|
||||
def transferObject(self):
|
||||
"""
|
||||
Return the transfer object used to read and write the data.
|
||||
|
||||
:rtype: mutils.TransferObject
|
||||
"""
|
||||
if not self._transferObject:
|
||||
path = self.transferPath()
|
||||
self._transferObject = self.TRANSFER_CLASS.fromPath(path)
|
||||
return self._transferObject
|
||||
|
||||
def currentLoadValue(self, name):
|
||||
"""
|
||||
Get the current field value for the given name.
|
||||
|
||||
:type name: str
|
||||
:rtype: object
|
||||
"""
|
||||
return self._currentLoadValues.get(name)
|
||||
|
||||
def setCurrentLoadValues(self, values):
|
||||
"""
|
||||
Set the current field values for the the item.
|
||||
|
||||
:type values: dict
|
||||
"""
|
||||
self._currentLoadValues = values
|
||||
|
||||
def loadFromCurrentValues(self):
|
||||
"""Load the mirror table using the settings for this item."""
|
||||
kwargs = self._currentLoadValues
|
||||
objects = maya.cmds.ls(selection=True) or []
|
||||
|
||||
try:
|
||||
self.load(objects=objects, **kwargs)
|
||||
except Exception as error:
|
||||
self.showErrorDialog("Item Error", str(error))
|
||||
raise
|
||||
|
||||
def contextMenu(self, menu, items=None):
|
||||
"""
|
||||
This method is called when the user right clicks on this item.
|
||||
|
||||
:type menu: QtWidgets.QMenu
|
||||
:type items: list[BaseItem]
|
||||
:rtype: None
|
||||
"""
|
||||
from studiolibrarymaya import setsmenu
|
||||
|
||||
action = setsmenu.selectContentAction(self, parent=menu)
|
||||
menu.addAction(action)
|
||||
menu.addSeparator()
|
||||
|
||||
subMenu = self.createSelectionSetsMenu(menu, enableSelectContent=False)
|
||||
menu.addMenu(subMenu)
|
||||
menu.addSeparator()
|
||||
|
||||
studiolibrary.LibraryItem.contextMenu(self, menu, items=items)
|
||||
|
||||
def showSelectionSetsMenu(self, **kwargs):
|
||||
"""
|
||||
Show the selection sets menu for this item at the cursor position.
|
||||
|
||||
:rtype: QtWidgets.QAction
|
||||
"""
|
||||
menu = self.createSelectionSetsMenu(**kwargs)
|
||||
position = QtGui.QCursor().pos()
|
||||
action = menu.exec_(position)
|
||||
return action
|
||||
|
||||
def createSelectionSetsMenu(self, parent=None, enableSelectContent=True):
|
||||
"""
|
||||
Get a new instance of the selection sets menu.
|
||||
|
||||
:type parent: QtWidgets.QWidget
|
||||
:type enableSelectContent: bool
|
||||
:rtype: QtWidgets.QMenu
|
||||
"""
|
||||
from . import setsmenu
|
||||
|
||||
parent = parent or self.libraryWindow()
|
||||
|
||||
namespaces = self.namespaces()
|
||||
|
||||
menu = setsmenu.SetsMenu(
|
||||
item=self,
|
||||
parent=parent,
|
||||
namespaces=namespaces,
|
||||
enableSelectContent=enableSelectContent,
|
||||
)
|
||||
|
||||
return menu
|
||||
|
||||
def selectContent(self, namespaces=None, **kwargs):
|
||||
"""
|
||||
Select the contents of this item in the Maya scene.
|
||||
|
||||
:type namespaces: list[str]
|
||||
"""
|
||||
namespaces = namespaces or self.namespaces()
|
||||
|
||||
kwargs = kwargs or mutils.selectionModifiers()
|
||||
|
||||
msg = "Select content: Item.selectContent(namespacea={0}, kwargs={1})"
|
||||
msg = msg.format(namespaces, kwargs)
|
||||
logger.debug(msg)
|
||||
|
||||
try:
|
||||
self.transferObject().select(namespaces=namespaces, **kwargs)
|
||||
except Exception as error:
|
||||
self.showErrorDialog("Item Error", str(error))
|
||||
raise
|
||||
|
||||
def loadSchema(self):
|
||||
"""
|
||||
Get schema used to load the item.
|
||||
|
||||
:rtype: list[dict]
|
||||
"""
|
||||
modified = self.itemData().get("modified")
|
||||
if modified:
|
||||
modified = studiolibrary.timeAgo(modified)
|
||||
|
||||
count = self.transferObject().objectCount()
|
||||
plural = "s" if count > 1 else ""
|
||||
contains = str(count) + " Object" + plural
|
||||
|
||||
return [
|
||||
{
|
||||
"name": "infoGroup",
|
||||
"title": "Info",
|
||||
"type": "group",
|
||||
"order": 1,
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"value": self.name(),
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"value": self.transferObject().owner(),
|
||||
},
|
||||
{
|
||||
"name": "created",
|
||||
"value": modified,
|
||||
},
|
||||
{
|
||||
"name": "contains",
|
||||
"value": contains,
|
||||
},
|
||||
{
|
||||
"name": "comment",
|
||||
"value": self.transferObject().description() or "No comment",
|
||||
},
|
||||
{
|
||||
"name": "namespaceGroup",
|
||||
"title": "Namespace",
|
||||
"type": "group",
|
||||
"order": 10,
|
||||
},
|
||||
{
|
||||
"name": "namespaceOption",
|
||||
"title": "",
|
||||
"type": "radio",
|
||||
"value": "From file",
|
||||
"items": ["From file", "From selection", "Use custom"],
|
||||
"persistent": True,
|
||||
"persistentKey": "BaseItem",
|
||||
},
|
||||
{
|
||||
"name": "namespaces",
|
||||
"title": "",
|
||||
"type": "tags",
|
||||
"value": [],
|
||||
"items": mutils.namespace.getAll(),
|
||||
"persistent": True,
|
||||
"label": {"visible": False},
|
||||
"persistentKey": "BaseItem",
|
||||
},
|
||||
]
|
||||
|
||||
def loadValidator(self, **values):
|
||||
"""
|
||||
Called when the load fields change.
|
||||
|
||||
:type values: dict
|
||||
"""
|
||||
namespaces = values.get("namespaces")
|
||||
namespaceOption = values.get("namespaceOption")
|
||||
|
||||
if namespaceOption == "From file":
|
||||
namespaces = self.transferObject().namespaces()
|
||||
elif namespaceOption == "From selection":
|
||||
namespaces = mutils.namespace.getFromSelection()
|
||||
|
||||
fieldChanged = values.get("fieldChanged")
|
||||
if fieldChanged == "namespaces":
|
||||
values["namespaceOption"] = "Use custom"
|
||||
else:
|
||||
values["namespaces"] = namespaces
|
||||
|
||||
self._currentLoadValues = values
|
||||
|
||||
return [
|
||||
{
|
||||
"name": "namespaces",
|
||||
"value": values.get("namespaces"),
|
||||
},
|
||||
{
|
||||
"name": "namespaceOption",
|
||||
"value": values.get("namespaceOption"),
|
||||
},
|
||||
]
|
||||
|
||||
def load(self, **kwargs):
|
||||
"""
|
||||
Load the data from the transfer object.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
logger.debug(u'Loading: {0}'.format(self.transferPath()))
|
||||
|
||||
self.transferObject().load(**kwargs)
|
||||
|
||||
logger.debug(u'Loading: {0}'.format(self.transferPath()))
|
||||
|
||||
def saveSchema(self):
|
||||
"""
|
||||
The base save schema.
|
||||
|
||||
:rtype: list[dict]
|
||||
"""
|
||||
return [
|
||||
{
|
||||
"name": "folder",
|
||||
"type": "path",
|
||||
"layout": "vertical",
|
||||
"visible": False,
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"layout": "vertical",
|
||||
},
|
||||
{
|
||||
"name": "comment",
|
||||
"type": "text",
|
||||
"layout": "vertical"
|
||||
},
|
||||
{
|
||||
"name": "objects",
|
||||
"type": "objects",
|
||||
"label": {"visible": False}
|
||||
},
|
||||
]
|
||||
|
||||
def saveValidator(self, **kwargs):
|
||||
"""
|
||||
The save validator is called when an input field has changed.
|
||||
|
||||
:type kwargs: dict
|
||||
:rtype: list[dict]
|
||||
"""
|
||||
fields = []
|
||||
|
||||
if not kwargs.get("folder"):
|
||||
fields.append({
|
||||
"name": "folder",
|
||||
"error": "No folder selected. Please select a destination folder.",
|
||||
})
|
||||
|
||||
if not kwargs.get("name"):
|
||||
fields.append({
|
||||
"name": "name",
|
||||
"error": "No name specified. Please set a name before saving.",
|
||||
})
|
||||
|
||||
selection = maya.cmds.ls(selection=True) or []
|
||||
msg = ""
|
||||
if not selection:
|
||||
msg = "No objects selected. Please select at least one object."
|
||||
|
||||
fields.append({
|
||||
"name": "objects",
|
||||
"value": selection,
|
||||
"error": msg,
|
||||
},
|
||||
)
|
||||
|
||||
return fields
|
||||
|
||||
def save(self, thumbnail="", **kwargs):
|
||||
"""
|
||||
Save all the given object data to the item path on disc.
|
||||
|
||||
:type thumbnail: str
|
||||
:type kwargs: dict
|
||||
"""
|
||||
# Copy the icon path to the given path
|
||||
if thumbnail:
|
||||
basename = os.path.basename(thumbnail)
|
||||
shutil.copyfile(thumbnail, self.path() + "/" + basename)
|
||||
Reference in New Issue
Block a user