mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
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:
commit
f91f7dfd42
9 changed files with 136 additions and 40 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue