mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge pull request #4433 from ynput/feature/creator_sorting
Publisher: Creators sorting
This commit is contained in:
commit
ffc3b8581a
6 changed files with 149 additions and 30 deletions
|
|
@ -33,6 +33,8 @@ class BatchMovieCreator(TrayPublishCreator):
|
|||
|
||||
create_allow_context_change = False
|
||||
version_regex = re.compile(r"^(.+)_v([0-9]+)$")
|
||||
# Position batch creator after simple creators
|
||||
order = 110
|
||||
|
||||
def __init__(self, project_settings, *args, **kwargs):
|
||||
super(BatchMovieCreator, self).__init__(project_settings,
|
||||
|
|
|
|||
|
|
@ -1432,6 +1432,53 @@ class CreateContext:
|
|||
"""Access to global publish attributes."""
|
||||
return self._publish_attributes
|
||||
|
||||
def get_sorted_creators(self, identifiers=None):
|
||||
"""Sorted creators by 'order' attribute.
|
||||
|
||||
Args:
|
||||
identifiers (Iterable[str]): Filter creators by identifiers. All
|
||||
creators are returned if 'None' is passed.
|
||||
|
||||
Returns:
|
||||
List[BaseCreator]: Sorted creator plugins by 'order' value.
|
||||
"""
|
||||
|
||||
if identifiers is not None:
|
||||
identifiers = set(identifiers)
|
||||
creators = [
|
||||
creator
|
||||
for identifier, creator in self.creators.items()
|
||||
if identifier in identifiers
|
||||
]
|
||||
else:
|
||||
creators = self.creators.values()
|
||||
|
||||
return sorted(
|
||||
creators, key=lambda creator: creator.order
|
||||
)
|
||||
|
||||
@property
|
||||
def sorted_creators(self):
|
||||
"""Sorted creators by 'order' attribute.
|
||||
|
||||
Returns:
|
||||
List[BaseCreator]: Sorted creator plugins by 'order' value.
|
||||
"""
|
||||
|
||||
return self.get_sorted_creators()
|
||||
|
||||
@property
|
||||
def sorted_autocreators(self):
|
||||
"""Sorted auto-creators by 'order' attribute.
|
||||
|
||||
Returns:
|
||||
List[AutoCreator]: Sorted plugins by 'order' value.
|
||||
"""
|
||||
|
||||
return sorted(
|
||||
self.autocreators.values(), key=lambda creator: creator.order
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_host_misssing_methods(cls, host):
|
||||
"""Collect missing methods from host.
|
||||
|
|
@ -1793,6 +1840,9 @@ class CreateContext:
|
|||
)
|
||||
])
|
||||
|
||||
def _remove_instance(self, instance):
|
||||
self._instances_by_id.pop(instance.id, None)
|
||||
|
||||
def creator_removed_instance(self, instance):
|
||||
"""When creator removes instance context should be acknowledged.
|
||||
|
||||
|
|
@ -1804,7 +1854,7 @@ class CreateContext:
|
|||
from scene metadata.
|
||||
"""
|
||||
|
||||
self._instances_by_id.pop(instance.id, None)
|
||||
self._remove_instance(instance)
|
||||
|
||||
def add_convertor_item(self, convertor_identifier, label):
|
||||
self.convertor_items_by_id[convertor_identifier] = ConvertorItem(
|
||||
|
|
@ -1848,7 +1898,7 @@ class CreateContext:
|
|||
# Collect instances
|
||||
error_message = "Collection of instances for creator {} failed. {}"
|
||||
failed_info = []
|
||||
for creator in self.creators.values():
|
||||
for creator in self.sorted_creators:
|
||||
label = creator.label
|
||||
identifier = creator.identifier
|
||||
failed = False
|
||||
|
|
@ -1920,7 +1970,8 @@ class CreateContext:
|
|||
|
||||
error_message = "Failed to run AutoCreator with identifier \"{}\". {}"
|
||||
failed_info = []
|
||||
for identifier, creator in self.autocreators.items():
|
||||
for creator in self.sorted_autocreators:
|
||||
identifier = creator.identifier
|
||||
label = creator.label
|
||||
failed = False
|
||||
add_traceback = False
|
||||
|
|
@ -2025,19 +2076,26 @@ class CreateContext:
|
|||
"""Save instance specific values."""
|
||||
instances_by_identifier = collections.defaultdict(list)
|
||||
for instance in self._instances_by_id.values():
|
||||
instance_changes = instance.changes()
|
||||
if not instance_changes:
|
||||
continue
|
||||
|
||||
identifier = instance.creator_identifier
|
||||
instances_by_identifier[identifier].append(instance)
|
||||
instances_by_identifier[identifier].append(
|
||||
UpdateData(instance, instance_changes)
|
||||
)
|
||||
|
||||
if not instances_by_identifier:
|
||||
return
|
||||
|
||||
error_message = "Instances update of creator \"{}\" failed. {}"
|
||||
failed_info = []
|
||||
for identifier, creator_instances in instances_by_identifier.items():
|
||||
update_list = []
|
||||
for instance in creator_instances:
|
||||
instance_changes = instance.changes()
|
||||
if instance_changes:
|
||||
update_list.append(UpdateData(instance, instance_changes))
|
||||
|
||||
creator = self.creators[identifier]
|
||||
for creator in self.get_sorted_creators(
|
||||
instances_by_identifier.keys()
|
||||
):
|
||||
identifier = creator.identifier
|
||||
update_list = instances_by_identifier[identifier]
|
||||
if not update_list:
|
||||
continue
|
||||
|
||||
|
|
@ -2073,9 +2131,13 @@ class CreateContext:
|
|||
def remove_instances(self, instances):
|
||||
"""Remove instances from context.
|
||||
|
||||
All instances that don't have creator identifier leading to existing
|
||||
creator are just removed from context.
|
||||
|
||||
Args:
|
||||
instances(list<CreatedInstance>): Instances that should be removed
|
||||
from context.
|
||||
instances(List[CreatedInstance]): Instances that should be removed.
|
||||
Remove logic is done using creator, which may require to
|
||||
do other cleanup than just remove instance from context.
|
||||
"""
|
||||
|
||||
instances_by_identifier = collections.defaultdict(list)
|
||||
|
|
@ -2083,10 +2145,21 @@ class CreateContext:
|
|||
identifier = instance.creator_identifier
|
||||
instances_by_identifier[identifier].append(instance)
|
||||
|
||||
# Just remove instances from context if creator is not available
|
||||
missing_creators = set(instances_by_identifier) - set(self.creators)
|
||||
for identifier in missing_creators:
|
||||
for instance in instances_by_identifier[identifier]:
|
||||
self._remove_instance(instance)
|
||||
|
||||
error_message = "Instances removement of creator \"{}\" failed. {}"
|
||||
failed_info = []
|
||||
for identifier, creator_instances in instances_by_identifier.items():
|
||||
creator = self.creators.get(identifier)
|
||||
# Remove instances by creator plugin order
|
||||
for creator in self.get_sorted_creators(
|
||||
instances_by_identifier.keys()
|
||||
):
|
||||
identifier = creator.identifier
|
||||
creator_instances = instances_by_identifier[identifier]
|
||||
|
||||
label = creator.label
|
||||
failed = False
|
||||
add_traceback = False
|
||||
|
|
@ -2129,6 +2202,7 @@ class CreateContext:
|
|||
family(str): Instance family for which should be attribute
|
||||
definitions returned.
|
||||
"""
|
||||
|
||||
if family not in self._attr_plugins_by_family:
|
||||
import pyblish.logic
|
||||
|
||||
|
|
@ -2144,7 +2218,13 @@ class CreateContext:
|
|||
return self._attr_plugins_by_family[family]
|
||||
|
||||
def _get_publish_plugins_with_attr_for_context(self):
|
||||
"""Publish plugins attributes for Context plugins."""
|
||||
"""Publish plugins attributes for Context plugins.
|
||||
|
||||
Returns:
|
||||
List[pyblish.api.Plugin]: Publish plugins that have attribute
|
||||
definitions for context.
|
||||
"""
|
||||
|
||||
plugins = []
|
||||
for plugin in self.plugins_with_defs:
|
||||
if not plugin.__instanceEnabled__:
|
||||
|
|
@ -2169,7 +2249,7 @@ class CreateContext:
|
|||
return self._collection_shared_data
|
||||
|
||||
def run_convertor(self, convertor_identifier):
|
||||
"""Run convertor plugin by it's idenfitifier.
|
||||
"""Run convertor plugin by identifier.
|
||||
|
||||
Conversion is skipped if convertor is not available.
|
||||
|
||||
|
|
@ -2182,7 +2262,7 @@ class CreateContext:
|
|||
convertor.convert()
|
||||
|
||||
def run_convertors(self, convertor_identifiers):
|
||||
"""Run convertor plugins by idenfitifiers.
|
||||
"""Run convertor plugins by identifiers.
|
||||
|
||||
Conversion is skipped if convertor is not available. It is recommended
|
||||
to trigger reset after conversion to reload instances.
|
||||
|
|
|
|||
|
|
@ -107,7 +107,11 @@ class SubsetConvertorPlugin(object):
|
|||
|
||||
@property
|
||||
def create_context(self):
|
||||
"""Quick access to create context."""
|
||||
"""Quick access to create context.
|
||||
|
||||
Returns:
|
||||
CreateContext: Context which initialized the plugin.
|
||||
"""
|
||||
|
||||
return self._create_context
|
||||
|
||||
|
|
@ -157,6 +161,10 @@ class BaseCreator:
|
|||
# Cached group label after first call 'get_group_label'
|
||||
_cached_group_label = None
|
||||
|
||||
# Order in which will be plugin executed (collect & update instances)
|
||||
# less == earlier -> Order '90' will be processed before '100'
|
||||
order = 100
|
||||
|
||||
# Variable to store logger
|
||||
_log = None
|
||||
|
||||
|
|
@ -489,6 +497,17 @@ class Creator(BaseCreator):
|
|||
# - similar to instance attribute definitions
|
||||
pre_create_attr_defs = []
|
||||
|
||||
@property
|
||||
def show_order(self):
|
||||
"""Order in which is creator shown in UI.
|
||||
|
||||
Returns:
|
||||
int: Order in which is creator shown (less == earlier). By default
|
||||
is using Creator's 'order' or processing.
|
||||
"""
|
||||
|
||||
return self.order
|
||||
|
||||
@abstractmethod
|
||||
def create(self, subset_name, instance_data, pre_create_data):
|
||||
"""Create new instance and store it.
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ CREATOR_THUMBNAIL_ENABLED_ROLE = QtCore.Qt.UserRole + 5
|
|||
FAMILY_ROLE = QtCore.Qt.UserRole + 6
|
||||
GROUP_ROLE = QtCore.Qt.UserRole + 7
|
||||
CONVERTER_IDENTIFIER_ROLE = QtCore.Qt.UserRole + 8
|
||||
CREATOR_SORT_ROLE = QtCore.Qt.UserRole + 9
|
||||
|
||||
|
||||
__all__ = (
|
||||
|
|
@ -36,6 +37,7 @@ __all__ = (
|
|||
"IS_GROUP_ROLE",
|
||||
"CREATOR_IDENTIFIER_ROLE",
|
||||
"CREATOR_THUMBNAIL_ENABLED_ROLE",
|
||||
"CREATOR_SORT_ROLE",
|
||||
"FAMILY_ROLE",
|
||||
"GROUP_ROLE",
|
||||
"CONVERTER_IDENTIFIER_ROLE",
|
||||
|
|
|
|||
|
|
@ -832,7 +832,8 @@ class CreatorItem:
|
|||
default_variants,
|
||||
create_allow_context_change,
|
||||
create_allow_thumbnail,
|
||||
pre_create_attributes_defs
|
||||
show_order,
|
||||
pre_create_attributes_defs,
|
||||
):
|
||||
self.identifier = identifier
|
||||
self.creator_type = creator_type
|
||||
|
|
@ -846,6 +847,7 @@ class CreatorItem:
|
|||
self.default_variants = default_variants
|
||||
self.create_allow_context_change = create_allow_context_change
|
||||
self.create_allow_thumbnail = create_allow_thumbnail
|
||||
self.show_order = show_order
|
||||
self.pre_create_attributes_defs = pre_create_attributes_defs
|
||||
|
||||
def get_group_label(self):
|
||||
|
|
@ -869,6 +871,7 @@ class CreatorItem:
|
|||
pre_create_attr_defs = None
|
||||
create_allow_context_change = None
|
||||
create_allow_thumbnail = None
|
||||
show_order = creator.order
|
||||
if creator_type is CreatorTypes.artist:
|
||||
description = creator.get_description()
|
||||
detail_description = creator.get_detail_description()
|
||||
|
|
@ -877,6 +880,7 @@ class CreatorItem:
|
|||
pre_create_attr_defs = creator.get_pre_create_attr_defs()
|
||||
create_allow_context_change = creator.create_allow_context_change
|
||||
create_allow_thumbnail = creator.create_allow_thumbnail
|
||||
show_order = creator.show_order
|
||||
|
||||
identifier = creator.identifier
|
||||
return cls(
|
||||
|
|
@ -892,7 +896,8 @@ class CreatorItem:
|
|||
default_variants,
|
||||
create_allow_context_change,
|
||||
create_allow_thumbnail,
|
||||
pre_create_attr_defs
|
||||
show_order,
|
||||
pre_create_attr_defs,
|
||||
)
|
||||
|
||||
def to_data(self):
|
||||
|
|
@ -915,6 +920,7 @@ class CreatorItem:
|
|||
"default_variants": self.default_variants,
|
||||
"create_allow_context_change": self.create_allow_context_change,
|
||||
"create_allow_thumbnail": self.create_allow_thumbnail,
|
||||
"show_order": self.show_order,
|
||||
"pre_create_attributes_defs": pre_create_attributes_defs,
|
||||
}
|
||||
|
||||
|
|
@ -1502,9 +1508,6 @@ class BasePublisherController(AbstractPublisherController):
|
|||
def _reset_attributes(self):
|
||||
"""Reset most of attributes that can be reset."""
|
||||
|
||||
# Reset creator items
|
||||
self._creator_items = None
|
||||
|
||||
self.publish_is_running = False
|
||||
self.publish_has_validated = False
|
||||
self.publish_has_crashed = False
|
||||
|
|
@ -1760,6 +1763,8 @@ class PublisherController(BasePublisherController):
|
|||
self._resetting_plugins = True
|
||||
|
||||
self._create_context.reset_plugins()
|
||||
# Reset creator items
|
||||
self._creator_items = None
|
||||
|
||||
self._resetting_plugins = False
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ from .tasks_widget import CreateWidgetTasksWidget
|
|||
from .precreate_widget import PreCreateWidget
|
||||
from ..constants import (
|
||||
VARIANT_TOOLTIP,
|
||||
CREATOR_IDENTIFIER_ROLE,
|
||||
FAMILY_ROLE,
|
||||
CREATOR_IDENTIFIER_ROLE,
|
||||
CREATOR_THUMBNAIL_ENABLED_ROLE,
|
||||
CREATOR_SORT_ROLE,
|
||||
)
|
||||
|
||||
SEPARATORS = ("---separator---", "---")
|
||||
|
|
@ -90,12 +91,19 @@ class CreatorShortDescWidget(QtWidgets.QWidget):
|
|||
self._description_label.setText(description)
|
||||
|
||||
|
||||
class CreatorsProxyModel(QtCore.QSortFilterProxyModel):
|
||||
def lessThan(self, left, right):
|
||||
l_show_order = left.data(CREATOR_SORT_ROLE)
|
||||
r_show_order = right.data(CREATOR_SORT_ROLE)
|
||||
if l_show_order == r_show_order:
|
||||
return super(CreatorsProxyModel, self).lessThan(left, right)
|
||||
return l_show_order < r_show_order
|
||||
|
||||
|
||||
class CreateWidget(QtWidgets.QWidget):
|
||||
def __init__(self, controller, parent=None):
|
||||
super(CreateWidget, self).__init__(parent)
|
||||
|
||||
self.setWindowTitle("Create new instance")
|
||||
|
||||
self._controller = controller
|
||||
|
||||
self._asset_name = None
|
||||
|
|
@ -141,7 +149,7 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
|
||||
creators_view = QtWidgets.QListView(creators_view_widget)
|
||||
creators_model = QtGui.QStandardItemModel()
|
||||
creators_sort_model = QtCore.QSortFilterProxyModel()
|
||||
creators_sort_model = CreatorsProxyModel()
|
||||
creators_sort_model.setSourceModel(creators_model)
|
||||
creators_view.setModel(creators_sort_model)
|
||||
|
||||
|
|
@ -441,7 +449,8 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
|
||||
# Add new families
|
||||
new_creators = set()
|
||||
for identifier, creator_item in self._controller.creator_items.items():
|
||||
creator_items_by_identifier = self._controller.creator_items
|
||||
for identifier, creator_item in creator_items_by_identifier.items():
|
||||
if creator_item.creator_type != "artist":
|
||||
continue
|
||||
|
||||
|
|
@ -457,6 +466,7 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
self._creators_model.appendRow(item)
|
||||
|
||||
item.setData(creator_item.label, QtCore.Qt.DisplayRole)
|
||||
item.setData(creator_item.show_order, CREATOR_SORT_ROLE)
|
||||
item.setData(identifier, CREATOR_IDENTIFIER_ROLE)
|
||||
item.setData(
|
||||
creator_item.create_allow_thumbnail,
|
||||
|
|
@ -482,8 +492,9 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
index = indexes[0]
|
||||
|
||||
identifier = index.data(CREATOR_IDENTIFIER_ROLE)
|
||||
create_item = creator_items_by_identifier.get(identifier)
|
||||
|
||||
self._set_creator_by_identifier(identifier)
|
||||
self._set_creator(create_item)
|
||||
|
||||
def _on_plugins_refresh(self):
|
||||
# Trigger refresh only if is visible
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue