Merge pull request #2863 from pypeclub/enhancement/OP-2880_NP-Fix-changing-task-on-publishing-instance

NewPublisher: Changing task on publishing instance
This commit is contained in:
Jakub Trllo 2022-03-10 09:34:23 +01:00 committed by GitHub
commit f91f7dfd42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 136 additions and 40 deletions

View file

@ -19,7 +19,7 @@ class CollectContextDataTestHost(
hosts = ["testhost"]
@classmethod
def get_instance_attr_defs(cls):
def get_attribute_defs(cls):
return [
attribute_definitions.BoolDef(
"test_bool",

View file

@ -20,7 +20,7 @@ class CollectInstanceOneTestHost(
hosts = ["testhost"]
@classmethod
def get_instance_attr_defs(cls):
def get_attribute_defs(cls):
return [
attribute_definitions.NumberDef(
"version",

View file

@ -1005,12 +1005,14 @@ class CreateContext:
if not instances:
return
task_names_by_asset_name = collections.defaultdict(set)
task_names_by_asset_name = {}
for instance in instances:
task_name = instance.get("task")
asset_name = instance.get("asset")
if asset_name and task_name:
task_names_by_asset_name[asset_name].add(task_name)
if asset_name:
task_names_by_asset_name[asset_name] = set()
if task_name:
task_names_by_asset_name[asset_name].add(task_name)
asset_names = [
asset_name

View file

@ -194,11 +194,15 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
"short": task_code
}
else:
elif "task" in anatomy_data:
# Just set 'task_name' variable to context task
task_name = anatomy_data["task"]["name"]
task_type = anatomy_data["task"]["type"]
else:
task_name = None
task_type = None
# Fill family in anatomy data
anatomy_data["family"] = instance.data.get("family")
@ -818,8 +822,12 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
# - is there a chance that task name is not filled in anatomy
# data?
# - should we use context task in that case?
task_name = instance.data["anatomyData"]["task"]["name"]
task_type = instance.data["anatomyData"]["task"]["type"]
anatomy_data = instance.data["anatomyData"]
task_name = None
task_type = None
if "task" in anatomy_data:
task_name = anatomy_data["task"]["name"]
task_type = anatomy_data["task"]["type"]
filtering_criteria = {
"families": instance.data["family"],
"hosts": instance.context.data["hostName"],

View file

@ -873,8 +873,6 @@ class PublisherController:
"""
for idx, plugin in enumerate(self.publish_plugins):
self._publish_progress = idx
# Add plugin to publish report
self._publish_report.add_plugin_iter(plugin, self._publish_context)
# Reset current plugin validations error
self._publish_current_plugin_validation_errors = None
@ -902,6 +900,9 @@ class PublisherController:
):
yield MainThreadItem(self.stop_publish)
# Add plugin to publish report
self._publish_report.add_plugin_iter(plugin, self._publish_context)
# Trigger callback that new plugin is going to be processed
self._trigger_callbacks(
self._publish_plugin_changed_callback_refs, plugin

View file

@ -8,7 +8,7 @@ try:
except Exception:
commonmark = None
from Qt import QtWidgets, QtCore, QtGui
from openpype.lib import TaskNotSetError
from openpype.pipeline.create import (
CreatorError,
SUBSET_NAME_ALLOWED_SYMBOLS
@ -563,10 +563,9 @@ class CreateDialog(QtWidgets.QDialog):
if variant_value is None:
variant_value = self.variant_input.text()
match = self._compiled_name_pattern.match(variant_value)
valid = bool(match)
self.create_btn.setEnabled(valid)
if not valid:
self.create_btn.setEnabled(True)
if not self._compiled_name_pattern.match(variant_value):
self.create_btn.setEnabled(False)
self._set_variant_state_property("invalid")
self.subset_name_input.setText("< Invalid variant >")
return
@ -576,9 +575,16 @@ class CreateDialog(QtWidgets.QDialog):
asset_doc = copy.deepcopy(self._asset_doc)
# Calculate subset name with Creator plugin
subset_name = self._selected_creator.get_subset_name(
variant_value, task_name, asset_doc, project_name
)
try:
subset_name = self._selected_creator.get_subset_name(
variant_value, task_name, asset_doc, project_name
)
except TaskNotSetError:
self.create_btn.setEnabled(False)
self._set_variant_state_property("invalid")
self.subset_name_input.setText("< Missing task >")
return
self.subset_name_input.setText(subset_name)
self._validate_subset_name(subset_name, variant_value)

View file

@ -467,12 +467,22 @@ class InstanceListView(AbstractInstanceView):
else:
active = False
group_names = set()
for instance_id in selected_instance_ids:
widget = self._widgets_by_id.get(instance_id)
if widget is not None:
widget.set_active(active)
if widget is None:
continue
widget.set_active(active)
group_name = self._group_by_instance_id.get(instance_id)
if group_name is not None:
group_names.add(group_name)
for group_name in group_names:
self._update_group_checkstate(group_name)
def _update_group_checkstate(self, group_name):
"""Update checkstate of one group."""
widget = self._group_widgets.get(group_name)
if widget is None:
return

View file

@ -17,9 +17,10 @@ class TasksModel(QtGui.QStandardItemModel):
controller (PublisherController): Controller which handles creation and
publishing.
"""
def __init__(self, controller):
def __init__(self, controller, allow_empty_task=False):
super(TasksModel, self).__init__()
self._allow_empty_task = allow_empty_task
self._controller = controller
self._items_by_name = {}
self._asset_names = []
@ -70,8 +71,14 @@ class TasksModel(QtGui.QStandardItemModel):
task_name (str): Name of task which should be available in asset's
tasks.
"""
task_names = self._task_names_by_asset_name.get(asset_name)
if task_names and task_name in task_names:
if asset_name not in self._task_names_by_asset_name:
return False
if self._allow_empty_task and not task_name:
return True
task_names = self._task_names_by_asset_name[asset_name]
if task_name in task_names:
return True
return False
@ -92,6 +99,8 @@ class TasksModel(QtGui.QStandardItemModel):
new_task_names = self.get_intersection_of_tasks(
task_names_by_asset_name
)
if self._allow_empty_task:
new_task_names.add("")
old_task_names = set(self._items_by_name.keys())
if new_task_names == old_task_names:
return
@ -111,7 +120,9 @@ class TasksModel(QtGui.QStandardItemModel):
item.setData(task_name, TASK_NAME_ROLE)
self._items_by_name[task_name] = item
new_items.append(item)
root_item.appendRows(new_items)
if new_items:
root_item.appendRows(new_items)
def headerData(self, section, orientation, role=None):
if role is None:

View file

@ -6,6 +6,7 @@ import collections
from Qt import QtWidgets, QtCore, QtGui
import qtawesome
from openpype.lib import TaskNotSetError
from openpype.widgets.attribute_defs import create_widget_for_attr_def
from openpype.tools import resources
from openpype.tools.flickcharm import FlickCharm
@ -470,6 +471,28 @@ class AssetsField(BaseClickableFrame):
self.set_selected_items(self._origin_value)
class TasksComboboxProxy(QtCore.QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(TasksComboboxProxy, self).__init__(*args, **kwargs)
self._filter_empty = False
def set_filter_empty(self, filter_empty):
if self._filter_empty is filter_empty:
return
self._filter_empty = filter_empty
self.invalidate()
def filterAcceptsRow(self, source_row, parent_index):
if self._filter_empty:
model = self.sourceModel()
source_index = model.index(
source_row, self.filterKeyColumn(), parent_index
)
if not source_index.data(QtCore.Qt.DisplayRole):
return False
return True
class TasksCombobox(QtWidgets.QComboBox):
"""Combobox to show tasks for selected instances.
@ -489,13 +512,16 @@ class TasksCombobox(QtWidgets.QComboBox):
delegate = QtWidgets.QStyledItemDelegate()
self.setItemDelegate(delegate)
model = TasksModel(controller)
self.setModel(model)
model = TasksModel(controller, True)
proxy_model = TasksComboboxProxy()
proxy_model.setSourceModel(model)
self.setModel(proxy_model)
self.currentIndexChanged.connect(self._on_index_change)
self._delegate = delegate
self._model = model
self._proxy_model = proxy_model
self._origin_value = []
self._origin_selection = []
self._selected_items = []
@ -506,6 +532,14 @@ class TasksCombobox(QtWidgets.QComboBox):
self._text = None
def set_invalid_empty_task(self, invalid=True):
self._proxy_model.set_filter_empty(invalid)
if invalid:
self._set_is_valid(False)
self.set_text("< One or more subsets require Task selected >")
else:
self.set_text(None)
def set_multiselection_text(self, text):
"""Change text shown when multiple different tasks are in context."""
self._multiselection_text = text
@ -595,6 +629,8 @@ class TasksCombobox(QtWidgets.QComboBox):
self._ignore_index_change = True
self._model.set_asset_names(asset_names)
self._proxy_model.set_filter_empty(False)
self._proxy_model.sort(0)
self._ignore_index_change = False
@ -640,6 +676,9 @@ class TasksCombobox(QtWidgets.QComboBox):
asset_task_combinations (list): List of tuples. Each item in
the list contain asset name and task name.
"""
self._proxy_model.set_filter_empty(False)
self._proxy_model.sort(0)
if asset_task_combinations is None:
asset_task_combinations = []
@ -931,7 +970,7 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
family_value_widget.set_value()
subset_value_widget.set_value()
submit_btn = QtWidgets.QPushButton("Submit", self)
submit_btn = QtWidgets.QPushButton("Confirm", self)
cancel_btn = QtWidgets.QPushButton("Cancel", self)
submit_btn.setEnabled(False)
cancel_btn.setEnabled(False)
@ -997,7 +1036,33 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
project_name = self.controller.project_name
subset_names = set()
invalid_tasks = False
for instance in self._current_instances:
new_variant_value = instance.get("variant")
new_asset_name = instance.get("asset")
new_task_name = instance.get("task")
if variant_value is not None:
new_variant_value = variant_value
if asset_name is not None:
new_asset_name = asset_name
if task_name is not None:
new_task_name = task_name
asset_doc = asset_docs_by_name[new_asset_name]
try:
new_subset_name = instance.creator.get_subset_name(
new_variant_value, new_task_name, asset_doc, project_name
)
except TaskNotSetError:
invalid_tasks = True
instance.set_task_invalid(True)
subset_names.add(instance["subset"])
continue
subset_names.add(new_subset_name)
if variant_value is not None:
instance["variant"] = variant_value
@ -1006,25 +1071,18 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
instance.set_asset_invalid(False)
if task_name is not None:
instance["task"] = task_name
instance["task"] = task_name or None
instance.set_task_invalid(False)
new_variant_value = instance.get("variant")
new_asset_name = instance.get("asset")
new_task_name = instance.get("task")
asset_doc = asset_docs_by_name[new_asset_name]
new_subset_name = instance.creator.get_subset_name(
new_variant_value, new_task_name, asset_doc, project_name
)
subset_names.add(new_subset_name)
instance["subset"] = new_subset_name
if invalid_tasks:
self.task_value_widget.set_invalid_empty_task()
self.subset_value_widget.set_value(subset_names)
self._set_btns_enabled(False)
self._set_btns_visible(False)
self._set_btns_visible(invalid_tasks)
self.instance_context_changed.emit()
@ -1097,7 +1155,7 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
variants.add(instance.get("variant") or self.unknown_value)
families.add(instance.get("family") or self.unknown_value)
asset_name = instance.get("asset") or self.unknown_value
task_name = instance.get("task") or self.unknown_value
task_name = instance.get("task") or ""
asset_names.add(asset_name)
asset_task_combinations.append((asset_name, task_name))
subset_names.add(instance.get("subset") or self.unknown_value)