diff --git a/client/ayon_core/tools/publisher/control.py b/client/ayon_core/tools/publisher/control.py index 3d11131dc3..ca781c38d2 100644 --- a/client/ayon_core/tools/publisher/control.py +++ b/client/ayon_core/tools/publisher/control.py @@ -543,6 +543,10 @@ class PublisherController( """ self._create_model.remove_instances(instance_ids) + def select_instances_in_host(self, instance_ids): + """Ask host/creators to select and focus selected instances.""" + return self._create_model.select_instances_in_host(list(instance_ids)) + def publish_has_started(self): return self._publish_model.has_started() diff --git a/client/ayon_core/tools/publisher/models/create.py b/client/ayon_core/tools/publisher/models/create.py index b8518a7de6..f1271281e0 100644 --- a/client/ayon_core/tools/publisher/models/create.py +++ b/client/ayon_core/tools/publisher/models/create.py @@ -787,6 +787,36 @@ class CreateModel: # is not required. self._remove_instances_from_context(instance_ids) + def select_instances_in_host(self, instance_ids: List[str]): + """Ask host/creator to select and focus instances in DCC. + + Calls creator-specific hook 'select_in_host' when available. + + Args: + instance_ids (List[str]): Instance identifiers to select. + """ + if not instance_ids: + return + for instance_id in instance_ids: + instance = self._get_instance_by_id(instance_id) + if instance is None: + continue + try: + creator_identifier = instance.creator_identifier + creator = self._creators.get(creator_identifier) + if creator is None: + continue + # Call optional hook if present on the creator + select_hook = getattr(creator, "select_in_host", None) + if callable(select_hook): + select_hook(instance) + except Exception as e: + # Never raise from a UX helper + self.log.debug( + "Selection hook failed for instance %s", instance_id, exc_info=True + ) + self.log.error(f"Selection hook failed for instance {instance_id}: {e}") + def set_instances_create_attr_values(self, instance_ids, key, value): self._set_instances_create_attr_values(instance_ids, key, value) diff --git a/client/ayon_core/tools/publisher/widgets/overview_widget.py b/client/ayon_core/tools/publisher/widgets/overview_widget.py index 01799ac908..bd66a51d89 100644 --- a/client/ayon_core/tools/publisher/widgets/overview_widget.py +++ b/client/ayon_core/tools/publisher/widgets/overview_widget.py @@ -127,19 +127,19 @@ class OverviewWidget(QtWidgets.QFrame): self._on_product_change ) product_list_view.double_clicked.connect( - self.publish_tab_requested + self._on_instances_double_clicked ) product_list_view_grouped.selection_changed.connect( self._on_product_change ) product_list_view_grouped.double_clicked.connect( - self.publish_tab_requested + self._on_instances_double_clicked ) product_view_cards.selection_changed.connect( self._on_product_change ) product_view_cards.double_clicked.connect( - self.publish_tab_requested + self._on_instances_double_clicked ) # Instance context has changed product_attributes_widget.convert_requested.connect( @@ -544,3 +544,16 @@ class OverviewWidget(QtWidgets.QFrame): def _on_instances_removed(self): self._refresh_instances() + + def _on_instances_double_clicked(self): + # On double-click, select and focus corresponding nodes in host + instance_ids, _, _ = self.get_selected_items() + if not instance_ids: + return + try: + self._controller.select_instances_in_host(instance_ids) + except Exception: + # Keep UI responsive even if host-side selection fails + pass + # Keep existing behavior: navigate to publish tab + self.publish_tab_requested.emit()