From c8bc9ab0ea30e3f7748f00473ff25210cab3ef32 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 May 2024 18:54:18 +0200 Subject: [PATCH 01/11] projects model has option to get status items --- .../ayon_core/tools/common_models/projects.py | 94 ++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/common_models/projects.py b/client/ayon_core/tools/common_models/projects.py index 19a38bee21..3911d0c403 100644 --- a/client/ayon_core/tools/common_models/projects.py +++ b/client/ayon_core/tools/common_models/projects.py @@ -5,7 +5,7 @@ import six from ayon_core.style import get_default_entity_icon_color -from ayon_core.lib import CacheItem +from ayon_core.lib import CacheItem, NestedCacheItem PROJECTS_MODEL_SENDER = "projects.model" @@ -17,6 +17,49 @@ def emit_event(self, topic, data, source): pass +class StatusItem: + """Item representing status of project. + + Args: + name (str): Status name ("Not ready"). + color (str): Status color in hex ("#434a56"). + short (str): Short status name ("NRD"). + icon (str): Icon name in MaterialIcons ("fiber_new"). + state (Literal["not_started", "in_progress", "done", "blocked"]): + Status state. + + """ + def __init__(self, name, color, short, icon, state): + self.name = name + self.color = color + self.short = short + self.icon = icon + self.state = state + + def to_data(self): + return { + "name": self.name, + "color": self.color, + "short": self.short, + "icon": self.icon, + "state": self.state, + } + + @classmethod + def from_data(cls, data): + return cls(**data) + + @classmethod + def from_project_item(cls, status_data): + return cls( + name=status_data["name"], + color=status_data["color"], + short=status_data["shortName"], + icon=status_data["icon"], + state=status_data["state"], + ) + + class ProjectItem: """Item representing folder entity on a server. @@ -89,6 +132,9 @@ def __init__(self, controller): self._projects_cache = CacheItem(default_factory=list) self._project_items_by_name = {} self._projects_by_name = {} + self._project_statuses_cache = NestedCacheItem( + levels=1, default_factory=list + ) self._is_refreshing = False self._controller = controller @@ -97,6 +143,7 @@ def reset(self): self._projects_cache.reset() self._project_items_by_name = {} self._projects_by_name = {} + self._project_statuses_cache.reset() def refresh(self): self._refresh_projects_cache() @@ -124,6 +171,34 @@ def get_project_entity(self, project_name): self._projects_by_name[project_name] = entity return self._projects_by_name[project_name] + def get_project_status_items(self, project_name, sender): + """Get project status items. + + Args: + project_name (str): Project name. + sender (Union[str, None]): Name of sender who asked for items. + + Returns: + list[StatusItem]: Status items for project. + + """ + statuses_cache = self._project_statuses_cache[project_name] + if not statuses_cache.is_valid: + with self._project_statuses_refresh_event_manager( + sender, project_name + ): + project_entity = None + if project_name: + project_entity = self.get_project_entity(project_name) + statuses = [] + if project_entity: + statuses = [ + StatusItem.from_project_item(status) + for status in project_entity["statuses"] + ] + statuses_cache.update_data(statuses) + return statuses_cache.get_data() + @contextlib.contextmanager def _project_refresh_event_manager(self, sender): self._is_refreshing = True @@ -143,6 +218,23 @@ def _project_refresh_event_manager(self, sender): ) self._is_refreshing = False + @contextlib.contextmanager + def _project_statuses_refresh_event_manager(self, sender, project_name): + self._controller.emit_event( + "projects.statuses.refresh.started", + {"sender": sender, "project_name": project_name}, + PROJECTS_MODEL_SENDER + ) + try: + yield + + finally: + self._controller.emit_event( + "projects.statuses.refresh.finished", + {"sender": sender, "project_name": project_name}, + PROJECTS_MODEL_SENDER + ) + def _refresh_projects_cache(self, sender=None): if self._is_refreshing: return None From c575420bb579f73cf1f4a738c85141b9b4203298 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 May 2024 18:55:00 +0200 Subject: [PATCH 02/11] project entities are cached values --- .../ayon_core/tools/common_models/projects.py | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/tools/common_models/projects.py b/client/ayon_core/tools/common_models/projects.py index 3911d0c403..d14963a4e9 100644 --- a/client/ayon_core/tools/common_models/projects.py +++ b/client/ayon_core/tools/common_models/projects.py @@ -131,10 +131,12 @@ class ProjectsModel(object): def __init__(self, controller): self._projects_cache = CacheItem(default_factory=list) self._project_items_by_name = {} - self._projects_by_name = {} self._project_statuses_cache = NestedCacheItem( levels=1, default_factory=list ) + self._projects_by_name = NestedCacheItem( + levels=1, default_factory=list + ) self._is_refreshing = False self._controller = controller @@ -142,8 +144,8 @@ def __init__(self, controller): def reset(self): self._projects_cache.reset() self._project_items_by_name = {} - self._projects_by_name = {} self._project_statuses_cache.reset() + self._projects_by_name.reset() def refresh(self): self._refresh_projects_cache() @@ -164,12 +166,23 @@ def get_project_items(self, sender): return self._projects_cache.get_data() def get_project_entity(self, project_name): - if project_name not in self._projects_by_name: + """Get project entity. + + Args: + project_name (str): Project name. + + Returns: + Union[dict[str, Any], None]: Project entity or None if project + was not found by name. + + """ + project_cache = self._projects_by_name[project_name] + if not project_cache.is_valid: entity = None if project_name: entity = ayon_api.get_project(project_name) - self._projects_by_name[project_name] = entity - return self._projects_by_name[project_name] + project_cache.update_data(entity) + return project_cache.get_data() def get_project_status_items(self, project_name, sender): """Get project status items. From 66122bfabe5fea58776ff5e2846ab8d3ef3eb27a Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 May 2024 18:55:28 +0200 Subject: [PATCH 03/11] removed unused attribute --- client/ayon_core/tools/common_models/projects.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/ayon_core/tools/common_models/projects.py b/client/ayon_core/tools/common_models/projects.py index d14963a4e9..fa308de0a9 100644 --- a/client/ayon_core/tools/common_models/projects.py +++ b/client/ayon_core/tools/common_models/projects.py @@ -130,7 +130,6 @@ def _get_project_items_from_entitiy(projects): class ProjectsModel(object): def __init__(self, controller): self._projects_cache = CacheItem(default_factory=list) - self._project_items_by_name = {} self._project_statuses_cache = NestedCacheItem( levels=1, default_factory=list ) @@ -143,7 +142,6 @@ def __init__(self, controller): def reset(self): self._projects_cache.reset() - self._project_items_by_name = {} self._project_statuses_cache.reset() self._projects_by_name.reset() From d572f929c2512c7ceea59fdba1cc480bee78f30a Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 May 2024 18:55:40 +0200 Subject: [PATCH 04/11] use helper method to create ProjectItem --- .../ayon_core/tools/common_models/projects.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/common_models/projects.py b/client/ayon_core/tools/common_models/projects.py index fa308de0a9..5df7178bcc 100644 --- a/client/ayon_core/tools/common_models/projects.py +++ b/client/ayon_core/tools/common_models/projects.py @@ -83,6 +83,23 @@ def __init__(self, name, active, is_library, icon=None): } self.icon = icon + @classmethod + def from_entity(cls, project_entity): + """Creates folder item from entity. + + Args: + project_entity (dict[str, Any]): Project entity. + + Returns: + ProjectItem: Project item. + + """ + return cls( + project_entity["name"], + project_entity["active"], + project_entity["library"], + ) + def to_data(self): """Converts folder item to data. @@ -122,7 +139,7 @@ def _get_project_items_from_entitiy(projects): """ return [ - ProjectItem(project["name"], project["active"], project["library"]) + ProjectItem.from_entity(project) for project in projects ] From 1c282b1bbb80266b3e7241111aefbe102651c695 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 May 2024 18:55:51 +0200 Subject: [PATCH 05/11] add docstring to 'refresh' method --- client/ayon_core/tools/common_models/projects.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/ayon_core/tools/common_models/projects.py b/client/ayon_core/tools/common_models/projects.py index 5df7178bcc..89dd881a10 100644 --- a/client/ayon_core/tools/common_models/projects.py +++ b/client/ayon_core/tools/common_models/projects.py @@ -163,6 +163,13 @@ def reset(self): self._projects_by_name.reset() def refresh(self): + """Refresh project items. + + This method will requery list of ProjectItem returned by + 'get_project_items'. + + To reset all cached items use 'reset' method. + """ self._refresh_projects_cache() def get_project_items(self, sender): From 235cd4b69b2c158aa2424173b2a647d99c9f50b9 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 May 2024 18:56:16 +0200 Subject: [PATCH 06/11] prepare backend for status value --- client/ayon_core/tools/loader/abstract.py | 25 +++++++++++++++++++ client/ayon_core/tools/loader/control.py | 5 ++++ .../ayon_core/tools/loader/models/products.py | 6 ++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/loader/abstract.py b/client/ayon_core/tools/loader/abstract.py index 7a7d335092..509db4d037 100644 --- a/client/ayon_core/tools/loader/abstract.py +++ b/client/ayon_core/tools/loader/abstract.py @@ -114,6 +114,7 @@ class VersionItem: thumbnail_id (Union[str, None]): Thumbnail id. published_time (Union[str, None]): Published time in format '%Y%m%dT%H%M%SZ'. + status (Union[str, None]): Status name. author (Union[str, None]): Author. frame_range (Union[str, None]): Frame range. duration (Union[int, None]): Duration. @@ -132,6 +133,7 @@ def __init__( thumbnail_id, published_time, author, + status, frame_range, duration, handles, @@ -146,6 +148,7 @@ def __init__( self.is_hero = is_hero self.published_time = published_time self.author = author + self.status = status self.frame_range = frame_range self.duration = duration self.handles = handles @@ -185,6 +188,7 @@ def to_data(self): "is_hero": self.is_hero, "published_time": self.published_time, "author": self.author, + "status": self.status, "frame_range": self.frame_range, "duration": self.duration, "handles": self.handles, @@ -488,6 +492,27 @@ def get_project_items(self, sender=None): pass + @abstractmethod + def get_project_status_items(self, project_name, sender=None): + """Items for all projects available on server. + + Triggers event topics "projects.statuses.refresh.started" and + "projects.statuses.refresh.finished" with data: + { + "sender": sender, + "project_name": project_name + } + + Args: + project_name (Union[str, None]): Project name. + sender (Optional[str]): Sender who requested the items. + + Returns: + list[StatusItem]: List of status items. + """ + + pass + @abstractmethod def get_product_items(self, project_name, folder_ids, sender=None): """Product items for folder ids. diff --git a/client/ayon_core/tools/loader/control.py b/client/ayon_core/tools/loader/control.py index 0c9bb369c7..35188369c2 100644 --- a/client/ayon_core/tools/loader/control.py +++ b/client/ayon_core/tools/loader/control.py @@ -180,6 +180,11 @@ def expected_folder_selected(self, folder_id): def get_project_items(self, sender=None): return self._projects_model.get_project_items(sender) + def get_project_status_items(self, project_name, sender=None): + return self._projects_model.get_project_status_items( + project_name, sender + ) + def get_folder_items(self, project_name, sender=None): return self._hierarchy_model.get_folder_items(project_name, sender) diff --git a/client/ayon_core/tools/loader/models/products.py b/client/ayon_core/tools/loader/models/products.py index a3bbc30a09..c9325c4480 100644 --- a/client/ayon_core/tools/loader/models/products.py +++ b/client/ayon_core/tools/loader/models/products.py @@ -58,6 +58,7 @@ def version_item_from_entity(version): thumbnail_id=version["thumbnailId"], published_time=published_time, author=author, + status=version["status"], frame_range=frame_range, duration=duration, handles=handles, @@ -526,8 +527,11 @@ def _query_product_items_by_ids( products = list(ayon_api.get_products(project_name, **kwargs)) product_ids = {product["id"] for product in products} + # Add 'status' to fields -> fixed in ayon-python-api 1.0.4 + fields = ayon_api.get_default_fields_for_type("version") + fields.add("status") versions = ayon_api.get_versions( - project_name, product_ids=product_ids + project_name, product_ids=product_ids, fields=fields ) return self._create_product_items( From f9efd8f05d5adb726d2d9f3c7dab15de3d18a70c Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 May 2024 18:56:27 +0200 Subject: [PATCH 07/11] added status column in UI --- .../tools/loader/ui/products_model.py | 96 ++++++++++++------- 1 file changed, 60 insertions(+), 36 deletions(-) diff --git a/client/ayon_core/tools/loader/ui/products_model.py b/client/ayon_core/tools/loader/ui/products_model.py index b465679c3b..76da76dbfb 100644 --- a/client/ayon_core/tools/loader/ui/products_model.py +++ b/client/ayon_core/tools/loader/ui/products_model.py @@ -22,18 +22,22 @@ VERSION_NAME_ROLE = QtCore.Qt.UserRole + 12 VERSION_NAME_EDIT_ROLE = QtCore.Qt.UserRole + 13 VERSION_PUBLISH_TIME_ROLE = QtCore.Qt.UserRole + 14 -VERSION_AUTHOR_ROLE = QtCore.Qt.UserRole + 15 -VERSION_FRAME_RANGE_ROLE = QtCore.Qt.UserRole + 16 -VERSION_DURATION_ROLE = QtCore.Qt.UserRole + 17 -VERSION_HANDLES_ROLE = QtCore.Qt.UserRole + 18 -VERSION_STEP_ROLE = QtCore.Qt.UserRole + 19 -VERSION_AVAILABLE_ROLE = QtCore.Qt.UserRole + 20 -VERSION_THUMBNAIL_ID_ROLE = QtCore.Qt.UserRole + 21 -ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 22 -REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 23 -REPRESENTATIONS_COUNT_ROLE = QtCore.Qt.UserRole + 24 -SYNC_ACTIVE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 25 -SYNC_REMOTE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 26 +VERSION_STATUS_NAME_ROLE = QtCore.Qt.UserRole + 15 +VERSION_STATUS_SHORT_ROLE = QtCore.Qt.UserRole + 16 +VERSION_STATUS_COLOR_ROLE = QtCore.Qt.UserRole + 17 +VERSION_STATUS_ROLE = QtCore.Qt.UserRole + 18 +VERSION_AUTHOR_ROLE = QtCore.Qt.UserRole + 19 +VERSION_FRAME_RANGE_ROLE = QtCore.Qt.UserRole + 20 +VERSION_DURATION_ROLE = QtCore.Qt.UserRole + 21 +VERSION_HANDLES_ROLE = QtCore.Qt.UserRole + 22 +VERSION_STEP_ROLE = QtCore.Qt.UserRole + 23 +VERSION_AVAILABLE_ROLE = QtCore.Qt.UserRole + 24 +VERSION_THUMBNAIL_ID_ROLE = QtCore.Qt.UserRole + 25 +ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 26 +REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 27 +REPRESENTATIONS_COUNT_ROLE = QtCore.Qt.UserRole + 28 +SYNC_ACTIVE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 29 +SYNC_REMOTE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 30 class ProductsModel(QtGui.QStandardItemModel): @@ -46,6 +50,7 @@ class ProductsModel(QtGui.QStandardItemModel): "Version", "Time", "Author", + "Status", "Frames", "Duration", "Handles", @@ -69,11 +74,35 @@ class ProductsModel(QtGui.QStandardItemModel): ] ] + product_name_col = column_labels.index("Product name") + product_type_col = column_labels.index("Product type") + folders_label_col = column_labels.index("Folder") version_col = column_labels.index("Version") published_time_col = column_labels.index("Time") - folders_label_col = column_labels.index("Folder") + author_col = column_labels.index("Author") + status_col = column_labels.index("Status") + frame_range_col = column_labels.index("Frames") + duration_col = column_labels.index("Duration") + handles_col = column_labels.index("Handles") + step_col = column_labels.index("Step") in_scene_col = column_labels.index("In scene") sitesync_avail_col = column_labels.index("Availability") + _display_role_mapping = { + product_name_col: QtCore.Qt.DisplayRole, + product_type_col: PRODUCT_TYPE_ROLE, + folders_label_col: FOLDER_LABEL_ROLE, + version_col: VERSION_NAME_ROLE, + published_time_col: VERSION_PUBLISH_TIME_ROLE, + author_col: VERSION_AUTHOR_ROLE, + status_col: VERSION_STATUS_NAME_ROLE, + frame_range_col: VERSION_FRAME_RANGE_ROLE, + duration_col: VERSION_DURATION_ROLE, + handles_col: VERSION_HANDLES_ROLE, + step_col: VERSION_STEP_ROLE, + in_scene_col: PRODUCT_IN_SCENE_ROLE, + sitesync_avail_col: VERSION_AVAILABLE_ROLE, + + } def __init__(self, controller): super(ProductsModel, self).__init__() @@ -96,6 +125,7 @@ def __init__(self, controller): self._last_project_name = None self._last_folder_ids = [] + self._last_project_statuses = {} def get_product_item_indexes(self): return [ @@ -141,6 +171,15 @@ def data(self, index, role=None): if not index.isValid(): return None + if role in (VERSION_STATUS_SHORT_ROLE, VERSION_STATUS_COLOR_ROLE): + status_name = self.data(index, VERSION_STATUS_NAME_ROLE) + status_item = self._last_project_statuses.get(status_name) + if status_item is None: + return "" + if role == VERSION_STATUS_SHORT_ROLE: + return status_item.short + return status_item.color + col = index.column() if col == 0: return super(ProductsModel, self).data(index, role) @@ -168,29 +207,8 @@ def data(self, index, role=None): if role == QtCore.Qt.DisplayRole: if not index.data(PRODUCT_ID_ROLE): return None - if col == self.version_col: - role = VERSION_NAME_ROLE - elif col == 1: - role = PRODUCT_TYPE_ROLE - elif col == 2: - role = FOLDER_LABEL_ROLE - elif col == 4: - role = VERSION_PUBLISH_TIME_ROLE - elif col == 5: - role = VERSION_AUTHOR_ROLE - elif col == 6: - role = VERSION_FRAME_RANGE_ROLE - elif col == 7: - role = VERSION_DURATION_ROLE - elif col == 8: - role = VERSION_HANDLES_ROLE - elif col == 9: - role = VERSION_STEP_ROLE - elif col == 10: - role = PRODUCT_IN_SCENE_ROLE - elif col == 11: - role = VERSION_AVAILABLE_ROLE - else: + role = self._display_role_mapping.get(col) + if role is None: return None index = self.index(index.row(), 0, index.parent()) @@ -312,6 +330,7 @@ def _set_version_data_to_product_item( version_item.published_time, VERSION_PUBLISH_TIME_ROLE ) model_item.setData(version_item.author, VERSION_AUTHOR_ROLE) + model_item.setData(version_item.status, VERSION_STATUS_NAME_ROLE) model_item.setData(version_item.frame_range, VERSION_FRAME_RANGE_ROLE) model_item.setData(version_item.duration, VERSION_DURATION_ROLE) model_item.setData(version_item.handles, VERSION_HANDLES_ROLE) @@ -393,6 +412,11 @@ def refresh(self, project_name, folder_ids): self._last_project_name = project_name self._last_folder_ids = folder_ids + status_items = self._controller.get_project_status_items(project_name) + self._last_project_statuses = { + status_item.name: status_item + for status_item in status_items + } active_site_icon_def = self._controller.get_active_site_icon_def( project_name From cc5e18149788538c4db76f09aa0fe64dfdf2efa2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 24 May 2024 10:12:36 +0200 Subject: [PATCH 08/11] remove redundand roles --- .../tools/loader/ui/products_model.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/client/ayon_core/tools/loader/ui/products_model.py b/client/ayon_core/tools/loader/ui/products_model.py index 76da76dbfb..dedd68abfe 100644 --- a/client/ayon_core/tools/loader/ui/products_model.py +++ b/client/ayon_core/tools/loader/ui/products_model.py @@ -25,19 +25,18 @@ VERSION_STATUS_NAME_ROLE = QtCore.Qt.UserRole + 15 VERSION_STATUS_SHORT_ROLE = QtCore.Qt.UserRole + 16 VERSION_STATUS_COLOR_ROLE = QtCore.Qt.UserRole + 17 -VERSION_STATUS_ROLE = QtCore.Qt.UserRole + 18 -VERSION_AUTHOR_ROLE = QtCore.Qt.UserRole + 19 -VERSION_FRAME_RANGE_ROLE = QtCore.Qt.UserRole + 20 -VERSION_DURATION_ROLE = QtCore.Qt.UserRole + 21 -VERSION_HANDLES_ROLE = QtCore.Qt.UserRole + 22 -VERSION_STEP_ROLE = QtCore.Qt.UserRole + 23 -VERSION_AVAILABLE_ROLE = QtCore.Qt.UserRole + 24 -VERSION_THUMBNAIL_ID_ROLE = QtCore.Qt.UserRole + 25 -ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 26 -REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 27 -REPRESENTATIONS_COUNT_ROLE = QtCore.Qt.UserRole + 28 -SYNC_ACTIVE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 29 -SYNC_REMOTE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 30 +VERSION_AUTHOR_ROLE = QtCore.Qt.UserRole + 18 +VERSION_FRAME_RANGE_ROLE = QtCore.Qt.UserRole + 19 +VERSION_DURATION_ROLE = QtCore.Qt.UserRole + 20 +VERSION_HANDLES_ROLE = QtCore.Qt.UserRole + 21 +VERSION_STEP_ROLE = QtCore.Qt.UserRole + 22 +VERSION_AVAILABLE_ROLE = QtCore.Qt.UserRole + 23 +VERSION_THUMBNAIL_ID_ROLE = QtCore.Qt.UserRole + 24 +ACTIVE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 25 +REMOTE_SITE_ICON_ROLE = QtCore.Qt.UserRole + 26 +REPRESENTATIONS_COUNT_ROLE = QtCore.Qt.UserRole + 27 +SYNC_ACTIVE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 28 +SYNC_REMOTE_SITE_AVAILABILITY = QtCore.Qt.UserRole + 29 class ProductsModel(QtGui.QStandardItemModel): From 4a70b7d26eb551b5a08f5e4c577bf5f783571e9f Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 24 May 2024 10:13:23 +0200 Subject: [PATCH 09/11] better way how to set delegates --- .../tools/loader/ui/products_widget.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/client/ayon_core/tools/loader/ui/products_widget.py b/client/ayon_core/tools/loader/ui/products_widget.py index d9f027153e..9c6a1dbb85 100644 --- a/client/ayon_core/tools/loader/ui/products_widget.py +++ b/client/ayon_core/tools/loader/ui/products_widget.py @@ -128,20 +128,17 @@ def __init__(self, controller, parent): products_view.setColumnWidth(idx, width) version_delegate = VersionDelegate() - products_view.setItemDelegateForColumn( - products_model.version_col, version_delegate) - time_delegate = PrettyTimeDelegate() - products_view.setItemDelegateForColumn( - products_model.published_time_col, time_delegate) - in_scene_delegate = LoadedInSceneDelegate() - products_view.setItemDelegateForColumn( - products_model.in_scene_col, in_scene_delegate) - sitesync_delegate = SiteSyncDelegate() - products_view.setItemDelegateForColumn( - products_model.sitesync_avail_col, sitesync_delegate) + + for col, delegate in ( + (products_model.version_col, version_delegate), + (products_model.published_time_col, time_delegate), + (products_model.in_scene_col, in_scene_delegate), + (products_model.sitesync_avail_col, sitesync_delegate), + ): + products_view.setItemDelegateForColumn(col, delegate) main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) From 50c26e3b71068be6695c6eb472ef3a5cbee26031 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 24 May 2024 10:13:43 +0200 Subject: [PATCH 10/11] added delegate for status --- .../tools/loader/ui/products_delegates.py | 46 +++++++++++++++++++ .../tools/loader/ui/products_widget.py | 7 ++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/tools/loader/ui/products_delegates.py b/client/ayon_core/tools/loader/ui/products_delegates.py index 12ed1165ae..6bcb78ec66 100644 --- a/client/ayon_core/tools/loader/ui/products_delegates.py +++ b/client/ayon_core/tools/loader/ui/products_delegates.py @@ -6,6 +6,9 @@ from .products_model import ( PRODUCT_ID_ROLE, VERSION_NAME_EDIT_ROLE, + VERSION_STATUS_NAME_ROLE, + VERSION_STATUS_SHORT_ROLE, + VERSION_STATUS_COLOR_ROLE, VERSION_ID_ROLE, PRODUCT_IN_SCENE_ROLE, ACTIVE_SITE_ICON_ROLE, @@ -194,6 +197,49 @@ def initStyleOption(self, option, index): option.palette.setBrush(QtGui.QPalette.Text, color) +class StatusDelegate(QtWidgets.QStyledItemDelegate): + """Delegate showing status name and short name.""" + + def paint(self, painter, option, index): + if option.widget: + style = option.widget.style() + else: + style = QtWidgets.QApplication.style() + + style.drawControl( + style.CE_ItemViewItem, option, painter, option.widget + ) + + painter.save() + + text_rect = style.subElementRect(style.SE_ItemViewItemText, option) + text_margin = style.proxy().pixelMetric( + style.PM_FocusFrameHMargin, option, option.widget + ) + 1 + padded_text_rect = text_rect.adjusted( + text_margin, 0, - text_margin, 0 + ) + + fm = QtGui.QFontMetrics(option.font) + text = index.data(VERSION_STATUS_NAME_ROLE) + if padded_text_rect.width() < fm.width(text): + text = index.data(VERSION_STATUS_SHORT_ROLE) + + status_color = index.data(VERSION_STATUS_COLOR_ROLE) + fg_color = QtGui.QColor(status_color) + pen = painter.pen() + pen.setColor(fg_color) + painter.setPen(pen) + + painter.drawText( + padded_text_rect, + option.displayAlignment, + text + ) + + painter.restore() + + class SiteSyncDelegate(QtWidgets.QStyledItemDelegate): """Paints icons and downloaded representation ration for both sites.""" diff --git a/client/ayon_core/tools/loader/ui/products_widget.py b/client/ayon_core/tools/loader/ui/products_widget.py index 9c6a1dbb85..3a30d83d52 100644 --- a/client/ayon_core/tools/loader/ui/products_widget.py +++ b/client/ayon_core/tools/loader/ui/products_widget.py @@ -22,7 +22,8 @@ from .products_delegates import ( VersionDelegate, LoadedInSceneDelegate, - SiteSyncDelegate + StatusDelegate, + SiteSyncDelegate, ) from .actions_utils import show_actions_menu @@ -89,6 +90,7 @@ class ProductsWidget(QtWidgets.QWidget): 90, # Product type 130, # Folder label 60, # Version + 100, # Status 125, # Time 75, # Author 75, # Frames @@ -129,12 +131,14 @@ def __init__(self, controller, parent): version_delegate = VersionDelegate() time_delegate = PrettyTimeDelegate() + status_delegate = StatusDelegate() in_scene_delegate = LoadedInSceneDelegate() sitesync_delegate = SiteSyncDelegate() for col, delegate in ( (products_model.version_col, version_delegate), (products_model.published_time_col, time_delegate), + (products_model.status_col, status_delegate), (products_model.in_scene_col, in_scene_delegate), (products_model.sitesync_avail_col, sitesync_delegate), ): @@ -172,6 +176,7 @@ def __init__(self, controller, parent): self._version_delegate = version_delegate self._time_delegate = time_delegate + self._status_delegate = status_delegate self._in_scene_delegate = in_scene_delegate self._sitesync_delegate = sitesync_delegate From 3c032fc764fe5a20cec2f18e4e2ad18c4dcb1542 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Fri, 24 May 2024 10:13:54 +0200 Subject: [PATCH 11/11] move status column after version --- client/ayon_core/tools/loader/ui/products_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/tools/loader/ui/products_model.py b/client/ayon_core/tools/loader/ui/products_model.py index dedd68abfe..f309473d10 100644 --- a/client/ayon_core/tools/loader/ui/products_model.py +++ b/client/ayon_core/tools/loader/ui/products_model.py @@ -47,9 +47,9 @@ class ProductsModel(QtGui.QStandardItemModel): "Product type", "Folder", "Version", + "Status", "Time", "Author", - "Status", "Frames", "Duration", "Handles", @@ -77,9 +77,9 @@ class ProductsModel(QtGui.QStandardItemModel): product_type_col = column_labels.index("Product type") folders_label_col = column_labels.index("Folder") version_col = column_labels.index("Version") + status_col = column_labels.index("Status") published_time_col = column_labels.index("Time") author_col = column_labels.index("Author") - status_col = column_labels.index("Status") frame_range_col = column_labels.index("Frames") duration_col = column_labels.index("Duration") handles_col = column_labels.index("Handles") @@ -91,9 +91,9 @@ class ProductsModel(QtGui.QStandardItemModel): product_type_col: PRODUCT_TYPE_ROLE, folders_label_col: FOLDER_LABEL_ROLE, version_col: VERSION_NAME_ROLE, + status_col: VERSION_STATUS_NAME_ROLE, published_time_col: VERSION_PUBLISH_TIME_ROLE, author_col: VERSION_AUTHOR_ROLE, - status_col: VERSION_STATUS_NAME_ROLE, frame_range_col: VERSION_FRAME_RANGE_ROLE, duration_col: VERSION_DURATION_ROLE, handles_col: VERSION_HANDLES_ROLE,