Merge branch 'develop' into enhancement/make)_sure_confirm_message_on_top_after_creating_hero_version

This commit is contained in:
Kayla Man 2025-11-10 20:59:35 +08:00 committed by GitHub
commit d5df6a99c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 79 additions and 10 deletions

View file

@ -15,6 +15,36 @@ from ayon_core.tools.utils.lib import checkstate_int_to_enum
from .workfiles_page import WorkfilesPage from .workfiles_page import WorkfilesPage
class LauncherFoldersWidget(FoldersWidget):
focused_in = QtCore.Signal()
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._folders_view.installEventFilter(self)
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.FocusIn:
self.focused_in.emit()
return False
class LauncherTasksWidget(TasksWidget):
focused_in = QtCore.Signal()
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._tasks_view.installEventFilter(self)
def deselect(self):
sel_model = self._tasks_view.selectionModel()
sel_model.clearSelection()
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.FocusIn:
self.focused_in.emit()
return False
class HierarchyPage(QtWidgets.QWidget): class HierarchyPage(QtWidgets.QWidget):
def __init__(self, controller, parent): def __init__(self, controller, parent):
super().__init__(parent) super().__init__(parent)
@ -68,12 +98,12 @@ class HierarchyPage(QtWidgets.QWidget):
filters_layout.addWidget(my_tasks_checkbox, 0) filters_layout.addWidget(my_tasks_checkbox, 0)
# - Folders widget # - Folders widget
folders_widget = FoldersWidget(controller, content_body) folders_widget = LauncherFoldersWidget(controller, content_body)
folders_widget.set_header_visible(True) folders_widget.set_header_visible(True)
folders_widget.set_deselectable(True) folders_widget.set_deselectable(True)
# - Tasks widget # - Tasks widget
tasks_widget = TasksWidget(controller, content_body) tasks_widget = LauncherTasksWidget(controller, content_body)
# - Third page - Workfiles # - Third page - Workfiles
workfiles_page = WorkfilesPage(controller, content_body) workfiles_page = WorkfilesPage(controller, content_body)
@ -97,6 +127,8 @@ class HierarchyPage(QtWidgets.QWidget):
my_tasks_checkbox.stateChanged.connect( my_tasks_checkbox.stateChanged.connect(
self._on_my_tasks_checkbox_state_changed self._on_my_tasks_checkbox_state_changed
) )
folders_widget.focused_in.connect(self._on_folders_focus)
tasks_widget.focused_in.connect(self._on_tasks_focus)
self._is_visible = False self._is_visible = False
self._controller = controller self._controller = controller
@ -151,3 +183,9 @@ class HierarchyPage(QtWidgets.QWidget):
task_ids = entity_ids["task_ids"] task_ids = entity_ids["task_ids"]
self._folders_widget.set_folder_ids_filter(folder_ids) self._folders_widget.set_folder_ids_filter(folder_ids)
self._tasks_widget.set_task_ids_filter(task_ids) self._tasks_widget.set_task_ids_filter(task_ids)
def _on_folders_focus(self):
self._workfiles_page.deselect()
def _on_tasks_focus(self):
self._workfiles_page.deselect()

View file

@ -3,7 +3,7 @@ from typing import Optional
import ayon_api import ayon_api
from qtpy import QtCore, QtWidgets, QtGui from qtpy import QtCore, QtWidgets, QtGui
from ayon_core.tools.utils import get_qt_icon from ayon_core.tools.utils import get_qt_icon, DeselectableTreeView
from ayon_core.tools.launcher.abstract import AbstractLauncherFrontEnd from ayon_core.tools.launcher.abstract import AbstractLauncherFrontEnd
VERSION_ROLE = QtCore.Qt.UserRole + 1 VERSION_ROLE = QtCore.Qt.UserRole + 1
@ -127,7 +127,7 @@ class WorkfilesModel(QtGui.QStandardItemModel):
return icon return icon
class WorkfilesView(QtWidgets.QTreeView): class WorkfilesView(DeselectableTreeView):
def drawBranches(self, painter, rect, index): def drawBranches(self, painter, rect, index):
return return
@ -165,6 +165,10 @@ class WorkfilesPage(QtWidgets.QWidget):
def refresh(self) -> None: def refresh(self) -> None:
self._workfiles_model.refresh() self._workfiles_model.refresh()
def deselect(self):
sel_model = self._workfiles_view.selectionModel()
sel_model.clearSelection()
def _on_refresh(self) -> None: def _on_refresh(self) -> None:
self._workfiles_proxy.sort(0, QtCore.Qt.DescendingOrder) self._workfiles_proxy.sort(0, QtCore.Qt.DescendingOrder)

View file

@ -202,7 +202,7 @@ class ContextCardWidget(CardWidget):
Is not visually under group widget and is always at the top of card view. Is not visually under group widget and is always at the top of card view.
""" """
def __init__(self, parent): def __init__(self, parent: QtWidgets.QWidget):
super().__init__(parent) super().__init__(parent)
self._id = CONTEXT_ID self._id = CONTEXT_ID
@ -211,7 +211,7 @@ class ContextCardWidget(CardWidget):
icon_widget = PublishPixmapLabel(None, self) icon_widget = PublishPixmapLabel(None, self)
icon_widget.setObjectName("ProductTypeIconLabel") icon_widget.setObjectName("ProductTypeIconLabel")
label_widget = QtWidgets.QLabel(CONTEXT_LABEL, self) label_widget = QtWidgets.QLabel(f"<span>{CONTEXT_LABEL}</span>", self)
icon_layout = QtWidgets.QHBoxLayout() icon_layout = QtWidgets.QHBoxLayout()
icon_layout.setContentsMargins(5, 5, 5, 5) icon_layout.setContentsMargins(5, 5, 5, 5)
@ -288,6 +288,8 @@ class InstanceCardWidget(CardWidget):
self._last_product_name = None self._last_product_name = None
self._last_variant = None self._last_variant = None
self._last_label = None self._last_label = None
self._last_folder_path = None
self._last_task_name = None
icon_widget = IconValuePixmapLabel(group_icon, self) icon_widget = IconValuePixmapLabel(group_icon, self)
icon_widget.setObjectName("ProductTypeIconLabel") icon_widget.setObjectName("ProductTypeIconLabel")
@ -383,29 +385,54 @@ class InstanceCardWidget(CardWidget):
self._icon_widget.setVisible(valid) self._icon_widget.setVisible(valid)
self._context_warning.setVisible(not valid) self._context_warning.setVisible(not valid)
@staticmethod
def _get_card_widget_sub_label(
folder_path: Optional[str],
task_name: Optional[str],
) -> str:
sublabel = ""
if folder_path:
folder_name = folder_path.rsplit("/", 1)[-1]
sublabel = f"<b>{folder_name}</b>"
if task_name:
sublabel += f" - <i>{task_name}</i>"
return sublabel
def _update_product_name(self): def _update_product_name(self):
variant = self.instance.variant variant = self.instance.variant
product_name = self.instance.product_name product_name = self.instance.product_name
label = self.instance.label label = self.instance.label
folder_path = self.instance.folder_path
task_name = self.instance.task_name
if ( if (
variant == self._last_variant variant == self._last_variant
and product_name == self._last_product_name and product_name == self._last_product_name
and label == self._last_label and label == self._last_label
and folder_path == self._last_folder_path
and task_name == self._last_task_name
): ):
return return
self._last_variant = variant self._last_variant = variant
self._last_product_name = product_name self._last_product_name = product_name
self._last_label = label self._last_label = label
self._last_folder_path = folder_path
self._last_task_name = task_name
# Make `variant` bold # Make `variant` bold
label = html_escape(self.instance.label) label = html_escape(self.instance.label)
found_parts = set(re.findall(variant, label, re.IGNORECASE)) found_parts = set(re.findall(variant, label, re.IGNORECASE))
if found_parts: if found_parts:
for part in found_parts: for part in found_parts:
replacement = "<b>{}</b>".format(part) replacement = f"<b>{part}</b>"
label = label.replace(part, replacement) label = label.replace(part, replacement)
label = f"<span>{label}</span>"
sublabel = self._get_card_widget_sub_label(folder_path, task_name)
if sublabel:
label += f"<br/><span style=\"font-size: 8pt;\">{sublabel}</span>"
self._label_widget.setText(label) self._label_widget.setText(label)
# HTML text will cause that label start catch mouse clicks # HTML text will cause that label start catch mouse clicks
# - disabling with changing interaction flag # - disabling with changing interaction flag
@ -702,11 +729,9 @@ class InstanceCardView(AbstractInstanceView):
def refresh(self): def refresh(self):
"""Refresh instances in view based on CreatedContext.""" """Refresh instances in view based on CreatedContext."""
self._make_sure_context_widget_exists() self._make_sure_context_widget_exists()
self._update_convertors_group() self._update_convertors_group()
context_info_by_id = self._controller.get_instances_context_info() context_info_by_id = self._controller.get_instances_context_info()
# Prepare instances by group and identifiers by group # Prepare instances by group and identifiers by group
@ -814,6 +839,8 @@ class InstanceCardView(AbstractInstanceView):
widget.setVisible(False) widget.setVisible(False)
widget.deleteLater() widget.deleteLater()
sorted_group_names.insert(0, CONTEXT_GROUP)
self._parent_id_by_id = parent_id_by_id self._parent_id_by_id = parent_id_by_id
self._instance_ids_by_parent_id = instance_ids_by_parent_id self._instance_ids_by_parent_id = instance_ids_by_parent_id
self._group_name_by_instance_id = group_by_instance_id self._group_name_by_instance_id = group_by_instance_id
@ -881,7 +908,7 @@ class InstanceCardView(AbstractInstanceView):
context_info, context_info,
is_parent_active, is_parent_active,
group_icon, group_icon,
group_widget group_widget,
) )
widget.selected.connect(self._on_widget_selection) widget.selected.connect(self._on_widget_selection)
widget.active_changed.connect(self._on_active_changed) widget.active_changed.connect(self._on_active_changed)