mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'develop' into enhancement/AY-4914_Move-Harmony-client-code
This commit is contained in:
commit
14bd1e9cf5
421 changed files with 3275 additions and 2807 deletions
|
|
@ -56,9 +56,12 @@ MOVED_ADDON_MILESTONE_VERSIONS = {
|
|||
"flame": VersionInfo(0, 2, 0),
|
||||
"harmony": VersionInfo(0, 2, 0),
|
||||
"max": VersionInfo(0, 2, 0),
|
||||
"photoshop": VersionInfo(0, 2, 0),
|
||||
"traypublisher": VersionInfo(0, 2, 0),
|
||||
"tvpaint": VersionInfo(0, 2, 0),
|
||||
"maya": VersionInfo(0, 2, 0),
|
||||
"nuke": VersionInfo(0, 2, 0),
|
||||
"resolve": VersionInfo(0, 2, 0),
|
||||
"substancepainter": VersionInfo(0, 2, 0),
|
||||
}
|
||||
|
||||
|
|
@ -1331,7 +1334,7 @@ class TrayAddonsManager(AddonsManager):
|
|||
self.doubleclick_callback = None
|
||||
|
||||
def add_doubleclick_callback(self, addon, callback):
|
||||
"""Register doubleclick callbacks on tray icon.
|
||||
"""Register double-click callbacks on tray icon.
|
||||
|
||||
Currently, there is no way how to determine which is launched. Name of
|
||||
callback can be defined with `doubleclick_callback` attribute.
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
from .addon import ResolveAddon
|
||||
|
||||
|
||||
__all__ = (
|
||||
"ResolveAddon",
|
||||
)
|
||||
|
|
@ -39,8 +39,8 @@ from ayon_core.lib import (
|
|||
EnumDef,
|
||||
is_in_tests,
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib_rendersettings import RenderSettings
|
||||
from ayon_core.hosts.maya.api.lib import get_attr_in_layer
|
||||
from ayon_maya.api.lib_rendersettings import RenderSettings
|
||||
from ayon_maya.api.lib import get_attr_in_layer
|
||||
|
||||
from openpype_modules.deadline import abstract_submit_deadline
|
||||
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
__version__ = "0.1.10"
|
||||
__version__ = "0.1.12"
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import pyblish.api
|
|||
from ayon_core.lib import filter_profiles
|
||||
from ayon_core.pipeline.publish import (
|
||||
PublishValidationError,
|
||||
OptionalPyblishPluginMixin,
|
||||
get_current_host_name,
|
||||
OptionalPyblishPluginMixin
|
||||
)
|
||||
from ayon_core.pipeline import get_current_host_name
|
||||
|
||||
|
||||
class ValidateVersion(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin):
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@ from ayon_core.tools.utils.lib import format_version
|
|||
from .products_model import (
|
||||
PRODUCT_ID_ROLE,
|
||||
VERSION_NAME_EDIT_ROLE,
|
||||
VERSION_STATUS_NAME_ROLE,
|
||||
VERSION_STATUS_SHORT_ROLE,
|
||||
VERSION_STATUS_COLOR_ROLE,
|
||||
VERSION_ID_ROLE,
|
||||
PRODUCT_IN_SCENE_ROLE,
|
||||
ACTIVE_SITE_ICON_ROLE,
|
||||
|
|
@ -205,57 +202,6 @@ class LoadedInSceneDelegate(QtWidgets.QStyledItemDelegate):
|
|||
option.palette.setBrush(QtGui.QPalette.Text, color)
|
||||
|
||||
|
||||
class StatusDelegate(QtWidgets.QStyledItemDelegate):
|
||||
"""Delegate showing status name and short name."""
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
if option.widget:
|
||||
style = option.widget.style()
|
||||
else:
|
||||
style = QtWidgets.QApplication.style()
|
||||
|
||||
style.drawControl(
|
||||
QtWidgets.QCommonStyle.CE_ItemViewItem,
|
||||
option,
|
||||
painter,
|
||||
option.widget
|
||||
)
|
||||
|
||||
painter.save()
|
||||
|
||||
text_rect = style.subElementRect(
|
||||
QtWidgets.QCommonStyle.SE_ItemViewItemText,
|
||||
option
|
||||
)
|
||||
text_margin = style.proxy().pixelMetric(
|
||||
QtWidgets.QCommonStyle.PM_FocusFrameHMargin,
|
||||
option,
|
||||
option.widget
|
||||
) + 1
|
||||
padded_text_rect = text_rect.adjusted(
|
||||
text_margin, 0, - text_margin, 0
|
||||
)
|
||||
|
||||
fm = QtGui.QFontMetrics(option.font)
|
||||
text = index.data(VERSION_STATUS_NAME_ROLE)
|
||||
if padded_text_rect.width() < fm.width(text):
|
||||
text = index.data(VERSION_STATUS_SHORT_ROLE)
|
||||
|
||||
status_color = index.data(VERSION_STATUS_COLOR_ROLE)
|
||||
fg_color = QtGui.QColor(status_color)
|
||||
pen = painter.pen()
|
||||
pen.setColor(fg_color)
|
||||
painter.setPen(pen)
|
||||
|
||||
painter.drawText(
|
||||
padded_text_rect,
|
||||
option.displayAlignment,
|
||||
text
|
||||
)
|
||||
|
||||
painter.restore()
|
||||
|
||||
|
||||
class SiteSyncDelegate(QtWidgets.QStyledItemDelegate):
|
||||
"""Paints icons and downloaded representation ration for both sites."""
|
||||
|
||||
|
|
|
|||
|
|
@ -25,18 +25,19 @@ VERSION_PUBLISH_TIME_ROLE = QtCore.Qt.UserRole + 14
|
|||
VERSION_STATUS_NAME_ROLE = QtCore.Qt.UserRole + 15
|
||||
VERSION_STATUS_SHORT_ROLE = QtCore.Qt.UserRole + 16
|
||||
VERSION_STATUS_COLOR_ROLE = QtCore.Qt.UserRole + 17
|
||||
VERSION_AUTHOR_ROLE = QtCore.Qt.UserRole + 18
|
||||
VERSION_FRAME_RANGE_ROLE = QtCore.Qt.UserRole + 19
|
||||
VERSION_DURATION_ROLE = QtCore.Qt.UserRole + 20
|
||||
VERSION_HANDLES_ROLE = QtCore.Qt.UserRole + 21
|
||||
VERSION_STEP_ROLE = QtCore.Qt.UserRole + 22
|
||||
VERSION_AVAILABLE_ROLE = QtCore.Qt.UserRole + 23
|
||||
VERSION_THUMBNAIL_ID_ROLE = QtCore.Qt.UserRole + 24
|
||||
ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 25
|
||||
REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 26
|
||||
REPRESENTATIONS_COUNT_ROLE = QtCore.Qt.UserRole + 27
|
||||
SYNC_ACTIVE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 28
|
||||
SYNC_REMOTE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 29
|
||||
VERSION_STATUS_ICON_ROLE = QtCore.Qt.UserRole + 18
|
||||
VERSION_AUTHOR_ROLE = QtCore.Qt.UserRole + 19
|
||||
VERSION_FRAME_RANGE_ROLE = QtCore.Qt.UserRole + 20
|
||||
VERSION_DURATION_ROLE = QtCore.Qt.UserRole + 21
|
||||
VERSION_HANDLES_ROLE = QtCore.Qt.UserRole + 22
|
||||
VERSION_STEP_ROLE = QtCore.Qt.UserRole + 23
|
||||
VERSION_AVAILABLE_ROLE = QtCore.Qt.UserRole + 24
|
||||
VERSION_THUMBNAIL_ID_ROLE = QtCore.Qt.UserRole + 25
|
||||
ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 26
|
||||
REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 27
|
||||
REPRESENTATIONS_COUNT_ROLE = QtCore.Qt.UserRole + 28
|
||||
SYNC_ACTIVE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 29
|
||||
SYNC_REMOTE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 30
|
||||
|
||||
|
||||
class ProductsModel(QtGui.QStandardItemModel):
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from ayon_core.tools.utils import (
|
|||
RecursiveSortFilterProxyModel,
|
||||
DeselectableTreeView,
|
||||
)
|
||||
from ayon_core.tools.utils.delegates import PrettyTimeDelegate
|
||||
from ayon_core.tools.utils.delegates import PrettyTimeDelegate, StatusDelegate
|
||||
|
||||
from .products_model import (
|
||||
ProductsModel,
|
||||
|
|
@ -17,12 +17,15 @@ from .products_model import (
|
|||
FOLDER_ID_ROLE,
|
||||
PRODUCT_ID_ROLE,
|
||||
VERSION_ID_ROLE,
|
||||
VERSION_STATUS_NAME_ROLE,
|
||||
VERSION_STATUS_SHORT_ROLE,
|
||||
VERSION_STATUS_COLOR_ROLE,
|
||||
VERSION_STATUS_ICON_ROLE,
|
||||
VERSION_THUMBNAIL_ID_ROLE,
|
||||
)
|
||||
from .products_delegates import (
|
||||
VersionDelegate,
|
||||
LoadedInSceneDelegate,
|
||||
StatusDelegate,
|
||||
SiteSyncDelegate,
|
||||
)
|
||||
from .actions_utils import show_actions_menu
|
||||
|
|
@ -131,7 +134,12 @@ class ProductsWidget(QtWidgets.QWidget):
|
|||
|
||||
version_delegate = VersionDelegate()
|
||||
time_delegate = PrettyTimeDelegate()
|
||||
status_delegate = StatusDelegate()
|
||||
status_delegate = StatusDelegate(
|
||||
VERSION_STATUS_NAME_ROLE,
|
||||
VERSION_STATUS_SHORT_ROLE,
|
||||
VERSION_STATUS_COLOR_ROLE,
|
||||
VERSION_STATUS_ICON_ROLE,
|
||||
)
|
||||
in_scene_delegate = LoadedInSceneDelegate()
|
||||
sitesync_delegate = SiteSyncDelegate()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import ayon_api
|
||||
|
||||
from ayon_core.lib.events import QueuedEventSystem
|
||||
from ayon_core.host import ILoadHost
|
||||
from ayon_core.host import HostBase
|
||||
from ayon_core.pipeline import (
|
||||
registered_host,
|
||||
get_current_context,
|
||||
)
|
||||
from ayon_core.tools.common_models import HierarchyModel
|
||||
from ayon_core.tools.common_models import HierarchyModel, ProjectsModel
|
||||
|
||||
from .models import SiteSyncModel
|
||||
from .models import SiteSyncModel, ContainersModel
|
||||
|
||||
|
||||
class SceneInventoryController:
|
||||
|
|
@ -28,11 +28,16 @@ class SceneInventoryController:
|
|||
self._current_folder_id = None
|
||||
self._current_folder_set = False
|
||||
|
||||
self._containers_model = ContainersModel(self)
|
||||
self._sitesync_model = SiteSyncModel(self)
|
||||
# Switch dialog requirements
|
||||
self._hierarchy_model = HierarchyModel(self)
|
||||
self._projects_model = ProjectsModel(self)
|
||||
self._event_system = self._create_event_system()
|
||||
|
||||
def get_host(self) -> HostBase:
|
||||
return self._host
|
||||
|
||||
def emit_event(self, topic, data=None, source=None):
|
||||
if data is None:
|
||||
data = {}
|
||||
|
|
@ -47,6 +52,7 @@ class SceneInventoryController:
|
|||
self._current_folder_id = None
|
||||
self._current_folder_set = False
|
||||
|
||||
self._containers_model.reset()
|
||||
self._sitesync_model.reset()
|
||||
self._hierarchy_model.reset()
|
||||
|
||||
|
|
@ -80,13 +86,32 @@ class SceneInventoryController:
|
|||
self._current_folder_set = True
|
||||
return self._current_folder_id
|
||||
|
||||
def get_project_status_items(self):
|
||||
project_name = self.get_current_project_name()
|
||||
return self._projects_model.get_project_status_items(
|
||||
project_name, None
|
||||
)
|
||||
|
||||
# Containers methods
|
||||
def get_containers(self):
|
||||
host = self._host
|
||||
if isinstance(host, ILoadHost):
|
||||
return list(host.get_containers())
|
||||
elif hasattr(host, "ls"):
|
||||
return list(host.ls())
|
||||
return []
|
||||
return self._containers_model.get_containers()
|
||||
|
||||
def get_containers_by_item_ids(self, item_ids):
|
||||
return self._containers_model.get_containers_by_item_ids(item_ids)
|
||||
|
||||
def get_container_items(self):
|
||||
return self._containers_model.get_container_items()
|
||||
|
||||
def get_container_items_by_id(self, item_ids):
|
||||
return self._containers_model.get_container_items_by_id(item_ids)
|
||||
|
||||
def get_representation_info_items(self, representation_ids):
|
||||
return self._containers_model.get_representation_info_items(
|
||||
representation_ids
|
||||
)
|
||||
|
||||
def get_version_items(self, product_ids):
|
||||
return self._containers_model.get_version_items(product_ids)
|
||||
|
||||
# Site Sync methods
|
||||
def is_sitesync_enabled(self):
|
||||
|
|
|
|||
|
|
@ -1,38 +1,10 @@
|
|||
import numbers
|
||||
|
||||
import ayon_api
|
||||
|
||||
from ayon_core.pipeline import HeroVersionType
|
||||
from ayon_core.tools.utils.models import TreeModel
|
||||
from ayon_core.tools.utils.lib import format_version
|
||||
|
||||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
|
||||
from .model import VERSION_LABEL_ROLE
|
||||
|
||||
|
||||
class VersionDelegate(QtWidgets.QStyledItemDelegate):
|
||||
"""A delegate that display version integer formatted as version string."""
|
||||
|
||||
version_changed = QtCore.Signal()
|
||||
first_run = False
|
||||
lock = False
|
||||
|
||||
def __init__(self, controller, *args, **kwargs):
|
||||
self._controller = controller
|
||||
super(VersionDelegate, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_project_name(self):
|
||||
return self._controller.get_current_project_name()
|
||||
|
||||
def displayText(self, value, locale):
|
||||
if isinstance(value, HeroVersionType):
|
||||
return format_version(value)
|
||||
if not isinstance(value, numbers.Integral):
|
||||
# For cases where no version is resolved like NOT FOUND cases
|
||||
# where a representation might not exist in current database
|
||||
return
|
||||
|
||||
return format_version(value)
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
fg_color = index.data(QtCore.Qt.ForegroundRole)
|
||||
if fg_color:
|
||||
|
|
@ -44,7 +16,7 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate):
|
|||
fg_color = None
|
||||
|
||||
if not fg_color:
|
||||
return super(VersionDelegate, self).paint(painter, option, index)
|
||||
return super().paint(painter, option, index)
|
||||
|
||||
if option.widget:
|
||||
style = option.widget.style()
|
||||
|
|
@ -60,9 +32,7 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate):
|
|||
|
||||
painter.save()
|
||||
|
||||
text = self.displayText(
|
||||
index.data(QtCore.Qt.DisplayRole), option.locale
|
||||
)
|
||||
text = index.data(VERSION_LABEL_ROLE)
|
||||
pen = painter.pen()
|
||||
pen.setColor(fg_color)
|
||||
painter.setPen(pen)
|
||||
|
|
@ -82,77 +52,3 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate):
|
|||
)
|
||||
|
||||
painter.restore()
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
item = index.data(TreeModel.ItemRole)
|
||||
if item.get("isGroup") or item.get("isMerged"):
|
||||
return
|
||||
|
||||
editor = QtWidgets.QComboBox(parent)
|
||||
|
||||
def commit_data():
|
||||
if not self.first_run:
|
||||
self.commitData.emit(editor) # Update model data
|
||||
self.version_changed.emit() # Display model data
|
||||
editor.currentIndexChanged.connect(commit_data)
|
||||
|
||||
self.first_run = True
|
||||
self.lock = False
|
||||
|
||||
return editor
|
||||
|
||||
def setEditorData(self, editor, index):
|
||||
if self.lock:
|
||||
# Only set editor data once per delegation
|
||||
return
|
||||
|
||||
editor.clear()
|
||||
|
||||
# Current value of the index
|
||||
item = index.data(TreeModel.ItemRole)
|
||||
value = index.data(QtCore.Qt.DisplayRole)
|
||||
|
||||
project_name = self.get_project_name()
|
||||
# Add all available versions to the editor
|
||||
product_id = item["version_entity"]["productId"]
|
||||
version_entities = list(sorted(
|
||||
ayon_api.get_versions(
|
||||
project_name, product_ids={product_id}, active=True
|
||||
),
|
||||
key=lambda item: abs(item["version"])
|
||||
))
|
||||
|
||||
selected = None
|
||||
items = []
|
||||
is_hero_version = value < 0
|
||||
for version_entity in version_entities:
|
||||
version = version_entity["version"]
|
||||
label = format_version(version)
|
||||
item = QtGui.QStandardItem(label)
|
||||
item.setData(version_entity, QtCore.Qt.UserRole)
|
||||
items.append(item)
|
||||
|
||||
if (
|
||||
version == value
|
||||
or is_hero_version and version < 0
|
||||
):
|
||||
selected = item
|
||||
|
||||
# Reverse items so latest versions be upper
|
||||
items.reverse()
|
||||
for item in items:
|
||||
editor.model().appendRow(item)
|
||||
|
||||
index = 0
|
||||
if selected:
|
||||
index = selected.row()
|
||||
|
||||
# Will trigger index-change signal
|
||||
editor.setCurrentIndex(index)
|
||||
self.first_run = False
|
||||
self.lock = True
|
||||
|
||||
def setModelData(self, editor, model, index):
|
||||
"""Apply the integer version back in the model"""
|
||||
version = editor.itemData(editor.currentIndex())
|
||||
model.setData(index, version["name"])
|
||||
|
|
|
|||
|
|
@ -1,57 +1,113 @@
|
|||
import re
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from collections import defaultdict
|
||||
import collections
|
||||
|
||||
import ayon_api
|
||||
from qtpy import QtCore, QtGui
|
||||
import qtawesome
|
||||
|
||||
from ayon_core.pipeline import (
|
||||
get_current_project_name,
|
||||
HeroVersionType,
|
||||
)
|
||||
from ayon_core.style import get_default_entity_icon_color
|
||||
from ayon_core.tools.utils import get_qt_icon
|
||||
from ayon_core.tools.utils.models import TreeModel, Item
|
||||
from ayon_core.tools.utils.lib import format_version
|
||||
|
||||
ITEM_ID_ROLE = QtCore.Qt.UserRole + 1
|
||||
NAME_COLOR_ROLE = QtCore.Qt.UserRole + 2
|
||||
COUNT_ROLE = QtCore.Qt.UserRole + 3
|
||||
IS_CONTAINER_ITEM_ROLE = QtCore.Qt.UserRole + 4
|
||||
VERSION_IS_LATEST_ROLE = QtCore.Qt.UserRole + 5
|
||||
VERSION_IS_HERO_ROLE = QtCore.Qt.UserRole + 6
|
||||
VERSION_LABEL_ROLE = QtCore.Qt.UserRole + 7
|
||||
VERSION_COLOR_ROLE = QtCore.Qt.UserRole + 8
|
||||
STATUS_NAME_ROLE = QtCore.Qt.UserRole + 9
|
||||
STATUS_COLOR_ROLE = QtCore.Qt.UserRole + 10
|
||||
STATUS_SHORT_ROLE = QtCore.Qt.UserRole + 11
|
||||
STATUS_ICON_ROLE = QtCore.Qt.UserRole + 12
|
||||
PRODUCT_ID_ROLE = QtCore.Qt.UserRole + 13
|
||||
PRODUCT_TYPE_ROLE = QtCore.Qt.UserRole + 14
|
||||
PRODUCT_TYPE_ICON_ROLE = QtCore.Qt.UserRole + 15
|
||||
PRODUCT_GROUP_NAME_ROLE = QtCore.Qt.UserRole + 16
|
||||
PRODUCT_GROUP_ICON_ROLE = QtCore.Qt.UserRole + 17
|
||||
LOADER_NAME_ROLE = QtCore.Qt.UserRole + 18
|
||||
OBJECT_NAME_ROLE = QtCore.Qt.UserRole + 19
|
||||
ACTIVE_SITE_PROGRESS_ROLE = QtCore.Qt.UserRole + 20
|
||||
REMOTE_SITE_PROGRESS_ROLE = QtCore.Qt.UserRole + 21
|
||||
ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 22
|
||||
REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 23
|
||||
# This value hold unique value of container that should be used to identify
|
||||
# containers inbetween refresh.
|
||||
ITEM_UNIQUE_NAME_ROLE = QtCore.Qt.UserRole + 24
|
||||
|
||||
|
||||
def walk_hierarchy(node):
|
||||
"""Recursively yield group node."""
|
||||
for child in node.children():
|
||||
if child.get("isGroupNode"):
|
||||
yield child
|
||||
|
||||
for _child in walk_hierarchy(child):
|
||||
yield _child
|
||||
|
||||
|
||||
class InventoryModel(TreeModel):
|
||||
class InventoryModel(QtGui.QStandardItemModel):
|
||||
"""The model for the inventory"""
|
||||
|
||||
Columns = [
|
||||
column_labels = [
|
||||
"Name",
|
||||
"version",
|
||||
"count",
|
||||
"productType",
|
||||
"group",
|
||||
"loader",
|
||||
"objectName",
|
||||
"active_site",
|
||||
"remote_site",
|
||||
"Version",
|
||||
"Status",
|
||||
"Count",
|
||||
"Product type",
|
||||
"Group",
|
||||
"Loader",
|
||||
"Object name",
|
||||
"Active site",
|
||||
"Remote site",
|
||||
]
|
||||
active_site_col = Columns.index("active_site")
|
||||
remote_site_col = Columns.index("remote_site")
|
||||
name_col = column_labels.index("Name")
|
||||
version_col = column_labels.index("Version")
|
||||
status_col = column_labels.index("Status")
|
||||
count_col = column_labels.index("Count")
|
||||
product_type_col = column_labels.index("Product type")
|
||||
product_group_col = column_labels.index("Group")
|
||||
loader_col = column_labels.index("Loader")
|
||||
object_name_col = column_labels.index("Object name")
|
||||
active_site_col = column_labels.index("Active site")
|
||||
remote_site_col = column_labels.index("Remote site")
|
||||
display_role_by_column = {
|
||||
name_col: QtCore.Qt.DisplayRole,
|
||||
version_col: VERSION_LABEL_ROLE,
|
||||
status_col: STATUS_NAME_ROLE,
|
||||
count_col: COUNT_ROLE,
|
||||
product_type_col: PRODUCT_TYPE_ROLE,
|
||||
product_group_col: PRODUCT_GROUP_NAME_ROLE,
|
||||
loader_col: LOADER_NAME_ROLE,
|
||||
object_name_col: OBJECT_NAME_ROLE,
|
||||
active_site_col: ACTIVE_SITE_PROGRESS_ROLE,
|
||||
remote_site_col: REMOTE_SITE_PROGRESS_ROLE,
|
||||
}
|
||||
decoration_role_by_column = {
|
||||
name_col: QtCore.Qt.DecorationRole,
|
||||
product_type_col: PRODUCT_TYPE_ICON_ROLE,
|
||||
product_group_col: PRODUCT_GROUP_ICON_ROLE,
|
||||
active_site_col: ACTIVE_SITE_ICON_ROLE,
|
||||
remote_site_col: REMOTE_SITE_ICON_ROLE,
|
||||
}
|
||||
foreground_role_by_column = {
|
||||
name_col: NAME_COLOR_ROLE,
|
||||
version_col: VERSION_COLOR_ROLE,
|
||||
status_col: STATUS_COLOR_ROLE
|
||||
}
|
||||
width_by_column = {
|
||||
name_col: 250,
|
||||
version_col: 55,
|
||||
status_col: 100,
|
||||
count_col: 55,
|
||||
product_type_col: 150,
|
||||
product_group_col: 120,
|
||||
loader_col: 150,
|
||||
}
|
||||
|
||||
OUTDATED_COLOR = QtGui.QColor(235, 30, 30)
|
||||
CHILD_OUTDATED_COLOR = QtGui.QColor(200, 160, 30)
|
||||
GRAYOUT_COLOR = QtGui.QColor(160, 160, 160)
|
||||
|
||||
UniqueRole = QtCore.Qt.UserRole + 2 # unique label role
|
||||
|
||||
def __init__(self, controller, parent=None):
|
||||
super(InventoryModel, self).__init__(parent)
|
||||
super().__init__(parent)
|
||||
|
||||
self.setColumnCount(len(self.column_labels))
|
||||
for idx, label in enumerate(self.column_labels):
|
||||
self.setHeaderData(idx, QtCore.Qt.Horizontal, label)
|
||||
|
||||
self.log = logging.getLogger(self.__class__.__name__)
|
||||
|
||||
self._controller = controller
|
||||
|
|
@ -60,103 +116,217 @@ class InventoryModel(TreeModel):
|
|||
|
||||
self._default_icon_color = get_default_entity_icon_color()
|
||||
|
||||
site_icons = self._controller.get_site_provider_icons()
|
||||
|
||||
self._site_icons = {
|
||||
provider: get_qt_icon(icon_def)
|
||||
for provider, icon_def in site_icons.items()
|
||||
}
|
||||
|
||||
def outdated(self, item):
|
||||
return item.get("isOutdated", True)
|
||||
|
||||
def refresh(self, selected=None):
|
||||
"""Refresh the model"""
|
||||
# for debugging or testing, injecting items from outside
|
||||
container_items = self._controller.get_container_items()
|
||||
|
||||
self._clear_items()
|
||||
|
||||
items_by_repre_id = {}
|
||||
for container_item in container_items:
|
||||
# if (
|
||||
# selected is not None
|
||||
# and container_item.item_id not in selected
|
||||
# ):
|
||||
# continue
|
||||
repre_id = container_item.representation_id
|
||||
items = items_by_repre_id.setdefault(repre_id, [])
|
||||
items.append(container_item)
|
||||
|
||||
repre_id = set(items_by_repre_id.keys())
|
||||
repre_info_by_id = self._controller.get_representation_info_items(
|
||||
repre_id
|
||||
)
|
||||
product_ids = {
|
||||
repre_info.product_id
|
||||
for repre_info in repre_info_by_id.values()
|
||||
}
|
||||
version_items_by_product_id = self._controller.get_version_items(
|
||||
product_ids
|
||||
)
|
||||
# SiteSync addon information
|
||||
progress_by_id = self._controller.get_representations_site_progress(
|
||||
repre_id
|
||||
)
|
||||
sites_info = self._controller.get_sites_information()
|
||||
site_icons = {
|
||||
provider: get_qt_icon(icon_def)
|
||||
for provider, icon_def in (
|
||||
self._controller.get_site_provider_icons().items()
|
||||
)
|
||||
}
|
||||
status_items_by_name = {
|
||||
status_item.name: status_item
|
||||
for status_item in self._controller.get_project_status_items()
|
||||
}
|
||||
|
||||
group_item_icon = qtawesome.icon(
|
||||
"fa.folder", color=self._default_icon_color
|
||||
)
|
||||
valid_item_icon = qtawesome.icon(
|
||||
"fa.file-o", color=self._default_icon_color
|
||||
)
|
||||
invalid_item_icon = qtawesome.icon(
|
||||
"fa.exclamation-circle", color=self._default_icon_color
|
||||
)
|
||||
group_icon = qtawesome.icon(
|
||||
"fa.object-group", color=self._default_icon_color
|
||||
)
|
||||
product_type_icon = qtawesome.icon(
|
||||
"fa.folder", color="#0091B2"
|
||||
)
|
||||
group_item_font = QtGui.QFont()
|
||||
group_item_font.setBold(True)
|
||||
|
||||
active_site_icon = site_icons.get(sites_info["active_site_provider"])
|
||||
remote_site_icon = site_icons.get(sites_info["remote_site_provider"])
|
||||
|
||||
root_item = self.invisibleRootItem()
|
||||
|
||||
group_items = []
|
||||
for repre_id, container_items in items_by_repre_id.items():
|
||||
repre_info = repre_info_by_id[repre_id]
|
||||
version_label = "N/A"
|
||||
version_color = None
|
||||
is_latest = False
|
||||
is_hero = False
|
||||
status_name = None
|
||||
status_color = None
|
||||
status_short = None
|
||||
if not repre_info.is_valid:
|
||||
group_name = "< Entity N/A >"
|
||||
item_icon = invalid_item_icon
|
||||
|
||||
else:
|
||||
group_name = "{}_{}: ({})".format(
|
||||
repre_info.folder_path.rsplit("/")[-1],
|
||||
repre_info.product_name,
|
||||
repre_info.representation_name
|
||||
)
|
||||
item_icon = valid_item_icon
|
||||
|
||||
version_items = (
|
||||
version_items_by_product_id[repre_info.product_id]
|
||||
)
|
||||
version_item = version_items[repre_info.version_id]
|
||||
version_label = format_version(version_item.version)
|
||||
is_hero = version_item.version < 0
|
||||
is_latest = version_item.is_latest
|
||||
if not is_latest:
|
||||
version_color = self.OUTDATED_COLOR
|
||||
status_name = version_item.status
|
||||
status_item = status_items_by_name.get(status_name)
|
||||
if status_item:
|
||||
status_short = status_item.short
|
||||
status_color = status_item.color
|
||||
|
||||
container_model_items = []
|
||||
for container_item in container_items:
|
||||
unique_name = (
|
||||
repre_info.representation_name
|
||||
+ container_item.object_name or "<none>"
|
||||
)
|
||||
|
||||
item = QtGui.QStandardItem()
|
||||
item.setColumnCount(root_item.columnCount())
|
||||
item.setData(container_item.namespace, QtCore.Qt.DisplayRole)
|
||||
item.setData(self.GRAYOUT_COLOR, NAME_COLOR_ROLE)
|
||||
item.setData(self.GRAYOUT_COLOR, VERSION_COLOR_ROLE)
|
||||
item.setData(item_icon, QtCore.Qt.DecorationRole)
|
||||
item.setData(repre_info.product_id, PRODUCT_ID_ROLE)
|
||||
item.setData(container_item.item_id, ITEM_ID_ROLE)
|
||||
item.setData(version_label, VERSION_LABEL_ROLE)
|
||||
item.setData(container_item.loader_name, LOADER_NAME_ROLE)
|
||||
item.setData(container_item.object_name, OBJECT_NAME_ROLE)
|
||||
item.setData(True, IS_CONTAINER_ITEM_ROLE)
|
||||
item.setData(unique_name, ITEM_UNIQUE_NAME_ROLE)
|
||||
container_model_items.append(item)
|
||||
|
||||
if not container_model_items:
|
||||
continue
|
||||
|
||||
progress = progress_by_id[repre_id]
|
||||
active_site_progress = "{}%".format(
|
||||
max(progress["active_site"], 0) * 100
|
||||
)
|
||||
remote_site_progress = "{}%".format(
|
||||
max(progress["remote_site"], 0) * 100
|
||||
)
|
||||
|
||||
group_item = QtGui.QStandardItem()
|
||||
group_item.setColumnCount(root_item.columnCount())
|
||||
group_item.setData(group_name, QtCore.Qt.DisplayRole)
|
||||
group_item.setData(group_name, ITEM_UNIQUE_NAME_ROLE)
|
||||
group_item.setData(group_item_icon, QtCore.Qt.DecorationRole)
|
||||
group_item.setData(group_item_font, QtCore.Qt.FontRole)
|
||||
group_item.setData(repre_info.product_id, PRODUCT_ID_ROLE)
|
||||
group_item.setData(repre_info.product_type, PRODUCT_TYPE_ROLE)
|
||||
group_item.setData(product_type_icon, PRODUCT_TYPE_ICON_ROLE)
|
||||
group_item.setData(is_latest, VERSION_IS_LATEST_ROLE)
|
||||
group_item.setData(is_hero, VERSION_IS_HERO_ROLE)
|
||||
group_item.setData(version_label, VERSION_LABEL_ROLE)
|
||||
group_item.setData(len(container_items), COUNT_ROLE)
|
||||
group_item.setData(status_name, STATUS_NAME_ROLE)
|
||||
group_item.setData(status_short, STATUS_SHORT_ROLE)
|
||||
group_item.setData(status_color, STATUS_COLOR_ROLE)
|
||||
|
||||
group_item.setData(
|
||||
active_site_progress, ACTIVE_SITE_PROGRESS_ROLE
|
||||
)
|
||||
group_item.setData(
|
||||
remote_site_progress, REMOTE_SITE_PROGRESS_ROLE
|
||||
)
|
||||
group_item.setData(active_site_icon, ACTIVE_SITE_ICON_ROLE)
|
||||
group_item.setData(remote_site_icon, REMOTE_SITE_ICON_ROLE)
|
||||
group_item.setData(False, IS_CONTAINER_ITEM_ROLE)
|
||||
|
||||
if version_color is not None:
|
||||
group_item.setData(version_color, VERSION_COLOR_ROLE)
|
||||
|
||||
if repre_info.product_group:
|
||||
group_item.setData(
|
||||
repre_info.product_group, PRODUCT_GROUP_NAME_ROLE
|
||||
)
|
||||
group_item.setData(group_icon, PRODUCT_GROUP_ICON_ROLE)
|
||||
|
||||
group_item.appendRows(container_model_items)
|
||||
group_items.append(group_item)
|
||||
|
||||
if group_items:
|
||||
root_item.appendRows(group_items)
|
||||
|
||||
def flags(self, index):
|
||||
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
|
||||
|
||||
def data(self, index, role):
|
||||
if not index.isValid():
|
||||
return
|
||||
|
||||
item = index.internalPointer()
|
||||
col = index.column()
|
||||
if role == QtCore.Qt.DisplayRole:
|
||||
role = self.display_role_by_column.get(col)
|
||||
if role is None:
|
||||
print(col, role)
|
||||
return None
|
||||
|
||||
if role == QtCore.Qt.FontRole:
|
||||
# Make top-level entries bold
|
||||
if item.get("isGroupNode") or item.get("isNotSet"): # group-item
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
return font
|
||||
elif role == QtCore.Qt.DecorationRole:
|
||||
role = self.decoration_role_by_column.get(col)
|
||||
if role is None:
|
||||
return None
|
||||
|
||||
if role == QtCore.Qt.ForegroundRole:
|
||||
# Set the text color to the OUTDATED_COLOR when the
|
||||
# collected version is not the same as the highest version
|
||||
key = self.Columns[index.column()]
|
||||
if key == "version": # version
|
||||
if item.get("isGroupNode"): # group-item
|
||||
if self.outdated(item):
|
||||
return self.OUTDATED_COLOR
|
||||
elif role == QtCore.Qt.ForegroundRole:
|
||||
role = self.foreground_role_by_column.get(col)
|
||||
if role is None:
|
||||
return None
|
||||
|
||||
if self._hierarchy_view:
|
||||
# If current group is not outdated, check if any
|
||||
# outdated children.
|
||||
for _node in walk_hierarchy(item):
|
||||
if self.outdated(_node):
|
||||
return self.CHILD_OUTDATED_COLOR
|
||||
else:
|
||||
if col != 0:
|
||||
index = self.index(index.row(), 0, index.parent())
|
||||
|
||||
if self._hierarchy_view:
|
||||
# Although this is not a group item, we still need
|
||||
# to distinguish which one contain outdated child.
|
||||
for _node in walk_hierarchy(item):
|
||||
if self.outdated(_node):
|
||||
return self.CHILD_OUTDATED_COLOR.darker(150)
|
||||
|
||||
return self.GRAYOUT_COLOR
|
||||
|
||||
if key == "Name" and not item.get("isGroupNode"):
|
||||
return self.GRAYOUT_COLOR
|
||||
|
||||
# Add icons
|
||||
if role == QtCore.Qt.DecorationRole:
|
||||
if index.column() == 0:
|
||||
# Override color
|
||||
color = item.get("color", self._default_icon_color)
|
||||
if item.get("isGroupNode"): # group-item
|
||||
return qtawesome.icon("fa.folder", color=color)
|
||||
if item.get("isNotSet"):
|
||||
return qtawesome.icon("fa.exclamation-circle", color=color)
|
||||
|
||||
return qtawesome.icon("fa.file-o", color=color)
|
||||
|
||||
if index.column() == 3:
|
||||
# Product type icon
|
||||
return item.get("productTypeIcon", None)
|
||||
|
||||
column_name = self.Columns[index.column()]
|
||||
|
||||
if column_name == "group" and item.get("group"):
|
||||
return qtawesome.icon("fa.object-group",
|
||||
color=get_default_entity_icon_color())
|
||||
|
||||
if item.get("isGroupNode"):
|
||||
if column_name == "active_site":
|
||||
provider = item.get("active_site_provider")
|
||||
return self._site_icons.get(provider)
|
||||
|
||||
if column_name == "remote_site":
|
||||
provider = item.get("remote_site_provider")
|
||||
return self._site_icons.get(provider)
|
||||
|
||||
if role == QtCore.Qt.DisplayRole and item.get("isGroupNode"):
|
||||
column_name = self.Columns[index.column()]
|
||||
progress = None
|
||||
if column_name == "active_site":
|
||||
progress = item.get("active_site_progress", 0)
|
||||
elif column_name == "remote_site":
|
||||
progress = item.get("remote_site_progress", 0)
|
||||
if progress is not None:
|
||||
return "{}%".format(max(progress, 0) * 100)
|
||||
|
||||
if role == self.UniqueRole:
|
||||
return item["representation"] + item.get("objectName", "<none>")
|
||||
|
||||
return super(InventoryModel, self).data(index, role)
|
||||
return super().data(index, role)
|
||||
|
||||
def set_hierarchy_view(self, state):
|
||||
"""Set whether to display products in hierarchy view."""
|
||||
|
|
@ -165,299 +335,34 @@ class InventoryModel(TreeModel):
|
|||
if state != self._hierarchy_view:
|
||||
self._hierarchy_view = state
|
||||
|
||||
def refresh(self, selected=None, containers=None):
|
||||
"""Refresh the model"""
|
||||
|
||||
# for debugging or testing, injecting items from outside
|
||||
if containers is None:
|
||||
containers = self._controller.get_containers()
|
||||
|
||||
self.clear()
|
||||
if not selected or not self._hierarchy_view:
|
||||
self._add_containers(containers)
|
||||
return
|
||||
|
||||
# Filter by cherry-picked items
|
||||
self._add_containers((
|
||||
container
|
||||
for container in containers
|
||||
if container["objectName"] in selected
|
||||
))
|
||||
|
||||
def _add_containers(self, containers, parent=None):
|
||||
"""Add the items to the model.
|
||||
|
||||
The items should be formatted similar to `api.ls()` returns, an item
|
||||
is then represented as:
|
||||
{"filename_v001.ma": [full/filename/of/loaded/filename_v001.ma,
|
||||
full/filename/of/loaded/filename_v001.ma],
|
||||
"nodetype" : "reference",
|
||||
"node": "referenceNode1"}
|
||||
|
||||
Note: When performing an additional call to `add_items` it will *not*
|
||||
group the new items with previously existing item groups of the
|
||||
same type.
|
||||
|
||||
Args:
|
||||
containers (generator): Container items.
|
||||
parent (Item, optional): Set this item as parent for the added
|
||||
items when provided. Defaults to the root of the model.
|
||||
|
||||
Returns:
|
||||
node.Item: root node which has children added based on the data
|
||||
"""
|
||||
|
||||
project_name = get_current_project_name()
|
||||
|
||||
self.beginResetModel()
|
||||
|
||||
# Group by representation
|
||||
grouped = defaultdict(lambda: {"containers": list()})
|
||||
for container in containers:
|
||||
repre_id = container["representation"]
|
||||
grouped[repre_id]["containers"].append(container)
|
||||
|
||||
(
|
||||
repres_by_id,
|
||||
versions_by_id,
|
||||
products_by_id,
|
||||
folders_by_id,
|
||||
) = self._query_entities(project_name, set(grouped.keys()))
|
||||
# Add to model
|
||||
not_found = defaultdict(list)
|
||||
not_found_ids = []
|
||||
for repre_id, group_dict in sorted(grouped.items()):
|
||||
group_containers = group_dict["containers"]
|
||||
representation = repres_by_id.get(repre_id)
|
||||
if not representation:
|
||||
not_found["representation"].extend(group_containers)
|
||||
not_found_ids.append(repre_id)
|
||||
def get_outdated_item_ids(self, ignore_hero=True):
|
||||
outdated_item_ids = []
|
||||
root_item = self.invisibleRootItem()
|
||||
for row in range(root_item.rowCount()):
|
||||
group_item = root_item.child(row)
|
||||
if group_item.data(VERSION_IS_LATEST_ROLE):
|
||||
continue
|
||||
|
||||
version_entity = versions_by_id.get(representation["versionId"])
|
||||
if not version_entity:
|
||||
not_found["version"].extend(group_containers)
|
||||
not_found_ids.append(repre_id)
|
||||
if ignore_hero and group_item.data(VERSION_IS_HERO_ROLE):
|
||||
continue
|
||||
|
||||
product_entity = products_by_id.get(version_entity["productId"])
|
||||
if not product_entity:
|
||||
not_found["product"].extend(group_containers)
|
||||
not_found_ids.append(repre_id)
|
||||
continue
|
||||
for idx in range(group_item.rowCount()):
|
||||
item = group_item.child(idx)
|
||||
outdated_item_ids.append(item.data(ITEM_ID_ROLE))
|
||||
return outdated_item_ids
|
||||
|
||||
folder_entity = folders_by_id.get(product_entity["folderId"])
|
||||
if not folder_entity:
|
||||
not_found["folder"].extend(group_containers)
|
||||
not_found_ids.append(repre_id)
|
||||
continue
|
||||
|
||||
group_dict.update({
|
||||
"representation": representation,
|
||||
"version": version_entity,
|
||||
"product": product_entity,
|
||||
"folder": folder_entity
|
||||
})
|
||||
|
||||
for _repre_id in not_found_ids:
|
||||
grouped.pop(_repre_id)
|
||||
|
||||
for where, group_containers in not_found.items():
|
||||
# create the group header
|
||||
group_node = Item()
|
||||
name = "< NOT FOUND - {} >".format(where)
|
||||
group_node["Name"] = name
|
||||
group_node["representation"] = name
|
||||
group_node["count"] = len(group_containers)
|
||||
group_node["isGroupNode"] = False
|
||||
group_node["isNotSet"] = True
|
||||
|
||||
self.add_child(group_node, parent=parent)
|
||||
|
||||
for container in group_containers:
|
||||
item_node = Item()
|
||||
item_node.update(container)
|
||||
item_node["Name"] = container.get("objectName", "NO NAME")
|
||||
item_node["isNotFound"] = True
|
||||
self.add_child(item_node, parent=group_node)
|
||||
|
||||
# TODO Use product icons
|
||||
product_type_icon = qtawesome.icon(
|
||||
"fa.folder", color="#0091B2"
|
||||
)
|
||||
# Prepare site sync specific data
|
||||
progress_by_id = self._controller.get_representations_site_progress(
|
||||
set(grouped.keys())
|
||||
)
|
||||
sites_info = self._controller.get_sites_information()
|
||||
|
||||
# Query the highest available version so the model can know
|
||||
# whether current version is currently up-to-date.
|
||||
highest_version_by_product_id = ayon_api.get_last_versions(
|
||||
project_name,
|
||||
product_ids={
|
||||
group["version"]["productId"] for group in grouped.values()
|
||||
},
|
||||
fields={"productId", "version"}
|
||||
)
|
||||
# Map value to `version` key
|
||||
highest_version_by_product_id = {
|
||||
product_id: version["version"]
|
||||
for product_id, version in highest_version_by_product_id.items()
|
||||
}
|
||||
|
||||
for repre_id, group_dict in sorted(grouped.items()):
|
||||
group_containers = group_dict["containers"]
|
||||
repre_entity = group_dict["representation"]
|
||||
version_entity = group_dict["version"]
|
||||
folder_entity = group_dict["folder"]
|
||||
product_entity = group_dict["product"]
|
||||
|
||||
product_type = product_entity["productType"]
|
||||
|
||||
# create the group header
|
||||
group_node = Item()
|
||||
group_node["Name"] = "{}_{}: ({})".format(
|
||||
folder_entity["name"],
|
||||
product_entity["name"],
|
||||
repre_entity["name"]
|
||||
)
|
||||
group_node["representation"] = repre_id
|
||||
|
||||
# Detect hero version type
|
||||
version = version_entity["version"]
|
||||
if version < 0:
|
||||
version = HeroVersionType(version)
|
||||
group_node["version"] = version
|
||||
|
||||
# Check if the version is outdated.
|
||||
# Hero versions are never considered to be outdated.
|
||||
is_outdated = False
|
||||
if not isinstance(version, HeroVersionType):
|
||||
last_version = highest_version_by_product_id.get(
|
||||
version_entity["productId"])
|
||||
if last_version is not None:
|
||||
is_outdated = version_entity["version"] != last_version
|
||||
group_node["isOutdated"] = is_outdated
|
||||
|
||||
group_node["productType"] = product_type or ""
|
||||
group_node["productTypeIcon"] = product_type_icon
|
||||
group_node["count"] = len(group_containers)
|
||||
group_node["isGroupNode"] = True
|
||||
group_node["group"] = product_entity["attrib"].get("productGroup")
|
||||
|
||||
# Site sync specific data
|
||||
progress = progress_by_id[repre_id]
|
||||
group_node.update(sites_info)
|
||||
group_node["active_site_progress"] = progress["active_site"]
|
||||
group_node["remote_site_progress"] = progress["remote_site"]
|
||||
|
||||
self.add_child(group_node, parent=parent)
|
||||
|
||||
for container in group_containers:
|
||||
item_node = Item()
|
||||
item_node.update(container)
|
||||
|
||||
# store the current version on the item
|
||||
item_node["version"] = version_entity["version"]
|
||||
item_node["version_entity"] = version_entity
|
||||
|
||||
# Remapping namespace to item name.
|
||||
# Noted that the name key is capital "N", by doing this, we
|
||||
# can view namespace in GUI without changing container data.
|
||||
item_node["Name"] = container["namespace"]
|
||||
|
||||
self.add_child(item_node, parent=group_node)
|
||||
|
||||
self.endResetModel()
|
||||
|
||||
return self._root_item
|
||||
|
||||
def _query_entities(self, project_name, repre_ids):
|
||||
"""Query entities for representations from containers.
|
||||
|
||||
Returns:
|
||||
tuple[dict, dict, dict, dict]: Representation, version, product
|
||||
and folder documents by id.
|
||||
"""
|
||||
|
||||
repres_by_id = {}
|
||||
versions_by_id = {}
|
||||
products_by_id = {}
|
||||
folders_by_id = {}
|
||||
output = (
|
||||
repres_by_id,
|
||||
versions_by_id,
|
||||
products_by_id,
|
||||
folders_by_id,
|
||||
)
|
||||
|
||||
filtered_repre_ids = set()
|
||||
for repre_id in repre_ids:
|
||||
# Filter out invalid representation ids
|
||||
# NOTE: This is added because scenes from OpenPype did contain
|
||||
# ObjectId from mongo.
|
||||
try:
|
||||
uuid.UUID(repre_id)
|
||||
filtered_repre_ids.add(repre_id)
|
||||
except ValueError:
|
||||
continue
|
||||
if not filtered_repre_ids:
|
||||
return output
|
||||
|
||||
repre_entities = ayon_api.get_representations(project_name, repre_ids)
|
||||
repres_by_id.update({
|
||||
repre_entity["id"]: repre_entity
|
||||
for repre_entity in repre_entities
|
||||
})
|
||||
version_ids = {
|
||||
repre_entity["versionId"]
|
||||
for repre_entity in repres_by_id.values()
|
||||
}
|
||||
if not version_ids:
|
||||
return output
|
||||
|
||||
versions_by_id.update({
|
||||
version_entity["id"]: version_entity
|
||||
for version_entity in ayon_api.get_versions(
|
||||
project_name, version_ids=version_ids
|
||||
)
|
||||
})
|
||||
|
||||
product_ids = {
|
||||
version_entity["productId"]
|
||||
for version_entity in versions_by_id.values()
|
||||
}
|
||||
if not product_ids:
|
||||
return output
|
||||
|
||||
products_by_id.update({
|
||||
product_entity["id"]: product_entity
|
||||
for product_entity in ayon_api.get_products(
|
||||
project_name, product_ids=product_ids
|
||||
)
|
||||
})
|
||||
folder_ids = {
|
||||
product_entity["folderId"]
|
||||
for product_entity in products_by_id.values()
|
||||
}
|
||||
if not folder_ids:
|
||||
return output
|
||||
|
||||
folders_by_id.update({
|
||||
folder_entity["id"]: folder_entity
|
||||
for folder_entity in ayon_api.get_folders(
|
||||
project_name, folder_ids=folder_ids
|
||||
)
|
||||
})
|
||||
return output
|
||||
def _clear_items(self):
|
||||
root_item = self.invisibleRootItem()
|
||||
root_item.removeRows(0, root_item.rowCount())
|
||||
|
||||
|
||||
class FilterProxyModel(QtCore.QSortFilterProxyModel):
|
||||
"""Filter model to where key column's value is in the filtered tags"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FilterProxyModel, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.setDynamicSortFilter(True)
|
||||
self.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||
self._filter_outdated = False
|
||||
self._hierarchy_view = False
|
||||
|
||||
|
|
@ -467,28 +372,23 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel):
|
|||
|
||||
# Always allow bottom entries (individual containers), since their
|
||||
# parent group hidden if it wouldn't have been validated.
|
||||
rows = model.rowCount(source_index)
|
||||
if not rows:
|
||||
if source_index.data(IS_CONTAINER_ITEM_ROLE):
|
||||
return True
|
||||
|
||||
# Filter by regex
|
||||
if hasattr(self, "filterRegExp"):
|
||||
regex = self.filterRegExp()
|
||||
else:
|
||||
regex = self.filterRegularExpression()
|
||||
pattern = regex.pattern()
|
||||
if pattern:
|
||||
pattern = re.escape(pattern)
|
||||
|
||||
if not self._matches(row, parent, pattern):
|
||||
return False
|
||||
|
||||
if self._filter_outdated:
|
||||
# When filtering to outdated we filter the up to date entries
|
||||
# thus we "allow" them when they are outdated
|
||||
if not self._is_outdated(row, parent):
|
||||
if source_index.data(VERSION_IS_LATEST_ROLE):
|
||||
return False
|
||||
|
||||
# Filter by regex
|
||||
if hasattr(self, "filterRegularExpression"):
|
||||
regex = self.filterRegularExpression()
|
||||
else:
|
||||
regex = self.filterRegExp()
|
||||
|
||||
if not self._matches(row, parent, regex.pattern()):
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_filter_outdated(self, state):
|
||||
|
|
@ -505,37 +405,6 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel):
|
|||
if state != self._hierarchy_view:
|
||||
self._hierarchy_view = state
|
||||
|
||||
def _is_outdated(self, row, parent):
|
||||
"""Return whether row is outdated.
|
||||
|
||||
A row is considered outdated if `isOutdated` data is true or not set.
|
||||
|
||||
"""
|
||||
def outdated(node):
|
||||
return node.get("isOutdated", True)
|
||||
|
||||
index = self.sourceModel().index(row, self.filterKeyColumn(), parent)
|
||||
|
||||
# The scene contents are grouped by "representation", e.g. the same
|
||||
# "representation" loaded twice is grouped under the same header.
|
||||
# Since the version check filters these parent groups we skip that
|
||||
# check for the individual children.
|
||||
has_parent = index.parent().isValid()
|
||||
if has_parent and not self._hierarchy_view:
|
||||
return True
|
||||
|
||||
# Filter to those that have the different version numbers
|
||||
node = index.internalPointer()
|
||||
if outdated(node):
|
||||
return True
|
||||
|
||||
if self._hierarchy_view:
|
||||
for _node in walk_hierarchy(node):
|
||||
if outdated(_node):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _matches(self, row, parent, pattern):
|
||||
"""Return whether row matches regex pattern.
|
||||
|
||||
|
|
@ -548,38 +417,31 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel):
|
|||
bool
|
||||
|
||||
"""
|
||||
if not pattern:
|
||||
return True
|
||||
|
||||
flags = 0
|
||||
if self.sortCaseSensitivity() == QtCore.Qt.CaseInsensitive:
|
||||
flags = re.IGNORECASE
|
||||
|
||||
regex = re.compile(re.escape(pattern), flags=flags)
|
||||
|
||||
model = self.sourceModel()
|
||||
column = self.filterKeyColumn()
|
||||
role = self.filterRole()
|
||||
|
||||
def matches(row, parent, pattern):
|
||||
matches_queue = collections.deque()
|
||||
matches_queue.append((row, parent))
|
||||
while matches_queue:
|
||||
queue_item = matches_queue.popleft()
|
||||
row, parent = queue_item
|
||||
|
||||
index = model.index(row, column, parent)
|
||||
key = model.data(index, role)
|
||||
if re.search(pattern, key, re.IGNORECASE):
|
||||
value = model.data(index, role)
|
||||
if regex.search(value):
|
||||
return True
|
||||
|
||||
if matches(row, parent, pattern):
|
||||
return True
|
||||
for idx in range(model.rowCount(index)):
|
||||
matches_queue.append((idx, index))
|
||||
|
||||
# Also allow if any of the children matches
|
||||
source_index = model.index(row, column, parent)
|
||||
rows = model.rowCount(source_index)
|
||||
|
||||
if any(
|
||||
matches(idx, source_index, pattern)
|
||||
for idx in range(rows)
|
||||
):
|
||||
return True
|
||||
|
||||
if not self._hierarchy_view:
|
||||
return False
|
||||
|
||||
for idx in range(rows):
|
||||
child_index = model.index(idx, column, source_index)
|
||||
child_rows = model.rowCount(child_index)
|
||||
return any(
|
||||
self._matches(child_idx, child_index, pattern)
|
||||
for child_idx in range(child_rows)
|
||||
)
|
||||
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
from .containers import ContainersModel
|
||||
from .sitesync import SiteSyncModel
|
||||
|
||||
|
||||
__all__ = (
|
||||
"ContainersModel",
|
||||
"SiteSyncModel",
|
||||
)
|
||||
|
|
|
|||
343
client/ayon_core/tools/sceneinventory/models/containers.py
Normal file
343
client/ayon_core/tools/sceneinventory/models/containers.py
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
import uuid
|
||||
import collections
|
||||
|
||||
import ayon_api
|
||||
from ayon_api.graphql import GraphQlQuery
|
||||
from ayon_core.host import ILoadHost
|
||||
|
||||
|
||||
# --- Implementation that should be in ayon-python-api ---
|
||||
# The implementation is not available in all versions of ayon-python-api.
|
||||
RepresentationHierarchy = collections.namedtuple(
|
||||
"RepresentationHierarchy",
|
||||
("folder", "product", "version", "representation")
|
||||
)
|
||||
|
||||
|
||||
def representations_parent_ids_qraphql_query():
|
||||
query = GraphQlQuery("RepresentationsHierarchyQuery")
|
||||
|
||||
project_name_var = query.add_variable("projectName", "String!")
|
||||
repre_ids_var = query.add_variable("representationIds", "[String!]")
|
||||
|
||||
project_field = query.add_field("project")
|
||||
project_field.set_filter("name", project_name_var)
|
||||
|
||||
repres_field = project_field.add_field_with_edges("representations")
|
||||
repres_field.add_field("id")
|
||||
repres_field.add_field("name")
|
||||
repres_field.set_filter("ids", repre_ids_var)
|
||||
version_field = repres_field.add_field("version")
|
||||
version_field.add_field("id")
|
||||
product_field = version_field.add_field("product")
|
||||
product_field.add_field("id")
|
||||
product_field.add_field("name")
|
||||
product_field.add_field("productType")
|
||||
product_attrib_field = product_field.add_field("attrib")
|
||||
product_attrib_field.add_field("productGroup")
|
||||
folder_field = product_field.add_field("folder")
|
||||
folder_field.add_field("id")
|
||||
folder_field.add_field("path")
|
||||
return query
|
||||
|
||||
|
||||
def get_representations_hierarchy(project_name, representation_ids):
|
||||
"""Find representations parents by representation id.
|
||||
|
||||
Representation parent entities up to project.
|
||||
|
||||
Args:
|
||||
project_name (str): Project where to look for entities.
|
||||
representation_ids (Iterable[str]): Representation ids.
|
||||
|
||||
Returns:
|
||||
dict[str, RepresentationParents]: Parent entities by
|
||||
representation id.
|
||||
|
||||
"""
|
||||
if not representation_ids:
|
||||
return {}
|
||||
|
||||
repre_ids = set(representation_ids)
|
||||
output = {
|
||||
repre_id: RepresentationHierarchy(None, None, None, None)
|
||||
for repre_id in representation_ids
|
||||
}
|
||||
|
||||
query = representations_parent_ids_qraphql_query()
|
||||
query.set_variable_value("projectName", project_name)
|
||||
query.set_variable_value("representationIds", list(repre_ids))
|
||||
|
||||
con = ayon_api.get_server_api_connection()
|
||||
parsed_data = query.query(con)
|
||||
for repre in parsed_data["project"]["representations"]:
|
||||
repre_id = repre["id"]
|
||||
version = repre.pop("version")
|
||||
product = version.pop("product")
|
||||
folder = product.pop("folder")
|
||||
|
||||
output[repre_id] = RepresentationHierarchy(
|
||||
folder, product, version, repre
|
||||
)
|
||||
|
||||
return output
|
||||
# --- END of ayon-python-api implementation ---
|
||||
|
||||
|
||||
class ContainerItem:
|
||||
def __init__(
|
||||
self,
|
||||
representation_id,
|
||||
loader_name,
|
||||
namespace,
|
||||
name,
|
||||
object_name,
|
||||
item_id
|
||||
):
|
||||
self.representation_id = representation_id
|
||||
self.loader_name = loader_name
|
||||
self.object_name = object_name
|
||||
self.namespace = namespace
|
||||
self.name = name
|
||||
self.item_id = item_id
|
||||
|
||||
@classmethod
|
||||
def from_container_data(cls, container):
|
||||
return cls(
|
||||
representation_id=container["representation"],
|
||||
loader_name=container["loader"],
|
||||
namespace=container["namespace"],
|
||||
name=container["name"],
|
||||
object_name=container["objectName"],
|
||||
item_id=uuid.uuid4().hex,
|
||||
)
|
||||
|
||||
|
||||
class RepresentationInfo:
|
||||
def __init__(
|
||||
self,
|
||||
folder_id,
|
||||
folder_path,
|
||||
product_id,
|
||||
product_name,
|
||||
product_type,
|
||||
product_group,
|
||||
version_id,
|
||||
representation_name,
|
||||
):
|
||||
self.folder_id = folder_id
|
||||
self.folder_path = folder_path
|
||||
self.product_id = product_id
|
||||
self.product_name = product_name
|
||||
self.product_type = product_type
|
||||
self.product_group = product_group
|
||||
self.version_id = version_id
|
||||
self.representation_name = representation_name
|
||||
self._is_valid = None
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
if self._is_valid is None:
|
||||
self._is_valid = (
|
||||
self.folder_id is not None
|
||||
and self.product_id is not None
|
||||
and self.version_id is not None
|
||||
and self.representation_name is not None
|
||||
)
|
||||
return self._is_valid
|
||||
|
||||
@classmethod
|
||||
def new_invalid(cls):
|
||||
return cls(None, None, None, None, None, None, None, None)
|
||||
|
||||
|
||||
class VersionItem:
|
||||
def __init__(self, version_id, product_id, version, status, is_latest):
|
||||
self.version = version
|
||||
self.version_id = version_id
|
||||
self.product_id = product_id
|
||||
self.version = version
|
||||
self.status = status
|
||||
self.is_latest = is_latest
|
||||
|
||||
@property
|
||||
def is_hero(self):
|
||||
return self.version < 0
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, version_entity, is_latest):
|
||||
return cls(
|
||||
version_id=version_entity["id"],
|
||||
product_id=version_entity["productId"],
|
||||
version=version_entity["version"],
|
||||
status=version_entity["status"],
|
||||
is_latest=is_latest,
|
||||
)
|
||||
|
||||
|
||||
class ContainersModel:
|
||||
def __init__(self, controller):
|
||||
self._controller = controller
|
||||
self._items_cache = None
|
||||
self._containers_by_id = {}
|
||||
self._container_items_by_id = {}
|
||||
self._version_items_by_product_id = {}
|
||||
self._repre_info_by_id = {}
|
||||
|
||||
def reset(self):
|
||||
self._items_cache = None
|
||||
self._containers_by_id = {}
|
||||
self._container_items_by_id = {}
|
||||
self._version_items_by_product_id = {}
|
||||
self._repre_info_by_id = {}
|
||||
|
||||
def get_containers(self):
|
||||
self._update_cache()
|
||||
return list(self._containers_by_id.values())
|
||||
|
||||
def get_containers_by_item_ids(self, item_ids):
|
||||
return {
|
||||
item_id: self._containers_by_id.get(item_id)
|
||||
for item_id in item_ids
|
||||
}
|
||||
|
||||
def get_container_items(self):
|
||||
self._update_cache()
|
||||
return list(self._items_cache)
|
||||
|
||||
def get_container_items_by_id(self, item_ids):
|
||||
return {
|
||||
item_id: self._container_items_by_id.get(item_id)
|
||||
for item_id in item_ids
|
||||
}
|
||||
|
||||
def get_representation_info_items(self, representation_ids):
|
||||
output = {}
|
||||
missing_repre_ids = set()
|
||||
for repre_id in representation_ids:
|
||||
try:
|
||||
uuid.UUID(repre_id)
|
||||
except ValueError:
|
||||
output[repre_id] = RepresentationInfo.new_invalid()
|
||||
continue
|
||||
|
||||
repre_info = self._repre_info_by_id.get(repre_id)
|
||||
if repre_info is None:
|
||||
missing_repre_ids.add(repre_id)
|
||||
else:
|
||||
output[repre_id] = repre_info
|
||||
|
||||
if not missing_repre_ids:
|
||||
return output
|
||||
|
||||
project_name = self._controller.get_current_project_name()
|
||||
repre_hierarchy_by_id = get_representations_hierarchy(
|
||||
project_name, missing_repre_ids
|
||||
)
|
||||
for repre_id, repre_hierarchy in repre_hierarchy_by_id.items():
|
||||
kwargs = {
|
||||
"folder_id": None,
|
||||
"folder_path": None,
|
||||
"product_id": None,
|
||||
"product_name": None,
|
||||
"product_type": None,
|
||||
"product_group": None,
|
||||
"version_id": None,
|
||||
"representation_name": None,
|
||||
}
|
||||
folder = repre_hierarchy.folder
|
||||
product = repre_hierarchy.product
|
||||
version = repre_hierarchy.version
|
||||
repre = repre_hierarchy.representation
|
||||
if folder:
|
||||
kwargs["folder_id"] = folder["id"]
|
||||
kwargs["folder_path"] = folder["path"]
|
||||
if product:
|
||||
group = product["attrib"]["productGroup"]
|
||||
kwargs["product_id"] = product["id"]
|
||||
kwargs["product_name"] = product["name"]
|
||||
kwargs["product_type"] = product["productType"]
|
||||
kwargs["product_group"] = group
|
||||
if version:
|
||||
kwargs["version_id"] = version["id"]
|
||||
if repre:
|
||||
kwargs["representation_name"] = repre["name"]
|
||||
|
||||
repre_info = RepresentationInfo(**kwargs)
|
||||
self._repre_info_by_id[repre_id] = repre_info
|
||||
output[repre_id] = repre_info
|
||||
return output
|
||||
|
||||
def get_version_items(self, product_ids):
|
||||
if not product_ids:
|
||||
return {}
|
||||
|
||||
missing_ids = {
|
||||
product_id
|
||||
for product_id in product_ids
|
||||
if product_id not in self._version_items_by_product_id
|
||||
}
|
||||
if missing_ids:
|
||||
def version_sorted(entity):
|
||||
return entity["version"]
|
||||
|
||||
project_name = self._controller.get_current_project_name()
|
||||
version_entities_by_product_id = {
|
||||
product_id: []
|
||||
for product_id in missing_ids
|
||||
}
|
||||
|
||||
version_entities = list(ayon_api.get_versions(
|
||||
project_name,
|
||||
product_ids=missing_ids,
|
||||
fields={"id", "version", "productId", "status"}
|
||||
))
|
||||
version_entities.sort(key=version_sorted)
|
||||
for version_entity in version_entities:
|
||||
product_id = version_entity["productId"]
|
||||
version_entities_by_product_id[product_id].append(
|
||||
version_entity
|
||||
)
|
||||
|
||||
for product_id, version_entities in (
|
||||
version_entities_by_product_id.items()
|
||||
):
|
||||
last_version = abs(version_entities[-1]["version"])
|
||||
version_items_by_id = {
|
||||
entity["id"]: VersionItem.from_entity(
|
||||
entity, abs(entity["version"]) == last_version
|
||||
)
|
||||
for entity in version_entities
|
||||
}
|
||||
self._version_items_by_product_id[product_id] = (
|
||||
version_items_by_id
|
||||
)
|
||||
|
||||
return {
|
||||
product_id: dict(self._version_items_by_product_id[product_id])
|
||||
for product_id in product_ids
|
||||
}
|
||||
|
||||
def _update_cache(self):
|
||||
if self._items_cache is not None:
|
||||
return
|
||||
|
||||
host = self._controller.get_host()
|
||||
if isinstance(host, ILoadHost):
|
||||
containers = list(host.get_containers())
|
||||
elif hasattr(host, "ls"):
|
||||
containers = list(host.ls())
|
||||
else:
|
||||
containers = []
|
||||
container_items = []
|
||||
containers_by_id = {}
|
||||
container_items_by_id = {}
|
||||
for container in containers:
|
||||
item = ContainerItem.from_container_data(container)
|
||||
containers_by_id[item.item_id] = container
|
||||
container_items_by_id[item.item_id] = item
|
||||
container_items.append(item)
|
||||
|
||||
self._containers_by_id = containers_by_id
|
||||
self._container_items_by_id = container_items_by_id
|
||||
self._items_cache = container_items
|
||||
216
client/ayon_core/tools/sceneinventory/select_version_dialog.py
Normal file
216
client/ayon_core/tools/sceneinventory/select_version_dialog.py
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
import uuid
|
||||
|
||||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
|
||||
from ayon_core.tools.utils.delegates import StatusDelegate
|
||||
|
||||
from .model import (
|
||||
ITEM_ID_ROLE,
|
||||
STATUS_NAME_ROLE,
|
||||
STATUS_SHORT_ROLE,
|
||||
STATUS_COLOR_ROLE,
|
||||
STATUS_ICON_ROLE,
|
||||
)
|
||||
|
||||
|
||||
class VersionOption:
|
||||
def __init__(
|
||||
self,
|
||||
version,
|
||||
label,
|
||||
status_name,
|
||||
status_short,
|
||||
status_color
|
||||
):
|
||||
self.version = version
|
||||
self.label = label
|
||||
self.status_name = status_name
|
||||
self.status_short = status_short
|
||||
self.status_color = status_color
|
||||
|
||||
|
||||
class SelectVersionModel(QtGui.QStandardItemModel):
|
||||
def data(self, index, role=None):
|
||||
if role is None:
|
||||
role = QtCore.Qt.DisplayRole
|
||||
|
||||
index = self.index(index.row(), 0, index.parent())
|
||||
return super().data(index, role)
|
||||
|
||||
|
||||
class SelectVersionComboBox(QtWidgets.QComboBox):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
combo_model = SelectVersionModel(0, 2)
|
||||
|
||||
self.setModel(combo_model)
|
||||
|
||||
combo_view = QtWidgets.QTreeView(self)
|
||||
combo_view.setHeaderHidden(True)
|
||||
combo_view.setIndentation(0)
|
||||
|
||||
self.setView(combo_view)
|
||||
|
||||
header = combo_view.header()
|
||||
header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
|
||||
header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
|
||||
|
||||
status_delegate = StatusDelegate(
|
||||
STATUS_NAME_ROLE,
|
||||
STATUS_SHORT_ROLE,
|
||||
STATUS_COLOR_ROLE,
|
||||
STATUS_ICON_ROLE,
|
||||
)
|
||||
combo_view.setItemDelegateForColumn(1, status_delegate)
|
||||
|
||||
self._combo_model = combo_model
|
||||
self._combo_view = combo_view
|
||||
self._status_delegate = status_delegate
|
||||
self._items_by_id = {}
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QtWidgets.QStylePainter(self)
|
||||
option = QtWidgets.QStyleOptionComboBox()
|
||||
self.initStyleOption(option)
|
||||
painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option)
|
||||
idx = self.currentIndex()
|
||||
status_name = self.itemData(idx, STATUS_NAME_ROLE)
|
||||
if status_name is None:
|
||||
painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option)
|
||||
return
|
||||
|
||||
painter.save()
|
||||
text_field_rect = self.style().subControlRect(
|
||||
QtWidgets.QStyle.CC_ComboBox,
|
||||
option,
|
||||
QtWidgets.QStyle.SC_ComboBoxEditField
|
||||
)
|
||||
adj_rect = text_field_rect.adjusted(1, 0, -1, 0)
|
||||
painter.drawText(
|
||||
adj_rect,
|
||||
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter,
|
||||
option.currentText
|
||||
)
|
||||
metrics = QtGui.QFontMetrics(self.font())
|
||||
text_width = metrics.width(option.currentText)
|
||||
x_offset = text_width + 2
|
||||
diff_width = adj_rect.width() - x_offset
|
||||
if diff_width <= 0:
|
||||
return
|
||||
|
||||
status_rect = adj_rect.adjusted(x_offset + 2, 0, 0, 0)
|
||||
if diff_width < metrics.width(status_name):
|
||||
status_name = self.itemData(idx, STATUS_SHORT_ROLE)
|
||||
|
||||
color = QtGui.QColor(self.itemData(idx, STATUS_COLOR_ROLE))
|
||||
|
||||
pen = painter.pen()
|
||||
pen.setColor(color)
|
||||
painter.setPen(pen)
|
||||
painter.drawText(
|
||||
status_rect,
|
||||
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter,
|
||||
status_name
|
||||
)
|
||||
|
||||
def set_current_index(self, index):
|
||||
model = self._combo_view.model()
|
||||
if index > model.rowCount():
|
||||
return
|
||||
|
||||
self.setCurrentIndex(index)
|
||||
|
||||
def get_item_by_id(self, item_id):
|
||||
return self._items_by_id[item_id]
|
||||
|
||||
def set_versions(self, version_options):
|
||||
self._items_by_id = {}
|
||||
model = self._combo_model
|
||||
root_item = model.invisibleRootItem()
|
||||
root_item.removeRows(0, root_item.rowCount())
|
||||
|
||||
new_items = []
|
||||
for version_option in version_options:
|
||||
item_id = uuid.uuid4().hex
|
||||
item = QtGui.QStandardItem(version_option.label)
|
||||
item.setColumnCount(root_item.columnCount())
|
||||
item.setData(
|
||||
version_option.status_name, STATUS_NAME_ROLE
|
||||
)
|
||||
item.setData(
|
||||
version_option.status_short, STATUS_SHORT_ROLE
|
||||
)
|
||||
item.setData(
|
||||
version_option.status_color, STATUS_COLOR_ROLE
|
||||
)
|
||||
item.setData(item_id, ITEM_ID_ROLE)
|
||||
|
||||
new_items.append(item)
|
||||
self._items_by_id[item_id] = version_option
|
||||
|
||||
if new_items:
|
||||
root_item.appendRows(new_items)
|
||||
|
||||
|
||||
class SelectVersionDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.setWindowTitle("Select version")
|
||||
|
||||
label_widget = QtWidgets.QLabel("Set version number to", self)
|
||||
versions_combobox = SelectVersionComboBox(self)
|
||||
|
||||
btns_widget = QtWidgets.QWidget(self)
|
||||
|
||||
confirm_btn = QtWidgets.QPushButton("OK", btns_widget)
|
||||
cancel_btn = QtWidgets.QPushButton("Cancel", btns_widget)
|
||||
|
||||
btns_layout = QtWidgets.QHBoxLayout(btns_widget)
|
||||
btns_layout.setContentsMargins(0, 0, 0, 0)
|
||||
btns_layout.addStretch(1)
|
||||
btns_layout.addWidget(confirm_btn, 0)
|
||||
btns_layout.addWidget(cancel_btn, 0)
|
||||
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
main_layout.addWidget(label_widget, 0)
|
||||
main_layout.addWidget(versions_combobox, 0)
|
||||
main_layout.addWidget(btns_widget, 0)
|
||||
|
||||
confirm_btn.clicked.connect(self._on_confirm)
|
||||
cancel_btn.clicked.connect(self._on_cancel)
|
||||
|
||||
self._selected_item = None
|
||||
self._cancelled = False
|
||||
self._versions_combobox = versions_combobox
|
||||
|
||||
def get_selected_item(self):
|
||||
if self._cancelled:
|
||||
return None
|
||||
return self._selected_item
|
||||
|
||||
def set_versions(self, version_options):
|
||||
self._versions_combobox.set_versions(version_options)
|
||||
|
||||
def select_index(self, index):
|
||||
self._versions_combobox.set_current_index(index)
|
||||
|
||||
@classmethod
|
||||
def ask_for_version(cls, version_options, index=None, parent=None):
|
||||
dialog = cls(parent)
|
||||
dialog.set_versions(version_options)
|
||||
if index is not None:
|
||||
dialog.select_index(index)
|
||||
dialog.exec_()
|
||||
return dialog.get_selected_item()
|
||||
|
||||
def _on_confirm(self):
|
||||
self._cancelled = False
|
||||
index = self._versions_combobox.currentIndex()
|
||||
item_id = self._versions_combobox.itemData(index, ITEM_ID_ROLE)
|
||||
self._selected_item = self._versions_combobox.get_item_by_id(item_id)
|
||||
self.accept()
|
||||
|
||||
def _on_cancel(self):
|
||||
self._cancelled = True
|
||||
self.reject()
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -2,17 +2,10 @@ from qtpy import QtWidgets, QtCore, QtGui
|
|||
import qtawesome
|
||||
|
||||
from ayon_core import style, resources
|
||||
from ayon_core.tools.utils.lib import (
|
||||
preserve_expanded_rows,
|
||||
preserve_selection,
|
||||
)
|
||||
from ayon_core.tools.utils import PlaceholderLineEdit
|
||||
|
||||
from ayon_core.tools.sceneinventory import SceneInventoryController
|
||||
|
||||
from .delegates import VersionDelegate
|
||||
from .model import (
|
||||
InventoryModel,
|
||||
FilterProxyModel
|
||||
)
|
||||
from .view import SceneInventoryView
|
||||
|
||||
|
||||
|
|
@ -20,7 +13,7 @@ class SceneInventoryWindow(QtWidgets.QDialog):
|
|||
"""Scene Inventory window"""
|
||||
|
||||
def __init__(self, controller=None, parent=None):
|
||||
super(SceneInventoryWindow, self).__init__(parent)
|
||||
super().__init__(parent)
|
||||
|
||||
if controller is None:
|
||||
controller = SceneInventoryController()
|
||||
|
|
@ -33,10 +26,9 @@ class SceneInventoryWindow(QtWidgets.QDialog):
|
|||
|
||||
self.resize(1100, 480)
|
||||
|
||||
# region control
|
||||
|
||||
filter_label = QtWidgets.QLabel("Search", self)
|
||||
text_filter = QtWidgets.QLineEdit(self)
|
||||
text_filter = PlaceholderLineEdit(self)
|
||||
text_filter.setPlaceholderText("Filter by name...")
|
||||
|
||||
outdated_only_checkbox = QtWidgets.QCheckBox(
|
||||
"Filter to outdated", self
|
||||
|
|
@ -44,52 +36,30 @@ class SceneInventoryWindow(QtWidgets.QDialog):
|
|||
outdated_only_checkbox.setToolTip("Show outdated files only")
|
||||
outdated_only_checkbox.setChecked(False)
|
||||
|
||||
icon = qtawesome.icon("fa.arrow-up", color="white")
|
||||
update_all_icon = qtawesome.icon("fa.arrow-up", color="white")
|
||||
update_all_button = QtWidgets.QPushButton(self)
|
||||
update_all_button.setToolTip("Update all outdated to latest version")
|
||||
update_all_button.setIcon(icon)
|
||||
update_all_button.setIcon(update_all_icon)
|
||||
|
||||
icon = qtawesome.icon("fa.refresh", color="white")
|
||||
refresh_icon = qtawesome.icon("fa.refresh", color="white")
|
||||
refresh_button = QtWidgets.QPushButton(self)
|
||||
refresh_button.setToolTip("Refresh")
|
||||
refresh_button.setIcon(icon)
|
||||
refresh_button.setIcon(refresh_icon)
|
||||
|
||||
control_layout = QtWidgets.QHBoxLayout()
|
||||
control_layout.addWidget(filter_label)
|
||||
control_layout.addWidget(text_filter)
|
||||
control_layout.addWidget(outdated_only_checkbox)
|
||||
control_layout.addWidget(update_all_button)
|
||||
control_layout.addWidget(refresh_button)
|
||||
|
||||
model = InventoryModel(controller)
|
||||
proxy = FilterProxyModel()
|
||||
proxy.setSourceModel(model)
|
||||
proxy.setDynamicSortFilter(True)
|
||||
proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||
headers_widget = QtWidgets.QWidget(self)
|
||||
headers_layout = QtWidgets.QHBoxLayout(headers_widget)
|
||||
headers_layout.setContentsMargins(0, 0, 0, 0)
|
||||
headers_layout.addWidget(filter_label, 0)
|
||||
headers_layout.addWidget(text_filter, 1)
|
||||
headers_layout.addWidget(outdated_only_checkbox, 0)
|
||||
headers_layout.addWidget(update_all_button, 0)
|
||||
headers_layout.addWidget(refresh_button, 0)
|
||||
|
||||
view = SceneInventoryView(controller, self)
|
||||
view.setModel(proxy)
|
||||
|
||||
sync_enabled = controller.is_sitesync_enabled()
|
||||
view.setColumnHidden(model.active_site_col, not sync_enabled)
|
||||
view.setColumnHidden(model.remote_site_col, not sync_enabled)
|
||||
|
||||
# set some nice default widths for the view
|
||||
view.setColumnWidth(0, 250) # name
|
||||
view.setColumnWidth(1, 55) # version
|
||||
view.setColumnWidth(2, 55) # count
|
||||
view.setColumnWidth(3, 150) # product type
|
||||
view.setColumnWidth(4, 120) # group
|
||||
view.setColumnWidth(5, 150) # loader
|
||||
|
||||
# apply delegates
|
||||
version_delegate = VersionDelegate(controller, self)
|
||||
column = model.Columns.index("version")
|
||||
view.setItemDelegateForColumn(column, version_delegate)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addLayout(control_layout)
|
||||
layout.addWidget(view)
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
main_layout.addWidget(headers_widget, 0)
|
||||
main_layout.addWidget(view, 1)
|
||||
|
||||
show_timer = QtCore.QTimer()
|
||||
show_timer.setInterval(0)
|
||||
|
|
@ -114,12 +84,8 @@ class SceneInventoryWindow(QtWidgets.QDialog):
|
|||
self._update_all_button = update_all_button
|
||||
self._outdated_only_checkbox = outdated_only_checkbox
|
||||
self._view = view
|
||||
self._model = model
|
||||
self._proxy = proxy
|
||||
self._version_delegate = version_delegate
|
||||
|
||||
self._first_show = True
|
||||
self._first_refresh = True
|
||||
|
||||
def showEvent(self, event):
|
||||
super(SceneInventoryWindow, self).showEvent(event)
|
||||
|
|
@ -139,29 +105,16 @@ class SceneInventoryWindow(QtWidgets.QDialog):
|
|||
whilst trying to name an instance.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def _on_refresh_request(self):
|
||||
"""Signal callback to trigger 'refresh' without any arguments."""
|
||||
|
||||
self.refresh()
|
||||
|
||||
def refresh(self, containers=None):
|
||||
self._first_refresh = False
|
||||
def refresh(self):
|
||||
self._controller.reset()
|
||||
with preserve_expanded_rows(
|
||||
tree_view=self._view,
|
||||
role=self._model.UniqueRole
|
||||
):
|
||||
with preserve_selection(
|
||||
tree_view=self._view,
|
||||
role=self._model.UniqueRole,
|
||||
current_index=False
|
||||
):
|
||||
kwargs = {"containers": containers}
|
||||
# TODO do not touch view's inner attribute
|
||||
if self._view._hierarchy_view:
|
||||
kwargs["selected"] = self._view._selected
|
||||
self._model.refresh(**kwargs)
|
||||
self._view.refresh()
|
||||
|
||||
def _on_show_timer(self):
|
||||
if self._show_counter < 3:
|
||||
|
|
@ -171,17 +124,13 @@ class SceneInventoryWindow(QtWidgets.QDialog):
|
|||
self.refresh()
|
||||
|
||||
def _on_hierarchy_view_change(self, enabled):
|
||||
self._proxy.set_hierarchy_view(enabled)
|
||||
self._model.set_hierarchy_view(enabled)
|
||||
self._view.set_hierarchy_view(enabled)
|
||||
|
||||
def _on_text_filter_change(self, text_filter):
|
||||
if hasattr(self._proxy, "setFilterRegExp"):
|
||||
self._proxy.setFilterRegExp(text_filter)
|
||||
else:
|
||||
self._proxy.setFilterRegularExpression(text_filter)
|
||||
self._view.set_text_filter(text_filter)
|
||||
|
||||
def _on_outdated_state_change(self):
|
||||
self._proxy.set_filter_outdated(
|
||||
self._view.set_filter_outdated(
|
||||
self._outdated_only_checkbox.isChecked()
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import time
|
|||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
from qtpy import QtWidgets
|
||||
from qtpy import QtWidgets, QtGui
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -106,3 +106,80 @@ class PrettyTimeDelegate(QtWidgets.QStyledItemDelegate):
|
|||
def displayText(self, value, locale):
|
||||
if value is not None:
|
||||
return pretty_timestamp(value)
|
||||
|
||||
|
||||
class StatusDelegate(QtWidgets.QStyledItemDelegate):
|
||||
"""Delegate showing status name and short name."""
|
||||
def __init__(
|
||||
self,
|
||||
status_name_role,
|
||||
status_short_name_role,
|
||||
status_color_role,
|
||||
status_icon_role,
|
||||
*args, **kwargs
|
||||
):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.status_name_role = status_name_role
|
||||
self.status_short_name_role = status_short_name_role
|
||||
self.status_color_role = status_color_role
|
||||
self.status_icon_role = status_icon_role
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
if option.widget:
|
||||
style = option.widget.style()
|
||||
else:
|
||||
style = QtWidgets.QApplication.style()
|
||||
|
||||
style.drawControl(
|
||||
QtWidgets.QCommonStyle.CE_ItemViewItem,
|
||||
option,
|
||||
painter,
|
||||
option.widget
|
||||
)
|
||||
|
||||
painter.save()
|
||||
|
||||
text_rect = style.subElementRect(
|
||||
QtWidgets.QCommonStyle.SE_ItemViewItemText,
|
||||
option
|
||||
)
|
||||
text_margin = style.proxy().pixelMetric(
|
||||
QtWidgets.QCommonStyle.PM_FocusFrameHMargin,
|
||||
option,
|
||||
option.widget
|
||||
) + 1
|
||||
padded_text_rect = text_rect.adjusted(
|
||||
text_margin, 0, - text_margin, 0
|
||||
)
|
||||
|
||||
fm = QtGui.QFontMetrics(option.font)
|
||||
text = self._get_status_name(index)
|
||||
if padded_text_rect.width() < fm.width(text):
|
||||
text = self._get_status_short_name(index)
|
||||
|
||||
fg_color = self._get_status_color(index)
|
||||
pen = painter.pen()
|
||||
pen.setColor(fg_color)
|
||||
painter.setPen(pen)
|
||||
|
||||
painter.drawText(
|
||||
padded_text_rect,
|
||||
option.displayAlignment,
|
||||
text
|
||||
)
|
||||
|
||||
painter.restore()
|
||||
|
||||
def _get_status_name(self, index):
|
||||
return index.data(self.status_name_role)
|
||||
|
||||
def _get_status_short_name(self, index):
|
||||
return index.data(self.status_short_name_role)
|
||||
|
||||
def _get_status_color(self, index):
|
||||
return QtGui.QColor(index.data(self.status_color_role))
|
||||
|
||||
def _get_status_icon(self, index):
|
||||
if self.status_icon_role is not None:
|
||||
return index.data(self.status_icon_role)
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
import sys
|
||||
import contextlib
|
||||
import collections
|
||||
from functools import partial
|
||||
|
||||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
|
|
@ -196,16 +197,16 @@ def get_openpype_qt_app():
|
|||
return get_ayon_qt_app()
|
||||
|
||||
|
||||
def iter_model_rows(model, column, include_root=False):
|
||||
def iter_model_rows(model, column=0, include_root=False):
|
||||
"""Iterate over all row indices in a model"""
|
||||
indices = [QtCore.QModelIndex()] # start iteration at root
|
||||
|
||||
for index in indices:
|
||||
indexes_queue = collections.deque()
|
||||
# start iteration at root
|
||||
indexes_queue.append(QtCore.QModelIndex())
|
||||
while indexes_queue:
|
||||
index = indexes_queue.popleft()
|
||||
# Add children to the iterations
|
||||
child_rows = model.rowCount(index)
|
||||
for child_row in range(child_rows):
|
||||
child_index = model.index(child_row, column, index)
|
||||
indices.append(child_index)
|
||||
for child_row in range(model.rowCount(index)):
|
||||
indexes_queue.append(model.index(child_row, column, index))
|
||||
|
||||
if not include_root and not index.isValid():
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -108,6 +108,10 @@ line-ending = "auto"
|
|||
# Ignore words that are not in the dictionary.
|
||||
ignore-words-list = "ayon,ynput,parms,parm,hda,developpement,ue"
|
||||
|
||||
# Ignore lines that contain this regex. This is hack for missing inline ignore.
|
||||
# Remove with next codespell release (>2.2.6)
|
||||
ignore-regex = ".*codespell:ignore.*"
|
||||
|
||||
skip = "./.*,./package/*,*/vendor/*,*/unreal/integration/*,*/aftereffects/api/extension/js/libs/*"
|
||||
count = true
|
||||
quiet-level = 3
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import os
|
|||
|
||||
from maya import cmds # noqa
|
||||
|
||||
from ayon_core.hosts.maya.api.lib import evaluation
|
||||
from ayon_maya.api.lib import evaluation
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -6,7 +6,7 @@ compatible implementation to support bothPython 2 and Python 3.
|
|||
|
||||
Instead of using ExitStack from contextlib, use it from this module:
|
||||
|
||||
>>> from ayon_core.hosts.maya.api.exitstack import ExitStack
|
||||
>>> from ayon_maya.api.exitstack import ExitStack
|
||||
|
||||
It will provide the appropriate ExitStack implementation for the current
|
||||
running Python version.
|
||||
|
|
@ -4,7 +4,7 @@ import logging
|
|||
|
||||
from maya import cmds # noqa
|
||||
import maya.mel as mel # noqa
|
||||
from ayon_core.hosts.maya.api.lib import maintained_selection
|
||||
from ayon_maya.api.lib import maintained_selection
|
||||
|
||||
|
||||
class FBXExtractor:
|
||||
|
|
@ -16,7 +16,7 @@ _gltf_options = {
|
|||
"hbu": bool, # hashBufferURI
|
||||
"ext": bool, # externalTextures
|
||||
"ivt": int, # initialValuesTime
|
||||
"acn": str, # animationClipName
|
||||
"acn": str, # animationClipName # codespell:ignore acn
|
||||
"ast": int, # animationClipStartTime
|
||||
"aet": int, # animationClipEndTime
|
||||
"afr": float, # animationClipFrameRate
|
||||
|
|
@ -8,7 +8,7 @@ from ayon_core.settings import get_project_settings
|
|||
|
||||
from ayon_core.pipeline import CreatorError, get_current_project_name
|
||||
from ayon_core.pipeline.context_tools import get_current_folder_entity
|
||||
from ayon_core.hosts.maya.api.lib import reset_frame_range
|
||||
from ayon_maya.api.lib import reset_frame_range
|
||||
|
||||
|
||||
class RenderSettings(object):
|
||||
|
|
@ -19,7 +19,7 @@ from maya.app.renderSetup.model.override import (
|
|||
UniqueOverride
|
||||
)
|
||||
|
||||
from ayon_core.hosts.maya.api.lib import get_attribute
|
||||
from ayon_maya.api.lib import get_attribute
|
||||
|
||||
EXACT_MATCH = 0
|
||||
PARENT_MATCH = 1
|
||||
|
|
@ -15,7 +15,7 @@ from ayon_core.pipeline import (
|
|||
)
|
||||
from ayon_core.pipeline.workfile import BuildWorkfile
|
||||
from ayon_core.tools.utils import host_tools
|
||||
from ayon_core.hosts.maya.api import lib, lib_rendersettings
|
||||
from ayon_maya.api import lib, lib_rendersettings
|
||||
from .lib import get_main_window, IS_HEADLESS
|
||||
from ..tools import show_look_assigner
|
||||
|
||||
|
|
@ -45,8 +45,8 @@ from ayon_core.pipeline.workfile.lock_workfile import (
|
|||
is_workfile_locked,
|
||||
is_workfile_lock_enabled
|
||||
)
|
||||
from ayon_core.hosts.maya import MAYA_ROOT_DIR
|
||||
from ayon_core.hosts.maya.lib import create_workspace_mel
|
||||
from ayon_maya import MAYA_ROOT_DIR
|
||||
from ayon_maya.lib import create_workspace_mel
|
||||
|
||||
from . import menu, lib
|
||||
from .workio import (
|
||||
|
|
@ -58,7 +58,7 @@ from .workio import (
|
|||
current_file
|
||||
)
|
||||
|
||||
log = logging.getLogger("ayon_core.hosts.maya")
|
||||
log = logging.getLogger("ayon_maya")
|
||||
|
||||
PLUGINS_DIR = os.path.join(MAYA_ROOT_DIR, "plugins")
|
||||
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
|
||||
|
|
@ -2,40 +2,41 @@ import json
|
|||
import os
|
||||
from abc import ABCMeta
|
||||
|
||||
import ayon_api
|
||||
import qargparse
|
||||
import six
|
||||
import ayon_api
|
||||
from maya import cmds
|
||||
from maya.app.renderSetup.model import renderSetup
|
||||
|
||||
from ayon_core.lib import BoolDef, Logger
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.pipeline import (
|
||||
AYON_INSTANCE_ID,
|
||||
AYON_CONTAINER_ID,
|
||||
AVALON_INSTANCE_ID,
|
||||
AVALON_CONTAINER_ID,
|
||||
AVALON_INSTANCE_ID,
|
||||
AYON_CONTAINER_ID,
|
||||
AYON_INSTANCE_ID,
|
||||
Anatomy,
|
||||
|
||||
AutoCreator,
|
||||
CreatedInstance,
|
||||
Creator as NewCreator,
|
||||
AutoCreator,
|
||||
HiddenCreator,
|
||||
|
||||
CreatorError,
|
||||
HiddenCreator,
|
||||
LegacyCreator,
|
||||
LoaderPlugin,
|
||||
get_representation_path,
|
||||
get_current_project_name,
|
||||
get_representation_path,
|
||||
publish,
|
||||
)
|
||||
from ayon_core.pipeline.load import LoadError
|
||||
from ayon_core.pipeline.create import get_product_name
|
||||
from ayon_core.pipeline.load import LoadError
|
||||
from ayon_core.settings import get_project_settings
|
||||
from maya import cmds
|
||||
from maya.app.renderSetup.model import renderSetup
|
||||
from pyblish.api import ContextPlugin, InstancePlugin
|
||||
|
||||
from . import lib
|
||||
from .lib import imprint, read
|
||||
from .pipeline import containerise
|
||||
|
||||
log = Logger.get_logger()
|
||||
SETTINGS_CATEGORY = "maya"
|
||||
|
||||
|
||||
def _get_attr(node, attr, default=None):
|
||||
|
|
@ -652,7 +653,7 @@ def get_load_color_for_product_type(product_type, settings=None):
|
|||
|
||||
class Loader(LoaderPlugin):
|
||||
hosts = ["maya"]
|
||||
|
||||
settings_category = SETTINGS_CATEGORY
|
||||
load_settings = {} # defined in settings
|
||||
|
||||
@classmethod
|
||||
|
|
@ -807,10 +808,9 @@ class ReferenceLoader(Loader):
|
|||
raise NotImplementedError("Must be implemented by subclass")
|
||||
|
||||
def update(self, container, context):
|
||||
from ayon_maya.api.lib import get_container_members
|
||||
from maya import cmds
|
||||
|
||||
from ayon_core.hosts.maya.api.lib import get_container_members
|
||||
|
||||
node = container["objectName"]
|
||||
|
||||
project_name = context["project"]["name"]
|
||||
|
|
@ -1025,3 +1025,30 @@ class ReferenceLoader(Loader):
|
|||
AYON_CONTAINER_ID, AVALON_CONTAINER_ID
|
||||
}:
|
||||
cmds.sets(node, forceElement=container)
|
||||
|
||||
|
||||
class MayaLoader(LoaderPlugin):
|
||||
"""Base class for loader plugins."""
|
||||
|
||||
settings_category = SETTINGS_CATEGORY
|
||||
|
||||
|
||||
class MayaInstancePlugin(InstancePlugin):
|
||||
"""Base class for instance publish plugins."""
|
||||
|
||||
settings_category = SETTINGS_CATEGORY
|
||||
hosts = ["maya"]
|
||||
|
||||
|
||||
class MayaContextPlugin(ContextPlugin):
|
||||
"""Base class for context publish plugins."""
|
||||
|
||||
settings_category = SETTINGS_CATEGORY
|
||||
hosts = ["maya"]
|
||||
|
||||
|
||||
class MayaExtractorPlugin(publish.Extractor):
|
||||
"""Base class for extract plugins."""
|
||||
|
||||
settings_category = SETTINGS_CATEGORY
|
||||
hosts = ["maya"]
|
||||
|
|
@ -20,7 +20,7 @@ from ayon_core.pipeline import (
|
|||
get_representation_path,
|
||||
get_current_project_name,
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
from ayon_maya.api.lib import (
|
||||
matrix_equals,
|
||||
unique_namespace,
|
||||
get_container_transforms,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
from ayon_applications import PreLaunchHook, LaunchTypes
|
||||
from ayon_core.hosts.maya.lib import create_workspace_mel
|
||||
from ayon_maya.lib import create_workspace_mel
|
||||
|
||||
|
||||
class PreCopyMel(PreLaunchHook):
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import ayon_api
|
||||
|
||||
from ayon_core.pipeline.create.creator_plugins import ProductConvertorPlugin
|
||||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_core.hosts.maya.api.lib import read
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_maya.api.lib import read
|
||||
|
||||
from maya import cmds
|
||||
from maya.app.renderSetup.model import renderSetup
|
||||
|
|
@ -12,7 +12,7 @@ class MayaLegacyConvertor(ProductConvertorPlugin,
|
|||
plugin.MayaCreatorBase):
|
||||
"""Find and convert any legacy products in the scene.
|
||||
|
||||
This Convertor will find all legacy products in the scene and will
|
||||
This Converter will find all legacy products in the scene and will
|
||||
transform them to the current system. Since the old products doesn't
|
||||
retain any information about their original creators, the only mapping
|
||||
we can do is based on their families.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from maya import cmds
|
||||
|
||||
from ayon_core.hosts.maya.api import lib, plugin
|
||||
from ayon_maya.api import lib, plugin
|
||||
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from maya import cmds
|
||||
|
||||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
|
||||
|
||||
class CreateAssembly(plugin.MayaCreator):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_core.lib import BoolDef
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
plugin,
|
||||
lib
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin, lib
|
||||
from ayon_maya.api import plugin, lib
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
EnumDef,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
|
||||
|
||||
class CreateMayaScene(plugin.MayaCreator):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
TextDef
|
||||
|
|
@ -8,7 +8,7 @@ from ayon_api import (
|
|||
)
|
||||
from maya import cmds # noqa: F401
|
||||
|
||||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_core.lib import BoolDef, EnumDef, TextDef
|
||||
from ayon_core.pipeline import (
|
||||
Creator,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
EnumDef
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin, lib
|
||||
from ayon_maya.api import plugin, lib
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
NumberDef,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin, lib
|
||||
from ayon_maya.api import plugin, lib
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
NumberDef,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin, lib
|
||||
from ayon_maya.api import plugin, lib
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
NumberDef,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Creator of Redshift proxy product types."""
|
||||
|
||||
from ayon_core.hosts.maya.api import plugin, lib
|
||||
from ayon_maya.api import plugin, lib
|
||||
from ayon_core.lib import BoolDef
|
||||
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Create ``Render`` instance in Maya."""
|
||||
|
||||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib_rendersettings,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_core.pipeline import CreatorError
|
||||
|
||||
|
||||
|
|
@ -3,7 +3,7 @@ import json
|
|||
from maya import cmds
|
||||
import ayon_api
|
||||
|
||||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from maya import cmds
|
||||
|
||||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
|
||||
|
||||
class CreateRig(plugin.MayaCreator):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_core.lib import BoolDef
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Creator for Unreal Skeletal Meshes."""
|
||||
from ayon_core.hosts.maya.api import plugin, lib
|
||||
from ayon_maya.api import plugin, lib
|
||||
from ayon_core.lib import (
|
||||
BoolDef,
|
||||
TextDef
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Creator for Unreal Static Meshes."""
|
||||
from ayon_core.hosts.maya.api import plugin, lib
|
||||
from ayon_maya.api import plugin, lib
|
||||
from maya import cmds # noqa
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
plugin,
|
||||
lib
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Create instance of vrayscene."""
|
||||
|
||||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib_rendersettings,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
import ayon_api
|
||||
|
||||
from ayon_core.pipeline import CreatedInstance, AutoCreator
|
||||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
from maya import cmds
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import plugin
|
||||
from ayon_maya.api import plugin
|
||||
|
||||
|
||||
class CreateXgen(plugin.MayaCreator):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from maya import cmds
|
||||
|
||||
from ayon_core.hosts.maya.api import (
|
||||
from ayon_maya.api import (
|
||||
lib,
|
||||
plugin
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
from maya import cmds
|
||||
|
||||
from ayon_core.pipeline import InventoryAction, get_repres_contexts
|
||||
from ayon_core.hosts.maya.api.lib import get_id
|
||||
from ayon_maya.api.lib import get_id
|
||||
|
||||
|
||||
class ConnectGeometry(InventoryAction):
|
||||
|
|
@ -9,7 +9,7 @@ from ayon_core.pipeline import (
|
|||
get_repres_contexts,
|
||||
get_representation_path,
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib import get_container_members, get_id
|
||||
from ayon_maya.api.lib import get_container_members, get_id
|
||||
|
||||
|
||||
class ConnectYetiRig(InventoryAction):
|
||||
|
|
@ -8,7 +8,7 @@ from ayon_core.pipeline import (
|
|||
InventoryAction,
|
||||
get_current_project_name,
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
from ayon_maya.api.lib import (
|
||||
maintained_selection,
|
||||
apply_shaders
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
from maya import cmds
|
||||
|
||||
from ayon_core.pipeline import InventoryAction
|
||||
from ayon_core.hosts.maya.api.lib import get_reference_node
|
||||
from ayon_maya.api.lib import get_reference_node
|
||||
|
||||
|
||||
class ImportReference(InventoryAction):
|
||||
|
|
@ -3,7 +3,7 @@ from ayon_core.pipeline import (
|
|||
get_current_project_name,
|
||||
)
|
||||
from ayon_core.pipeline.load import get_representation_contexts_by_ids
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
from ayon_maya.api.lib import (
|
||||
create_rig_animation_instance,
|
||||
get_container_members,
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
from maya import cmds
|
||||
|
||||
from ayon_core.pipeline import InventoryAction, registered_host
|
||||
from ayon_core.hosts.maya.api.lib import get_container_members
|
||||
from ayon_maya.api.lib import get_container_members
|
||||
|
||||
|
||||
class SelectInScene(InventoryAction):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import ayon_core.hosts.maya.api.plugin
|
||||
import ayon_maya.api.plugin
|
||||
import maya.cmds as cmds
|
||||
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ def _process_reference(file_url, name, namespace, options):
|
|||
Returns:
|
||||
list: list of object nodes
|
||||
"""
|
||||
from ayon_core.hosts.maya.api.lib import unique_namespace
|
||||
from ayon_maya.api.lib import unique_namespace
|
||||
# Get name from asset being loaded
|
||||
# Assuming name is product name from the animation, we split the number
|
||||
# suffix from the name to ensure the namespace is unique
|
||||
|
|
@ -43,7 +43,7 @@ def _process_reference(file_url, name, namespace, options):
|
|||
return nodes
|
||||
|
||||
|
||||
class AbcLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
|
||||
class AbcLoader(ayon_maya.api.plugin.ReferenceLoader):
|
||||
"""Loader to reference an Alembic file"""
|
||||
|
||||
product_types = {
|
||||
|
|
@ -74,7 +74,7 @@ class AbcLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
|
|||
return nodes
|
||||
|
||||
|
||||
class FbxLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
|
||||
class FbxLoader(ayon_maya.api.plugin.ReferenceLoader):
|
||||
"""Loader to reference an Fbx files"""
|
||||
|
||||
product_types = {
|
||||
|
|
@ -3,11 +3,11 @@
|
|||
"""
|
||||
import qargparse
|
||||
from ayon_core.pipeline import load
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
from ayon_maya.api.lib import (
|
||||
maintained_selection,
|
||||
get_custom_namespace
|
||||
)
|
||||
import ayon_core.hosts.maya.api.plugin
|
||||
import ayon_maya.api.plugin
|
||||
|
||||
|
||||
class SetFrameRangeLoader(load.LoaderPlugin):
|
||||
|
|
@ -85,7 +85,7 @@ class SetFrameRangeWithHandlesLoader(load.LoaderPlugin):
|
|||
animationEndTime=end)
|
||||
|
||||
|
||||
class ImportMayaLoader(ayon_core.hosts.maya.api.plugin.Loader):
|
||||
class ImportMayaLoader(ayon_maya.api.plugin.Loader):
|
||||
"""Import action for Maya (unmanaged)
|
||||
|
||||
Warning:
|
||||
|
|
@ -1,21 +1,18 @@
|
|||
import os
|
||||
|
||||
import clique
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_representation_path
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
unique_namespace,
|
||||
from ayon_maya.api.lib import (
|
||||
get_attribute_input,
|
||||
get_fps_for_current_context,
|
||||
maintained_selection,
|
||||
get_fps_for_current_context
|
||||
unique_namespace,
|
||||
)
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.hosts.maya.api.plugin import get_load_color_for_product_type
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from ayon_maya.api.plugin import get_load_color_for_product_type
|
||||
from ayon_maya.api import plugin
|
||||
|
||||
|
||||
def is_sequence(files):
|
||||
|
|
@ -26,7 +23,7 @@ def is_sequence(files):
|
|||
return sequence
|
||||
|
||||
|
||||
class ArnoldStandinLoader(load.LoaderPlugin):
|
||||
class ArnoldStandinLoader(plugin.Loader):
|
||||
"""Load as Arnold standin"""
|
||||
|
||||
product_types = {
|
||||
|
|
@ -1,16 +1,10 @@
|
|||
from ayon_core.lib import (
|
||||
BoolDef
|
||||
)
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
registered_host
|
||||
)
|
||||
from ayon_core.hosts.maya.api.workfile_template_builder import (
|
||||
MayaTemplateBuilder
|
||||
)
|
||||
from ayon_core.lib import BoolDef
|
||||
from ayon_core.pipeline import registered_host
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_maya.api.workfile_template_builder import MayaTemplateBuilder
|
||||
|
||||
|
||||
class LoadAsTemplate(load.LoaderPlugin):
|
||||
class LoadAsTemplate(plugin.Loader):
|
||||
"""Load workfile as a template """
|
||||
|
||||
product_types = {"workfile", "mayaScene"}
|
||||
|
|
@ -1,16 +1,12 @@
|
|||
import maya.cmds as cmds
|
||||
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
remove_container
|
||||
)
|
||||
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.hosts.maya.api.lib import unique_namespace
|
||||
from ayon_core.hosts.maya.api import setdress
|
||||
from ayon_core.pipeline import remove_container
|
||||
from ayon_maya.api import setdress
|
||||
from ayon_maya.api.lib import unique_namespace
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from ayon_maya.api import plugin
|
||||
|
||||
|
||||
class AssemblyLoader(load.LoaderPlugin):
|
||||
class AssemblyLoader(plugin.Loader):
|
||||
|
||||
product_types = {"assembly"}
|
||||
representations = {"json"}
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_maya.api.lib import get_container_members, unique_namespace
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from ayon_maya.api import plugin
|
||||
from maya import cmds, mel
|
||||
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_representation_path,
|
||||
)
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.hosts.maya.api.lib import unique_namespace, get_container_members
|
||||
|
||||
|
||||
class AudioLoader(load.LoaderPlugin):
|
||||
class AudioLoader(plugin.Loader):
|
||||
"""Specific loader of audio."""
|
||||
|
||||
product_types = {"audio"}
|
||||
|
|
@ -1,16 +1,13 @@
|
|||
import maya.cmds as cmds
|
||||
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.hosts.maya.api.lib import unique_namespace
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_representation_path
|
||||
)
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.hosts.maya.api.plugin import get_load_color_for_product_type
|
||||
from ayon_maya.api.lib import unique_namespace
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_maya.api.plugin import get_load_color_for_product_type
|
||||
|
||||
|
||||
class GpuCacheLoader(load.LoaderPlugin):
|
||||
class GpuCacheLoader(plugin.Loader):
|
||||
"""Load Alembic as gpuCache"""
|
||||
|
||||
product_types = {"model", "animation", "proxyAbc", "pointcache"}
|
||||
|
|
@ -1,24 +1,17 @@
|
|||
import copy
|
||||
|
||||
from ayon_core.lib import EnumDef
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_current_host_name,
|
||||
from ayon_core.pipeline import get_current_host_name
|
||||
from ayon_core.pipeline.colorspace import (
|
||||
get_current_context_imageio_config_preset,
|
||||
get_imageio_file_rules,
|
||||
get_imageio_file_rules_colorspace_from_filepath,
|
||||
)
|
||||
from ayon_core.pipeline.load.utils import get_representation_path_from_context
|
||||
from ayon_core.pipeline.colorspace import (
|
||||
get_imageio_file_rules_colorspace_from_filepath,
|
||||
get_current_context_imageio_config_preset,
|
||||
get_imageio_file_rules
|
||||
)
|
||||
from ayon_core.settings import get_project_settings
|
||||
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
unique_namespace,
|
||||
namespaced
|
||||
)
|
||||
|
||||
from ayon_maya.api.lib import namespaced, unique_namespace
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from ayon_maya.api import plugin
|
||||
from maya import cmds
|
||||
|
||||
|
||||
|
|
@ -88,7 +81,7 @@ def create_stencil():
|
|||
return file, place, stencil, place_stencil
|
||||
|
||||
|
||||
class FileNodeLoader(load.LoaderPlugin):
|
||||
class FileNodeLoader(plugin.Loader):
|
||||
"""File node loader."""
|
||||
|
||||
product_types = {"image", "plate", "render"}
|
||||
|
|
@ -1,18 +1,14 @@
|
|||
from qtpy import QtWidgets, QtCore
|
||||
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_representation_path,
|
||||
)
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
unique_namespace,
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_maya.api.lib import (
|
||||
get_container_members,
|
||||
namespaced,
|
||||
pairwise,
|
||||
get_container_members
|
||||
unique_namespace,
|
||||
)
|
||||
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from ayon_maya.api import plugin
|
||||
from maya import cmds
|
||||
from qtpy import QtCore, QtWidgets
|
||||
|
||||
|
||||
def disconnect_inputs(plug):
|
||||
|
|
@ -84,7 +80,7 @@ class CameraWindow(QtWidgets.QDialog):
|
|||
self.close()
|
||||
|
||||
|
||||
class ImagePlaneLoader(load.LoaderPlugin):
|
||||
class ImagePlaneLoader(plugin.Loader):
|
||||
"""Specific loader of plate for image planes on selected camera."""
|
||||
|
||||
product_types = {"image", "plate", "render"}
|
||||
|
|
@ -3,18 +3,16 @@
|
|||
import json
|
||||
from collections import defaultdict
|
||||
|
||||
from qtpy import QtWidgets
|
||||
import ayon_maya.api.plugin
|
||||
from ayon_api import get_representation_by_name
|
||||
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
import ayon_core.hosts.maya.api.plugin
|
||||
from ayon_core.hosts.maya.api import lib
|
||||
from ayon_core.hosts.maya.api.lib import get_reference_node
|
||||
|
||||
from ayon_core.tools.utils import ScrollMessageBox
|
||||
from ayon_maya.api import lib
|
||||
from ayon_maya.api.lib import get_reference_node
|
||||
from qtpy import QtWidgets
|
||||
|
||||
|
||||
class LookLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
|
||||
class LookLoader(ayon_maya.api.plugin.ReferenceLoader):
|
||||
"""Specific loader for lookdev"""
|
||||
|
||||
product_types = {"look"}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
from ayon_maya.api import plugin
|
||||
from maya import mel
|
||||
from ayon_core.pipeline import load
|
||||
|
||||
class MatchmoveLoader(load.LoaderPlugin):
|
||||
|
||||
class MatchmoveLoader(plugin.Loader):
|
||||
"""
|
||||
This will run matchmove script to create track in scene.
|
||||
|
||||
|
|
@ -1,19 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import maya.cmds as cmds
|
||||
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_representation_path,
|
||||
)
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_core.pipeline.load import get_representation_path_from_context
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
namespaced,
|
||||
unique_namespace
|
||||
)
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_maya.api.lib import namespaced, unique_namespace
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from ayon_maya.api import plugin
|
||||
|
||||
|
||||
class MayaUsdLoader(load.LoaderPlugin):
|
||||
class MayaUsdLoader(plugin.Loader):
|
||||
"""Read USD data in a Maya USD Proxy"""
|
||||
|
||||
product_types = {"model", "usd", "pointcache", "animation"}
|
||||
|
|
@ -1,23 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import maya.cmds as cmds
|
||||
from maya import mel
|
||||
import os
|
||||
|
||||
import maya.cmds as cmds
|
||||
from ayon_api import get_representation_by_id
|
||||
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_representation_path
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
maintained_selection,
|
||||
namespaced,
|
||||
unique_namespace
|
||||
)
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_maya.api.lib import maintained_selection, namespaced, unique_namespace
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from maya import mel
|
||||
|
||||
|
||||
class MultiverseUsdLoader(load.LoaderPlugin):
|
||||
class MultiverseUsdLoader(plugin.Loader):
|
||||
"""Read USD data in a Multiverse Compound"""
|
||||
|
||||
product_types = {
|
||||
|
|
@ -1,22 +1,17 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import maya.cmds as cmds
|
||||
from maya import mel
|
||||
import os
|
||||
|
||||
import maya.cmds as cmds
|
||||
import qargparse
|
||||
from ayon_api import get_representation_by_id
|
||||
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_representation_path
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
maintained_selection
|
||||
)
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_maya.api.lib import maintained_selection
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from maya import mel
|
||||
|
||||
|
||||
class MultiverseUsdOverLoader(load.LoaderPlugin):
|
||||
class MultiverseUsdOverLoader(plugin.Loader):
|
||||
"""Reference file"""
|
||||
|
||||
product_types = {"mvUsdOverride"}
|
||||
|
|
@ -1,25 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Loader for Redshift proxy."""
|
||||
import os
|
||||
|
||||
import clique
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_core.pipeline import (
|
||||
load,
|
||||
get_representation_path
|
||||
)
|
||||
from ayon_core.hosts.maya.api.lib import (
|
||||
namespaced,
|
||||
maintained_selection,
|
||||
unique_namespace
|
||||
)
|
||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||
from ayon_core.hosts.maya.api.plugin import get_load_color_for_product_type
|
||||
from ayon_maya.api import plugin
|
||||
from ayon_maya.api.lib import maintained_selection, namespaced, unique_namespace
|
||||
from ayon_maya.api.pipeline import containerise
|
||||
from ayon_maya.api.plugin import get_load_color_for_product_type
|
||||
|
||||
|
||||
class RedshiftProxyLoader(load.LoaderPlugin):
|
||||
class RedshiftProxyLoader(plugin.Loader):
|
||||
"""Load Redshift proxy"""
|
||||
|
||||
product_types = {"redshiftproxy"}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue