From 88d6a848d3a830d0798b53c5adbaa5500e5a6345 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 10 Jul 2024 12:53:22 +0200 Subject: [PATCH] fix status filtering after refresh --- .../tools/loader/ui/products_delegates.py | 65 +++++++++++++------ .../tools/loader/ui/products_model.py | 38 +++++++---- .../tools/loader/ui/products_widget.py | 16 +++-- 3 files changed, 81 insertions(+), 38 deletions(-) diff --git a/client/ayon_core/tools/loader/ui/products_delegates.py b/client/ayon_core/tools/loader/ui/products_delegates.py index d54164c0f2..869bb5915c 100644 --- a/client/ayon_core/tools/loader/ui/products_delegates.py +++ b/client/ayon_core/tools/loader/ui/products_delegates.py @@ -1,4 +1,7 @@ import numbers +import uuid +from typing import Dict, Set + from qtpy import QtWidgets, QtCore, QtGui from ayon_core.tools.utils.lib import format_version @@ -74,7 +77,7 @@ class VersionsFilterModel(QtCore.QSortFilterProxyModel): class VersionComboBox(QtWidgets.QComboBox): - value_changed = QtCore.Signal(str) + value_changed = QtCore.Signal() def __init__(self, product_id, parent): super().__init__(parent) @@ -105,6 +108,11 @@ class VersionComboBox(QtWidgets.QComboBox): if self.currentIndex() != 0: self.setCurrentIndex(0) + def all_versions_filtered_out(self): + if self._items_by_id: + return self.count() == 0 + return False + def update_versions(self, version_items, current_version_id): self.blockSignals(True) version_items = list(version_items) @@ -129,7 +137,13 @@ class VersionComboBox(QtWidgets.QComboBox): if value == self._current_id: return self._current_id = value - self.value_changed.emit(self._product_id) + self.value_changed.emit() + + +class EditorInfo: + def __init__(self, widget): + self.widget = widget + self.added = False class VersionDelegate(QtWidgets.QStyledItemDelegate): @@ -139,7 +153,8 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self._editor_by_product_id = {} + + self._editor_by_id: Dict[str, EditorInfo] = {} self._statuses_filter = None def displayText(self, value, locale): @@ -149,8 +164,8 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate): def set_statuses_filter(self, status_names): self._statuses_filter = set(status_names) - for widget in self._editor_by_product_id.values(): - widget.set_statuses_filter(status_names) + for info in self._editor_by_id.values(): + info.widget.set_statuses_filter(status_names) def paint(self, painter, option, index): fg_color = index.data(QtCore.Qt.ForegroundRole) @@ -209,27 +224,21 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate): if not product_id: return + item_id = uuid.uuid4().hex + editor = VersionComboBox(product_id, parent) - self._editor_by_product_id[product_id] = editor - editor.value_changed.connect(self._on_editor_change) - editor.set_statuses_filter(self._statuses_filter) + editor.setProperty("itemId", item_id) - def on_destroy(obj): - self._on_destroy(product_id) + self._editor_by_id[item_id] = EditorInfo(editor) - editor.destroyed.connect(on_destroy) + def editor_changed(): + self._on_editor_change(item_id) + + editor.value_changed.connect(editor_changed) + editor.destroyed.connect(self._on_destroy) return editor - def _on_editor_change(self, product_id): - editor = self._editor_by_product_id[product_id] - - # Update model data - self.commitData.emit(editor) - - def _on_destroy(self, product_id): - self._editor_by_product_id.pop(product_id, None) - def setEditorData(self, editor, index): editor.clear() @@ -237,6 +246,10 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate): versions = index.data(VERSION_NAME_EDIT_ROLE) or [] version_id = index.data(VERSION_ID_ROLE) editor.update_versions(versions, version_id) + editor.set_statuses_filter(self._statuses_filter) + + item_id = editor.property("itemId") + self._editor_by_id[item_id].added = True def setModelData(self, editor, model, index): """Apply the integer version back in the model""" @@ -244,6 +257,18 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate): version_id = editor.itemData(editor.currentIndex()) model.setData(index, version_id, VERSION_NAME_EDIT_ROLE) + def _on_editor_change(self, item_id): + info = self._editor_by_id.get(item_id) + if info is None or not info.added: + return + + editor = info.widget + self.commitData.emit(editor) + + def _on_destroy(self, obj): + item_id = obj.property("itemId") + self._editor_by_id.pop(item_id, None) + class LoadedInSceneDelegate(QtWidgets.QStyledItemDelegate): """Delegate for Loaded in Scene state columns. diff --git a/client/ayon_core/tools/loader/ui/products_model.py b/client/ayon_core/tools/loader/ui/products_model.py index fb15507f1c..b2f8aad307 100644 --- a/client/ayon_core/tools/loader/ui/products_model.py +++ b/client/ayon_core/tools/loader/ui/products_model.py @@ -351,11 +351,10 @@ class ProductsModel(QtGui.QStandardItemModel): representation count by version id. sync_availability_by_version_id (Optional[str, Tuple[int, int]]): Mapping of sync availability by version id. - """ + """ model_item.setData(version_item.version_id, VERSION_ID_ROLE) model_item.setData(version_item.version, VERSION_NAME_ROLE) - model_item.setData(version_item.version_id, VERSION_ID_ROLE) model_item.setData(version_item.is_hero, VERSION_HERO_ROLE) model_item.setData( version_item.published_time, VERSION_PUBLISH_TIME_ROLE @@ -398,11 +397,11 @@ class ProductsModel(QtGui.QStandardItemModel): remote_site_icon, repre_count_by_version_id, sync_availability_by_version_id, + last_version_by_product_id, ): model_item = self._items_by_id.get(product_item.product_id) - versions = list(product_item.version_items.values()) - versions.sort() - last_version = versions[-1] + last_version = last_version_by_product_id[product_item.product_id] + statuses = { version_item.status for version_item in product_item.version_items.values() @@ -443,7 +442,7 @@ class ProductsModel(QtGui.QStandardItemModel): def get_last_project_name(self): return self._last_project_name - def refresh(self, project_name, folder_ids): + def refresh(self, project_name, folder_ids, status_names): self._clear() self._last_project_name = project_name @@ -473,16 +472,27 @@ class ProductsModel(QtGui.QStandardItemModel): product_item.product_id: product_item for product_item in product_items } - last_version_id_by_product_id = {} + last_version_by_product_id = {} for product_item in product_items: - versions = list(product_item.version_items.values()) - versions.sort() - last_version = versions[-1] - last_version_id_by_product_id[product_item.product_id] = ( - last_version.version_id + all_versions = list(product_item.version_items.values()) + all_versions.sort() + versions = [ + version_item + for version_item in all_versions + if status_names is None or version_item.status in status_names + ] + if versions: + last_version = versions[-1] + else: + last_version = all_versions[-1] + last_version_by_product_id[product_item.product_id] = ( + last_version ) - version_ids = set(last_version_id_by_product_id.values()) + version_ids = { + version_item.version_id + for version_item in last_version_by_product_id.values() + } repre_count_by_version_id = self._controller.get_versions_representation_count( project_name, version_ids ) @@ -559,6 +569,7 @@ class ProductsModel(QtGui.QStandardItemModel): remote_site_icon, repre_count_by_version_id, sync_availability_by_version_id, + last_version_by_product_id, ) new_items.append(item) @@ -581,6 +592,7 @@ class ProductsModel(QtGui.QStandardItemModel): remote_site_icon, repre_count_by_version_id, sync_availability_by_version_id, + last_version_by_product_id, ) new_merged_items.append(item) merged_product_types.add(product_item.product_type) diff --git a/client/ayon_core/tools/loader/ui/products_widget.py b/client/ayon_core/tools/loader/ui/products_widget.py index be4a0698e8..b0a8c61f9d 100644 --- a/client/ayon_core/tools/loader/ui/products_widget.py +++ b/client/ayon_core/tools/loader/ui/products_widget.py @@ -34,12 +34,17 @@ from .actions_utils import show_actions_menu class ProductsProxyModel(RecursiveSortFilterProxyModel): def __init__(self, parent=None): - super(ProductsProxyModel, self).__init__(parent) + super().__init__(parent) self._product_type_filters = {} self._statuses_filter = None self._ascending_sort = True + def get_statuses_filter(self): + if self._statuses_filter is None: + return None + return set(self._statuses_filter) + def set_product_type_filters(self, product_type_filters): self._product_type_filters = product_type_filters self.invalidateFilter() @@ -97,13 +102,13 @@ class ProductsProxyModel(RecursiveSortFilterProxyModel): if not self._ascending_sort: output = not output return output - return super(ProductsProxyModel, self).lessThan(left, right) + return super().lessThan(left, right) def sort(self, column, order=None): if order is None: order = QtCore.Qt.AscendingOrder self._ascending_sort = order == QtCore.Qt.AscendingOrder - super(ProductsProxyModel, self).sort(column, order) + super().sort(column, order) class ProductsWidget(QtWidgets.QWidget): @@ -245,8 +250,8 @@ class ProductsWidget(QtWidgets.QWidget): status_names (list[str]): The list of status names. """ - self._products_proxy_model.set_statuses_filter(status_names) self._version_delegate.set_statuses_filter(status_names) + self._products_proxy_model.set_statuses_filter(status_names) def set_product_type_filter(self, product_type_filters): """ @@ -314,7 +319,8 @@ class ProductsWidget(QtWidgets.QWidget): def _refresh_model(self): self._products_model.refresh( self._selected_project_name, - self._selected_folder_ids + self._selected_folder_ids, + self._products_proxy_model.get_statuses_filter() ) def _on_context_menu(self, point):