diff --git a/client/ayon_core/tools/publisher/control.py b/client/ayon_core/tools/publisher/control.py index 487748afd9..a7c23112b0 100644 --- a/client/ayon_core/tools/publisher/control.py +++ b/client/ayon_core/tools/publisher/control.py @@ -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() diff --git a/client/ayon_core/tools/publisher/control_qt.py b/client/ayon_core/tools/publisher/control_qt.py index 3d56c08131..53fed7866a 100644 --- a/client/ayon_core/tools/publisher/control_qt.py +++ b/client/ayon_core/tools/publisher/control_qt.py @@ -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 diff --git a/client/ayon_core/tools/publisher/widgets/assets_widget.py b/client/ayon_core/tools/publisher/widgets/assets_dialog.py similarity index 75% rename from client/ayon_core/tools/publisher/widgets/assets_widget.py rename to client/ayon_core/tools/publisher/widgets/assets_dialog.py index 1c5016de99..9b54767624 100644 --- a/client/ayon_core/tools/publisher/widgets/assets_widget.py +++ b/client/ayon_core/tools/publisher/widgets/assets_dialog.py @@ -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 = {} diff --git a/client/ayon_core/tools/publisher/widgets/create_context_widgets.py b/client/ayon_core/tools/publisher/widgets/create_context_widgets.py new file mode 100644 index 0000000000..317d922251 --- /dev/null +++ b/client/ayon_core/tools/publisher/widgets/create_context_widgets.py @@ -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 diff --git a/client/ayon_core/tools/publisher/widgets/create_widget.py b/client/ayon_core/tools/publisher/widgets/create_widget.py index 8eae205882..daaa167460 100644 --- a/client/ayon_core/tools/publisher/widgets/create_widget.py +++ b/client/ayon_core/tools/publisher/widgets/create_widget.py @@ -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 diff --git a/client/ayon_core/tools/publisher/widgets/tasks_widget.py b/client/ayon_core/tools/publisher/widgets/tasks_widget.py index 9a1b22b9a5..37c32ccb97 100644 --- a/client/ayon_core/tools/publisher/widgets/tasks_widget.py +++ b/client/ayon_core/tools/publisher/widgets/tasks_widget.py @@ -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() diff --git a/client/ayon_core/tools/publisher/widgets/widgets.py b/client/ayon_core/tools/publisher/widgets/widgets.py index bd5ab250bd..94825432ee 100644 --- a/client/ayon_core/tools/publisher/widgets/widgets.py +++ b/client/ayon_core/tools/publisher/widgets/widgets.py @@ -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, diff --git a/client/ayon_core/tools/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py index 79386d7ea0..07ec826db7 100644 --- a/client/ayon_core/tools/traypublisher/window.py +++ b/client/ayon_core/tools/traypublisher/window.py @@ -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: