Merge pull request #4433 from ynput/feature/creator_sorting

Publisher: Creators sorting
This commit is contained in:
Jakub Trllo 2023-02-08 18:06:44 +01:00 committed by GitHub
commit ffc3b8581a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 149 additions and 30 deletions

View file

@ -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,

View file

@ -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.

View file

@ -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.

View file

@ -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",

View file

@ -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

View file

@ -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