mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
initial commit
This commit is contained in:
parent
65865c2e8f
commit
175185d177
8 changed files with 324 additions and 469 deletions
|
|
@ -14,12 +14,10 @@ import arrow
|
|||
import pyblish.api
|
||||
|
||||
from ayon_core.client import (
|
||||
get_assets,
|
||||
get_asset_by_id,
|
||||
get_asset_by_name,
|
||||
get_subsets,
|
||||
get_asset_name_identifier,
|
||||
)
|
||||
from ayon_core.lib.events import EventSystem
|
||||
from ayon_core.lib.events import QueuedEventSystem
|
||||
from ayon_core.lib.attribute_definitions import (
|
||||
UIDef,
|
||||
serialize_attr_defs,
|
||||
|
|
@ -43,6 +41,7 @@ from ayon_core.pipeline.create.context import (
|
|||
ConvertorsOperationFailed,
|
||||
)
|
||||
from ayon_core.pipeline.publish import get_publish_instance_label
|
||||
from ayon_core.tools.ayon_utils.models import HierarchyModel
|
||||
|
||||
# Define constant for plugin orders offset
|
||||
PLUGIN_ORDER_OFFSET = 0.5
|
||||
|
|
@ -69,101 +68,17 @@ class MainThreadItem:
|
|||
class AssetDocsCache:
|
||||
"""Cache asset documents for creation part."""
|
||||
|
||||
projection = {
|
||||
"_id": True,
|
||||
"name": True,
|
||||
"data.visualParent": True,
|
||||
"data.tasks": True,
|
||||
"data.parents": True,
|
||||
}
|
||||
|
||||
def __init__(self, controller):
|
||||
self._controller = controller
|
||||
self._asset_docs = None
|
||||
self._asset_docs_hierarchy = None
|
||||
self._task_names_by_asset_name = {}
|
||||
self._asset_docs_by_name = {}
|
||||
self._full_asset_docs_by_name = {}
|
||||
|
||||
def reset(self):
|
||||
self._asset_docs = None
|
||||
self._asset_docs_hierarchy = None
|
||||
self._task_names_by_asset_name = {}
|
||||
self._asset_docs_by_name = {}
|
||||
self._full_asset_docs_by_name = {}
|
||||
|
||||
def _query(self):
|
||||
if self._asset_docs is not None:
|
||||
return
|
||||
|
||||
project_name = self._controller.project_name
|
||||
asset_docs = list(get_assets(
|
||||
project_name, fields=self.projection.keys()
|
||||
))
|
||||
asset_docs_by_name = {}
|
||||
task_names_by_asset_name = {}
|
||||
for asset_doc in asset_docs:
|
||||
if "data" not in asset_doc:
|
||||
asset_doc["data"] = {"tasks": {}, "visualParent": None}
|
||||
elif "tasks" not in asset_doc["data"]:
|
||||
asset_doc["data"]["tasks"] = {}
|
||||
|
||||
asset_name = get_asset_name_identifier(asset_doc)
|
||||
asset_tasks = asset_doc["data"]["tasks"]
|
||||
task_names_by_asset_name[asset_name] = list(asset_tasks.keys())
|
||||
asset_docs_by_name[asset_name] = asset_doc
|
||||
|
||||
self._asset_docs = asset_docs
|
||||
self._asset_docs_by_name = asset_docs_by_name
|
||||
self._task_names_by_asset_name = task_names_by_asset_name
|
||||
|
||||
def get_asset_docs(self):
|
||||
self._query()
|
||||
return copy.deepcopy(self._asset_docs)
|
||||
|
||||
def get_asset_hierarchy(self):
|
||||
"""Prepare asset documents into hierarchy.
|
||||
|
||||
Convert ObjectId to string. Asset id is not used during whole
|
||||
process of publisher but asset name is used rather.
|
||||
|
||||
Returns:
|
||||
Dict[Union[str, None]: Any]: Mapping of parent id to it's children.
|
||||
Top level assets have parent id 'None'.
|
||||
"""
|
||||
|
||||
if self._asset_docs_hierarchy is None:
|
||||
_queue = collections.deque(self.get_asset_docs())
|
||||
|
||||
output = collections.defaultdict(list)
|
||||
while _queue:
|
||||
asset_doc = _queue.popleft()
|
||||
asset_doc["_id"] = str(asset_doc["_id"])
|
||||
parent_id = asset_doc["data"]["visualParent"]
|
||||
if parent_id is not None:
|
||||
parent_id = str(parent_id)
|
||||
asset_doc["data"]["visualParent"] = parent_id
|
||||
output[parent_id].append(asset_doc)
|
||||
self._asset_docs_hierarchy = output
|
||||
return copy.deepcopy(self._asset_docs_hierarchy)
|
||||
|
||||
def get_task_names_by_asset_name(self):
|
||||
self._query()
|
||||
return copy.deepcopy(self._task_names_by_asset_name)
|
||||
|
||||
def get_asset_by_name(self, asset_name):
|
||||
self._query()
|
||||
asset_doc = self._asset_docs_by_name.get(asset_name)
|
||||
if asset_doc is None:
|
||||
return None
|
||||
return copy.deepcopy(asset_doc)
|
||||
|
||||
def get_full_asset_by_name(self, asset_name):
|
||||
self._query()
|
||||
if asset_name not in self._full_asset_docs_by_name:
|
||||
asset_doc = self._asset_docs_by_name.get(asset_name)
|
||||
project_name = self._controller.project_name
|
||||
full_asset_doc = get_asset_by_id(project_name, asset_doc["_id"])
|
||||
full_asset_doc = get_asset_by_name(project_name, asset_name)
|
||||
self._full_asset_docs_by_name[asset_name] = full_asset_doc
|
||||
return copy.deepcopy(self._full_asset_docs_by_name[asset_name])
|
||||
|
||||
|
|
@ -1104,18 +1019,6 @@ class AbstractPublisherController(object):
|
|||
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_asset_docs(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_asset_hierarchy(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_task_names_by_asset_names(self, asset_names):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_existing_subset_names(self, asset_name):
|
||||
pass
|
||||
|
|
@ -1499,13 +1402,22 @@ class BasePublisherController(AbstractPublisherController):
|
|||
"""
|
||||
|
||||
if self._event_system is None:
|
||||
self._event_system = EventSystem()
|
||||
self._event_system = QueuedEventSystem()
|
||||
return self._event_system
|
||||
|
||||
def _emit_event(self, topic, data=None):
|
||||
# Events system
|
||||
def emit_event(self, topic, data=None, source=None):
|
||||
"""Use implemented event system to trigger event."""
|
||||
|
||||
if data is None:
|
||||
data = {}
|
||||
self.event_system.emit(topic, data, "controller")
|
||||
self.event_system.emit(topic, data, source)
|
||||
|
||||
def register_event_callback(self, topic, callback):
|
||||
self.event_system.add_callback(topic, callback)
|
||||
|
||||
def _emit_event(self, topic, data=None):
|
||||
self.emit_event(topic, data, "controller")
|
||||
|
||||
def _get_host_is_valid(self):
|
||||
return self._host_is_valid
|
||||
|
|
@ -1738,6 +1650,7 @@ class PublisherController(BasePublisherController):
|
|||
self._resetting_instances = False
|
||||
|
||||
# Cacher of avalon documents
|
||||
self._hierarchy_model = HierarchyModel(self)
|
||||
self._asset_docs_cache = AssetDocsCache(self)
|
||||
|
||||
@property
|
||||
|
|
@ -1794,11 +1707,24 @@ class PublisherController(BasePublisherController):
|
|||
"""Publish plugins."""
|
||||
return self._create_context.publish_plugins
|
||||
|
||||
# --- Publish specific callbacks ---
|
||||
def get_asset_docs(self):
|
||||
"""Get asset documents from cache for whole project."""
|
||||
return self._asset_docs_cache.get_asset_docs()
|
||||
# Hierarchy model
|
||||
def get_folder_items(self, project_name, sender=None):
|
||||
return self._hierarchy_model.get_folder_items(project_name, sender)
|
||||
|
||||
def get_task_items(self, project_name, folder_id, sender=None):
|
||||
return self._hierarchy_model.get_task_items(
|
||||
project_name, folder_id, sender
|
||||
)
|
||||
|
||||
def get_folder_entity(self, project_name, folder_id):
|
||||
return self._hierarchy_model.get_folder_entity(
|
||||
project_name, folder_id
|
||||
)
|
||||
|
||||
def get_task_entity(self, project_name, task_id):
|
||||
return self._hierarchy_model.get_task_entity(project_name, task_id)
|
||||
|
||||
# --- Publish specific callbacks ---
|
||||
def get_context_title(self):
|
||||
"""Get context title for artist shown at the top of main window."""
|
||||
|
||||
|
|
@ -1813,32 +1739,18 @@ class PublisherController(BasePublisherController):
|
|||
|
||||
return context_title
|
||||
|
||||
def get_asset_hierarchy(self):
|
||||
"""Prepare asset documents into hierarchy."""
|
||||
|
||||
return self._asset_docs_cache.get_asset_hierarchy()
|
||||
|
||||
def get_task_names_by_asset_names(self, asset_names):
|
||||
"""Prepare task names by asset name."""
|
||||
task_names_by_asset_name = (
|
||||
self._asset_docs_cache.get_task_names_by_asset_name()
|
||||
)
|
||||
result = {}
|
||||
for asset_name in asset_names:
|
||||
result[asset_name] = set(
|
||||
task_names_by_asset_name.get(asset_name) or []
|
||||
)
|
||||
return result
|
||||
|
||||
def get_existing_subset_names(self, asset_name):
|
||||
project_name = self.project_name
|
||||
asset_doc = self._asset_docs_cache.get_asset_by_name(asset_name)
|
||||
if not asset_doc:
|
||||
folder_item = self._hierarchy_model.get_folder_item_by_path(
|
||||
project_name, asset_name
|
||||
)
|
||||
if not folder_item:
|
||||
return None
|
||||
|
||||
asset_id = asset_doc["_id"]
|
||||
subset_docs = get_subsets(
|
||||
project_name, asset_ids=[asset_id], fields=["name"]
|
||||
project_name,
|
||||
asset_ids=[folder_item.entity_id],
|
||||
fields=["name"]
|
||||
)
|
||||
return {
|
||||
subset_doc["name"]
|
||||
|
|
@ -1858,8 +1770,6 @@ class PublisherController(BasePublisherController):
|
|||
# Reset avalon context
|
||||
self._create_context.reset_current_context()
|
||||
|
||||
self._asset_docs_cache.reset()
|
||||
|
||||
self._reset_plugins()
|
||||
# Publish part must be reset after plugins
|
||||
self._reset_publish()
|
||||
|
|
|
|||
|
|
@ -251,15 +251,9 @@ class QtRemotePublishController(BasePublisherController):
|
|||
|
||||
pass
|
||||
|
||||
def get_asset_docs(self):
|
||||
pass
|
||||
|
||||
def get_asset_hierarchy(self):
|
||||
pass
|
||||
|
||||
def get_task_names_by_asset_names(self, asset_names):
|
||||
pass
|
||||
|
||||
def get_existing_subset_names(self, asset_name):
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -2,99 +2,13 @@ import collections
|
|||
|
||||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
|
||||
from ayon_core.tools.utils.assets_widget import (
|
||||
get_asset_icon,
|
||||
)
|
||||
from ayon_core.tools.utils import (
|
||||
PlaceholderLineEdit,
|
||||
RecursiveSortFilterProxyModel,
|
||||
)
|
||||
from ayon_core.tools.utils.assets_widget import (
|
||||
SingleSelectAssetsWidget,
|
||||
ASSET_ID_ROLE,
|
||||
ASSET_NAME_ROLE,
|
||||
ASSET_PATH_ROLE,
|
||||
get_asset_icon,
|
||||
)
|
||||
|
||||
|
||||
class CreateWidgetAssetsWidget(SingleSelectAssetsWidget):
|
||||
current_context_required = QtCore.Signal()
|
||||
header_height_changed = QtCore.Signal(int)
|
||||
|
||||
def __init__(self, controller, parent):
|
||||
self._controller = controller
|
||||
super(CreateWidgetAssetsWidget, self).__init__(parent)
|
||||
|
||||
self.set_refresh_btn_visibility(False)
|
||||
self.set_current_asset_btn_visibility(False)
|
||||
|
||||
self._last_selection = None
|
||||
self._enabled = None
|
||||
|
||||
self._last_filter_height = None
|
||||
|
||||
def get_project_name(self):
|
||||
return self._controller.project_name
|
||||
|
||||
def get_selected_asset_name(self):
|
||||
selection_model = self._view.selectionModel()
|
||||
indexes = selection_model.selectedRows()
|
||||
for index in indexes:
|
||||
return index.data(ASSET_PATH_ROLE)
|
||||
return None
|
||||
|
||||
def _check_header_height(self):
|
||||
"""Catch header height changes.
|
||||
|
||||
Label on top of creaters should have same height so Creators view has
|
||||
same offset.
|
||||
"""
|
||||
height = self.header_widget.height()
|
||||
if height != self._last_filter_height:
|
||||
self._last_filter_height = height
|
||||
self.header_height_changed.emit(height)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
super(CreateWidgetAssetsWidget, self).resizeEvent(event)
|
||||
self._check_header_height()
|
||||
|
||||
def showEvent(self, event):
|
||||
super(CreateWidgetAssetsWidget, self).showEvent(event)
|
||||
self._check_header_height()
|
||||
|
||||
def _on_current_asset_click(self):
|
||||
self.current_context_required.emit()
|
||||
|
||||
def set_enabled(self, enabled):
|
||||
if self._enabled == enabled:
|
||||
return
|
||||
self._enabled = enabled
|
||||
if not enabled:
|
||||
self._last_selection = self.get_selected_asset_id()
|
||||
self._clear_selection()
|
||||
elif self._last_selection is not None:
|
||||
self.select_asset(self._last_selection)
|
||||
|
||||
def _select_indexes(self, *args, **kwargs):
|
||||
super(CreateWidgetAssetsWidget, self)._select_indexes(*args, **kwargs)
|
||||
if self._enabled:
|
||||
return
|
||||
self._last_selection = self.get_selected_asset_id()
|
||||
self._clear_selection()
|
||||
|
||||
def update_current_asset(self):
|
||||
# Hide set current asset if there is no one
|
||||
asset_name = self._get_current_asset_name()
|
||||
self.set_current_asset_btn_visibility(bool(asset_name))
|
||||
|
||||
def _get_current_asset_name(self):
|
||||
return self._controller.current_asset_name
|
||||
|
||||
def _create_source_model(self):
|
||||
return AssetsHierarchyModel(self._controller)
|
||||
|
||||
def _refresh_model(self):
|
||||
self._model.reset()
|
||||
self._on_model_refresh(self._model.rowCount() > 0)
|
||||
|
||||
|
||||
class AssetsHierarchyModel(QtGui.QStandardItemModel):
|
||||
"""Assets hierarchy model.
|
||||
|
|
@ -119,7 +33,8 @@ class AssetsHierarchyModel(QtGui.QStandardItemModel):
|
|||
self._items_by_name = {}
|
||||
self._items_by_path = {}
|
||||
self._items_by_asset_id = {}
|
||||
assets_by_parent_id = self._controller.get_asset_hierarchy()
|
||||
# assets_by_parent_id = self._controller.get_asset_hierarchy()
|
||||
assets_by_parent_id = {}
|
||||
|
||||
items_by_name = {}
|
||||
items_by_path = {}
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
|
||||
from ayon_core.lib.events import QueuedEventSystem
|
||||
from ayon_core.tools.utils import PlaceholderLineEdit
|
||||
|
||||
from ayon_core.tools.ayon_utils.widgets import FoldersWidget, TasksWidget
|
||||
|
||||
|
||||
class CreateSelectionModel(object):
|
||||
"""Model handling selection changes.
|
||||
|
||||
Triggering events:
|
||||
- "selection.project.changed"
|
||||
- "selection.folder.changed"
|
||||
- "selection.task.changed"
|
||||
"""
|
||||
|
||||
event_source = "publisher.create.selection.model"
|
||||
|
||||
def __init__(self, controller):
|
||||
self._controller = controller
|
||||
|
||||
self._project_name = None
|
||||
self._folder_id = None
|
||||
self._task_name = None
|
||||
self._task_id = None
|
||||
|
||||
def get_selected_project_name(self):
|
||||
return self._project_name
|
||||
|
||||
def set_selected_project(self, project_name):
|
||||
if project_name == self._project_name:
|
||||
return
|
||||
|
||||
self._project_name = project_name
|
||||
self._controller.emit_event(
|
||||
"selection.project.changed",
|
||||
{"project_name": project_name},
|
||||
self.event_source
|
||||
)
|
||||
|
||||
def get_selected_folder_id(self):
|
||||
return self._folder_id
|
||||
|
||||
def set_selected_folder(self, folder_id):
|
||||
print(folder_id, self._folder_id)
|
||||
if folder_id == self._folder_id:
|
||||
return
|
||||
|
||||
self._folder_id = folder_id
|
||||
self._controller.emit_event(
|
||||
"selection.folder.changed",
|
||||
{
|
||||
"project_name": self._project_name,
|
||||
"folder_id": folder_id,
|
||||
},
|
||||
self.event_source
|
||||
)
|
||||
|
||||
def get_selected_task_name(self):
|
||||
return self._task_name
|
||||
|
||||
def get_selected_task_id(self):
|
||||
return self._task_id
|
||||
|
||||
def set_selected_task(self, task_id, task_name):
|
||||
if task_id == self._task_id:
|
||||
return
|
||||
|
||||
self._task_name = task_name
|
||||
self._task_id = task_id
|
||||
self._controller.emit_event(
|
||||
"selection.task.changed",
|
||||
{
|
||||
"project_name": self._project_name,
|
||||
"folder_id": self._folder_id,
|
||||
"task_name": task_name,
|
||||
"task_id": task_id,
|
||||
},
|
||||
self.event_source
|
||||
)
|
||||
|
||||
|
||||
class CreateHierarchyController:
|
||||
def __init__(self, controller):
|
||||
self._event_system = QueuedEventSystem()
|
||||
self._controller = controller
|
||||
self._selection_model = CreateSelectionModel(controller)
|
||||
|
||||
# Events system
|
||||
@property
|
||||
def event_system(self):
|
||||
return self._event_system
|
||||
|
||||
def emit_event(self, topic, data=None, source=None):
|
||||
"""Use implemented event system to trigger event."""
|
||||
|
||||
if data is None:
|
||||
data = {}
|
||||
print("emit_event", topic, data, source)
|
||||
self.event_system.emit(topic, data, source)
|
||||
|
||||
def register_event_callback(self, topic, callback):
|
||||
self.event_system.add_callback(topic, callback)
|
||||
|
||||
def get_project_name(self):
|
||||
return self._controller.project_name
|
||||
|
||||
def get_folder_items(self, project_name, sender=None):
|
||||
return self._controller.get_folder_items(project_name, sender)
|
||||
|
||||
def get_task_items(self, project_name, folder_id, sender=None):
|
||||
return self._controller.get_task_items(
|
||||
project_name, folder_id, sender
|
||||
)
|
||||
|
||||
# Selection model
|
||||
def set_selected_project(self, project_name):
|
||||
self._selection_model.set_selected_project(project_name)
|
||||
|
||||
def set_selected_folder(self, folder_id):
|
||||
self._selection_model.set_selected_folder(folder_id)
|
||||
|
||||
def set_selected_task(self, task_id, task_name):
|
||||
self._selection_model.set_selected_task(task_id, task_name)
|
||||
|
||||
|
||||
class CreateContextWidget(QtWidgets.QWidget):
|
||||
folder_changed = QtCore.Signal()
|
||||
task_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, controller, parent):
|
||||
super(CreateContextWidget, self).__init__(parent)
|
||||
|
||||
self._controller = controller
|
||||
self._enabled = True
|
||||
self._last_folder_id = None
|
||||
self._last_selected_task_name = None
|
||||
|
||||
headers_widget = QtWidgets.QWidget(self)
|
||||
|
||||
folder_filter_input = PlaceholderLineEdit(headers_widget)
|
||||
folder_filter_input.setPlaceholderText("Filter folders..")
|
||||
|
||||
current_context_btn = QtWidgets.QPushButton(
|
||||
"Go to current context", headers_widget
|
||||
)
|
||||
current_context_btn.setToolTip("Go to current context")
|
||||
current_context_btn.setVisible(False)
|
||||
|
||||
headers_layout = QtWidgets.QHBoxLayout(headers_widget)
|
||||
headers_layout.setContentsMargins(0, 0, 0, 0)
|
||||
headers_layout.addWidget(folder_filter_input, 1)
|
||||
headers_layout.addWidget(current_context_btn, 0)
|
||||
|
||||
hierarchy_controller = CreateHierarchyController(controller)
|
||||
|
||||
folders_widget = FoldersWidget(hierarchy_controller, self)
|
||||
tasks_widget = TasksWidget(hierarchy_controller, self)
|
||||
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||||
main_layout.setSpacing(0)
|
||||
main_layout.addWidget(headers_widget, 0)
|
||||
main_layout.addWidget(folders_widget, 2)
|
||||
main_layout.addWidget(tasks_widget, 1)
|
||||
|
||||
folders_widget.selection_changed.connect(self._on_folder_change)
|
||||
tasks_widget.selection_changed.connect(self._on_task_change)
|
||||
current_context_btn.clicked.connect(self._on_current_context_click)
|
||||
|
||||
self._folder_filter_input = folder_filter_input
|
||||
self._current_context_btn = current_context_btn
|
||||
self._folders_widget = folders_widget
|
||||
self._tasks_widget = tasks_widget
|
||||
self._hierarchy_controller = hierarchy_controller
|
||||
|
||||
def get_selected_folder_id(self):
|
||||
return self._folders_widget.get_selected_folder_id()
|
||||
|
||||
def get_selected_folder_path(self):
|
||||
return self._folders_widget.get_selected_folder_path()
|
||||
|
||||
def get_selected_task_name(self):
|
||||
return self._tasks_widget.get_selected_task_name()
|
||||
|
||||
def get_selected_task_type(self):
|
||||
return self._tasks_widget.get_selected_task_type()
|
||||
|
||||
def update_current_context_btn(self):
|
||||
# Hide set current asset if there is no one
|
||||
folder_path = self._controller.current_asset_name
|
||||
self._current_context_btn.setVisible(bool(folder_path))
|
||||
|
||||
def set_selected_context(self, folder_path, task_name):
|
||||
self._folders_widget.set_selected_folder_path(folder_path)
|
||||
self._tasks_widget.set_selected_task(task_name)
|
||||
|
||||
def is_enabled(self):
|
||||
return self._enabled
|
||||
|
||||
def set_enabled(self, enabled):
|
||||
if enabled is self._enabled:
|
||||
return
|
||||
|
||||
self.setEnabled(enabled)
|
||||
self._enabled = enabled
|
||||
|
||||
if not enabled:
|
||||
self._last_folder_id = self.get_selected_folder_id()
|
||||
self._folders_widget.set_selected_folder(None)
|
||||
last_selected_task_name = self.get_selected_task_name()
|
||||
if last_selected_task_name:
|
||||
self._last_selected_task_name = last_selected_task_name
|
||||
self._clear_selection()
|
||||
|
||||
elif self._last_selected_task_name is not None:
|
||||
self.set_selected_folder(self._last_folder_id)
|
||||
self.select_task_name(self._last_selected_task_name)
|
||||
|
||||
def refresh(self):
|
||||
self._hierarchy_controller.set_selected_project(
|
||||
self._controller.project_name
|
||||
)
|
||||
self._folders_widget.set_project_name(self._controller.project_name)
|
||||
|
||||
def _clear_selection(self):
|
||||
self._folders_widget.set_selected_folder(None)
|
||||
|
||||
def _on_folder_change(self):
|
||||
self.folder_changed.emit()
|
||||
|
||||
def _on_task_change(self):
|
||||
self.task_changed.emit()
|
||||
|
||||
def _on_current_context_click(self):
|
||||
# TODO implement
|
||||
folder_path = self._controller.current_asset_name
|
||||
task_name = self._controller.current_task_name
|
||||
|
|
@ -14,8 +14,7 @@ from .widgets import (
|
|||
IconValuePixmapLabel,
|
||||
CreateBtn,
|
||||
)
|
||||
from .assets_widget import CreateWidgetAssetsWidget
|
||||
from .tasks_widget import CreateWidgetTasksWidget
|
||||
from .create_context_widgets import CreateContextWidget
|
||||
from .precreate_widget import PreCreateWidget
|
||||
from ..constants import (
|
||||
VARIANT_TOOLTIP,
|
||||
|
|
@ -121,16 +120,7 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
|
||||
main_splitter_widget = QtWidgets.QSplitter(self)
|
||||
|
||||
context_widget = QtWidgets.QWidget(main_splitter_widget)
|
||||
|
||||
assets_widget = CreateWidgetAssetsWidget(controller, context_widget)
|
||||
tasks_widget = CreateWidgetTasksWidget(controller, context_widget)
|
||||
|
||||
context_layout = QtWidgets.QVBoxLayout(context_widget)
|
||||
context_layout.setContentsMargins(0, 0, 0, 0)
|
||||
context_layout.setSpacing(0)
|
||||
context_layout.addWidget(assets_widget, 2)
|
||||
context_layout.addWidget(tasks_widget, 1)
|
||||
context_widget = CreateContextWidget(controller, main_splitter_widget)
|
||||
|
||||
# --- Creators view ---
|
||||
creators_widget = QtWidgets.QWidget(main_splitter_widget)
|
||||
|
|
@ -279,11 +269,8 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
)
|
||||
variant_hints_btn.clicked.connect(self._on_variant_btn_click)
|
||||
variant_hints_menu.triggered.connect(self._on_variant_action)
|
||||
assets_widget.selection_changed.connect(self._on_asset_change)
|
||||
assets_widget.current_context_required.connect(
|
||||
self._on_current_session_context_request
|
||||
)
|
||||
tasks_widget.task_changed.connect(self._on_task_change)
|
||||
context_widget.folder_changed.connect(self._on_folder_change)
|
||||
context_widget.task_changed.connect(self._on_task_change)
|
||||
thumbnail_widget.thumbnail_created.connect(self._on_thumbnail_create)
|
||||
thumbnail_widget.thumbnail_cleared.connect(self._on_thumbnail_clear)
|
||||
|
||||
|
|
@ -299,8 +286,6 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
self._creators_splitter = creators_splitter
|
||||
|
||||
self._context_widget = context_widget
|
||||
self._assets_widget = assets_widget
|
||||
self._tasks_widget = tasks_widget
|
||||
|
||||
self.subset_name_input = subset_name_input
|
||||
|
||||
|
|
@ -324,7 +309,7 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
self._first_show = True
|
||||
self._last_thumbnail_path = None
|
||||
|
||||
self._last_current_context_asset = None
|
||||
self._last_current_context_folder_path = None
|
||||
self._last_current_context_task = None
|
||||
self._use_current_context = True
|
||||
|
||||
|
|
@ -340,31 +325,35 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
return self._context_widget.isEnabled()
|
||||
|
||||
def _get_asset_name(self):
|
||||
asset_name = None
|
||||
folder_path = None
|
||||
if self._context_change_is_enabled():
|
||||
asset_name = self._assets_widget.get_selected_asset_name()
|
||||
folder_path = self._context_widget.get_selected_folder_path()
|
||||
|
||||
if asset_name is None:
|
||||
asset_name = self.current_asset_name
|
||||
return asset_name or None
|
||||
if folder_path is None:
|
||||
folder_path = self.current_asset_name
|
||||
return folder_path or None
|
||||
|
||||
def _get_folder_id(self):
|
||||
folder_id = None
|
||||
if self._context_widget.isEnabled():
|
||||
folder_id = self._context_widget.get_selected_folder_id()
|
||||
return folder_id
|
||||
|
||||
def _get_task_name(self):
|
||||
task_name = None
|
||||
if self._context_change_is_enabled():
|
||||
# Don't use selection of task if asset is not set
|
||||
asset_name = self._assets_widget.get_selected_asset_name()
|
||||
if asset_name:
|
||||
task_name = self._tasks_widget.get_selected_task_name()
|
||||
folder_path = self._context_widget.get_selected_folder_path()
|
||||
if folder_path:
|
||||
task_name = self._context_widget.get_selected_task_name()
|
||||
|
||||
if not task_name:
|
||||
task_name = self.current_task_name
|
||||
return task_name
|
||||
|
||||
def _set_context_enabled(self, enabled):
|
||||
self._assets_widget.set_enabled(enabled)
|
||||
self._tasks_widget.set_enabled(enabled)
|
||||
check_prereq = self._context_widget.isEnabled() != enabled
|
||||
self._context_widget.setEnabled(enabled)
|
||||
self._context_widget.set_enabled(enabled)
|
||||
if check_prereq:
|
||||
self._invalidate_prereq()
|
||||
|
||||
|
|
@ -375,12 +364,12 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
self._use_current_context = True
|
||||
|
||||
def refresh(self):
|
||||
current_asset_name = self._controller.current_asset_name
|
||||
current_folder_path = self._controller.current_asset_name
|
||||
current_task_name = self._controller.current_task_name
|
||||
|
||||
# Get context before refresh to keep selection of asset and
|
||||
# task widgets
|
||||
asset_name = self._get_asset_name()
|
||||
folder_path = self._get_asset_name()
|
||||
task_name = self._get_task_name()
|
||||
|
||||
# Replace by current context if last loaded context was
|
||||
|
|
@ -388,16 +377,16 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
if (
|
||||
self._use_current_context
|
||||
or (
|
||||
self._last_current_context_asset
|
||||
and asset_name == self._last_current_context_asset
|
||||
self._last_current_context_folder_path
|
||||
and folder_path == self._last_current_context_folder_path
|
||||
and task_name == self._last_current_context_task
|
||||
)
|
||||
):
|
||||
asset_name = current_asset_name
|
||||
folder_path = current_folder_path
|
||||
task_name = current_task_name
|
||||
|
||||
# Store values for future refresh
|
||||
self._last_current_context_asset = current_asset_name
|
||||
self._last_current_context_folder_path = current_folder_path
|
||||
self._last_current_context_task = current_task_name
|
||||
self._use_current_context = False
|
||||
|
||||
|
|
@ -407,18 +396,16 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
# name
|
||||
self._set_context_enabled(False)
|
||||
|
||||
self._assets_widget.refresh()
|
||||
|
||||
# Refresh data before update of creators
|
||||
self._refresh_asset()
|
||||
self._context_widget.refresh()
|
||||
self._refresh_product_name()
|
||||
|
||||
# Then refresh creators which may trigger callbacks using refreshed
|
||||
# data
|
||||
self._refresh_creators()
|
||||
|
||||
self._assets_widget.update_current_asset()
|
||||
self._assets_widget.select_asset_by_name(asset_name)
|
||||
self._tasks_widget.set_asset_name(asset_name)
|
||||
self._tasks_widget.select_task_name(task_name)
|
||||
self._context_widget.update_current_context_btn()
|
||||
self._context_widget.set_selected_context(folder_path, task_name)
|
||||
|
||||
self._invalidate_prereq_deffered()
|
||||
|
||||
|
|
@ -460,7 +447,7 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
|
||||
self._on_variant_change()
|
||||
|
||||
def _refresh_asset(self):
|
||||
def _refresh_product_name(self):
|
||||
asset_name = self._get_asset_name()
|
||||
|
||||
# Skip if asset did not change
|
||||
|
|
@ -545,11 +532,8 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
# Trigger refresh only if is visible
|
||||
self.refresh()
|
||||
|
||||
def _on_asset_change(self):
|
||||
self._refresh_asset()
|
||||
|
||||
asset_name = self._assets_widget.get_selected_asset_name()
|
||||
self._tasks_widget.set_asset_name(asset_name)
|
||||
def _on_folder_change(self):
|
||||
self._refresh_product_name()
|
||||
if self._context_change_is_enabled():
|
||||
self._invalidate_prereq_deffered()
|
||||
|
||||
|
|
@ -564,12 +548,6 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
def _on_thumbnail_clear(self):
|
||||
self._last_thumbnail_path = None
|
||||
|
||||
def _on_current_session_context_request(self):
|
||||
self._assets_widget.select_current_asset()
|
||||
task_name = self.current_task_name
|
||||
if task_name:
|
||||
self._tasks_widget.select_task_name(task_name)
|
||||
|
||||
def _on_creator_item_change(self, new_index, _old_index):
|
||||
identifier = None
|
||||
if new_index.isValid():
|
||||
|
|
@ -616,7 +594,7 @@ class CreateWidget(QtWidgets.QWidget):
|
|||
!= self._context_change_is_enabled()
|
||||
):
|
||||
self._set_context_enabled(creator_item.create_allow_context_change)
|
||||
self._refresh_asset()
|
||||
self._refresh_product_name()
|
||||
|
||||
self._thumbnail_widget.setVisible(
|
||||
creator_item.create_allow_thumbnail
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
|
||||
from ayon_core.tools.utils.views import DeselectableTreeView
|
||||
from ayon_core.tools.utils.lib import get_default_task_icon
|
||||
|
||||
TASK_NAME_ROLE = QtCore.Qt.UserRole + 1
|
||||
|
|
@ -144,183 +143,3 @@ class TasksModel(QtGui.QStandardItemModel):
|
|||
|
||||
return super(TasksModel, self).headerData(section, orientation, role)
|
||||
|
||||
|
||||
class TasksProxyModel(QtCore.QSortFilterProxyModel):
|
||||
def lessThan(self, x_index, y_index):
|
||||
x_order = x_index.data(TASK_ORDER_ROLE)
|
||||
y_order = y_index.data(TASK_ORDER_ROLE)
|
||||
if x_order is not None and y_order is not None:
|
||||
if x_order < y_order:
|
||||
return True
|
||||
if x_order > y_order:
|
||||
return False
|
||||
|
||||
elif x_order is None and y_order is not None:
|
||||
return True
|
||||
|
||||
elif y_order is None and x_order is not None:
|
||||
return False
|
||||
|
||||
x_name = x_index.data(QtCore.Qt.DisplayRole)
|
||||
y_name = y_index.data(QtCore.Qt.DisplayRole)
|
||||
if x_name == y_name:
|
||||
return True
|
||||
|
||||
if x_name == tuple(sorted((x_name, y_name)))[0]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class CreateWidgetTasksWidget(QtWidgets.QWidget):
|
||||
"""Widget showing active Tasks
|
||||
|
||||
Deprecated:
|
||||
This widget will be removed soon. Please do not use it in new code.
|
||||
"""
|
||||
|
||||
task_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, controller, parent):
|
||||
self._controller = controller
|
||||
|
||||
self._enabled = None
|
||||
|
||||
super(CreateWidgetTasksWidget, self).__init__(parent)
|
||||
|
||||
tasks_view = DeselectableTreeView(self)
|
||||
tasks_view.setIndentation(0)
|
||||
tasks_view.setSortingEnabled(True)
|
||||
tasks_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
|
||||
header_view = tasks_view.header()
|
||||
header_view.setSortIndicator(0, QtCore.Qt.AscendingOrder)
|
||||
|
||||
tasks_model = TasksModel(self._controller)
|
||||
tasks_proxy = TasksProxyModel()
|
||||
tasks_proxy.setSourceModel(tasks_model)
|
||||
tasks_view.setModel(tasks_proxy)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(tasks_view)
|
||||
|
||||
selection_model = tasks_view.selectionModel()
|
||||
selection_model.selectionChanged.connect(self._on_task_change)
|
||||
|
||||
self._tasks_model = tasks_model
|
||||
self._tasks_proxy = tasks_proxy
|
||||
self._tasks_view = tasks_view
|
||||
|
||||
self._last_selected_task_name = None
|
||||
|
||||
def refresh(self):
|
||||
self._tasks_model.refresh()
|
||||
|
||||
def set_asset_id(self, asset_id):
|
||||
# Try and preserve the last selected task and reselect it
|
||||
# after switching assets. If there's no currently selected
|
||||
# asset keep whatever the "last selected" was prior to it.
|
||||
current = self.get_selected_task_name()
|
||||
if current:
|
||||
self._last_selected_task_name = current
|
||||
|
||||
self._tasks_model.set_asset_id(asset_id)
|
||||
|
||||
if self._last_selected_task_name:
|
||||
self.select_task_name(self._last_selected_task_name)
|
||||
|
||||
# Force a task changed emit.
|
||||
self.task_changed.emit()
|
||||
|
||||
def _clear_selection(self):
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
selection_model.clearSelection()
|
||||
|
||||
def select_task_name(self, task_name):
|
||||
"""Select a task by name.
|
||||
|
||||
If the task does not exist in the current model then selection is only
|
||||
cleared.
|
||||
|
||||
Args:
|
||||
task_name (str): Name of the task to select.
|
||||
|
||||
"""
|
||||
task_view_model = self._tasks_view.model()
|
||||
if not task_view_model:
|
||||
return
|
||||
|
||||
# Clear selection
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
selection_model.clearSelection()
|
||||
|
||||
# Select the task
|
||||
mode = (
|
||||
QtCore.QItemSelectionModel.Select
|
||||
| QtCore.QItemSelectionModel.Rows
|
||||
)
|
||||
for row in range(task_view_model.rowCount()):
|
||||
index = task_view_model.index(row, 0)
|
||||
name = index.data(TASK_NAME_ROLE)
|
||||
if name == task_name:
|
||||
selection_model.select(index, mode)
|
||||
|
||||
# Set the currently active index
|
||||
self._tasks_view.setCurrentIndex(index)
|
||||
break
|
||||
|
||||
last_selected_task_name = self.get_selected_task_name()
|
||||
if last_selected_task_name:
|
||||
self._last_selected_task_name = last_selected_task_name
|
||||
|
||||
if not self._enabled:
|
||||
current = self.get_selected_task_name()
|
||||
if current:
|
||||
self._last_selected_task_name = current
|
||||
self._clear_selection()
|
||||
|
||||
def get_selected_task_name(self):
|
||||
"""Return name of task at current index (selected)
|
||||
|
||||
Returns:
|
||||
str: Name of the current task.
|
||||
|
||||
"""
|
||||
index = self._tasks_view.currentIndex()
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
if index.isValid() and selection_model.isSelected(index):
|
||||
return index.data(TASK_NAME_ROLE)
|
||||
return None
|
||||
|
||||
def get_selected_task_type(self):
|
||||
index = self._tasks_view.currentIndex()
|
||||
selection_model = self._tasks_view.selectionModel()
|
||||
if index.isValid() and selection_model.isSelected(index):
|
||||
return index.data(TASK_TYPE_ROLE)
|
||||
return None
|
||||
|
||||
def set_asset_name(self, asset_name):
|
||||
current = self.get_selected_task_name()
|
||||
if current:
|
||||
self._last_selected_task_name = current
|
||||
|
||||
self._tasks_model.set_asset_names([asset_name])
|
||||
if self._last_selected_task_name and self._enabled:
|
||||
self.select_task_name(self._last_selected_task_name)
|
||||
|
||||
# Force a task changed emit.
|
||||
self.task_changed.emit()
|
||||
|
||||
def set_enabled(self, enabled):
|
||||
self._enabled = enabled
|
||||
if not enabled:
|
||||
last_selected_task_name = self.get_selected_task_name()
|
||||
if last_selected_task_name:
|
||||
self._last_selected_task_name = last_selected_task_name
|
||||
self._clear_selection()
|
||||
|
||||
elif self._last_selected_task_name is not None:
|
||||
self.select_task_name(self._last_selected_task_name)
|
||||
|
||||
def _on_task_change(self):
|
||||
self.task_changed.emit()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ from ayon_core.pipeline.create import (
|
|||
TaskNotSetError,
|
||||
)
|
||||
from .thumbnail_widget import ThumbnailWidget
|
||||
from .assets_widget import AssetsDialog
|
||||
from .assets_dialog import AssetsDialog
|
||||
from .tasks_widget import TasksModel
|
||||
from .icons import (
|
||||
get_pixmap,
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ class TrayPublisherController(QtPublisherController):
|
|||
def host(self):
|
||||
return self._host
|
||||
|
||||
def reset_project_data_cache(self):
|
||||
self._asset_docs_cache.reset()
|
||||
def reset_hierarchy_cache(self):
|
||||
self._hierarchy_model.reset()
|
||||
|
||||
|
||||
class TrayPublisherRegistry(JSONSettingRegistry):
|
||||
|
|
@ -248,7 +248,7 @@ class TrayPublishWindow(PublisherWindow):
|
|||
def _on_project_select(self, project_name):
|
||||
# TODO register project specific plugin paths
|
||||
self._controller.save_changes(False)
|
||||
self._controller.reset_project_data_cache()
|
||||
self._controller.reset_hierarchy_cache()
|
||||
|
||||
self.reset()
|
||||
if not self._controller.instances:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue