AbstractManagerWidget Architecture
===================================

The Problem: Duplicated Manager Widget Code
-------------------------------------------

Many manager-style widgets implement nearly identical CRUD operations (add,
delete, edit, list items) with only domain-specific differences. This
duplication creates maintenance burden: fixes must be applied repeatedly and
feature additions require parallel edits. Implicit duck-typed hooks also make
required subclass contracts unclear.

The Solution: Template Method Pattern with Declarative Configuration
---------------------------------------------------------------------

AbstractManagerWidget uses the template method pattern to define the CRUD
workflow once, with declarative configuration via class attributes. Subclasses
specify domain behavior (button configs, item hooks, preview fields) as class
attributes rather than ad-hoc methods. This eliminates duplication, makes
contracts explicit (ABCs), and enables extension without copy/paste.

Overview
--------

The ``AbstractManagerWidget`` is a PyQt6 ABC that eliminates duck-typing and
code duplication across manager widgets through declarative configuration and
the template method pattern.

Architecture Pattern
--------------------

The ABC uses the **template method pattern** with declarative configuration:

.. code-block:: python

    from pyqt_reactive.widgets.shared.abstract_manager_widget import AbstractManagerWidget

    class MyManagerWidget(AbstractManagerWidget):
        # Declarative configuration via class attributes
        TITLE = "Pipeline Editor"
        
        BUTTON_CONFIGS = [
            ButtonConfig(text="Add Step", action="add", icon="plus"),
            ButtonConfig(text="Delete Step", action="delete", icon="trash"),
            ButtonConfig(text="Edit Step", action="edit", icon="edit"),
        ]
        
        ITEM_HOOKS = ItemHooks(
            get_items=lambda self: self.pipeline_steps,
            set_items=lambda self, items: setattr(self, 'pipeline_steps', items),
            get_selected_index=lambda self: self.step_list.currentRow(),
        )
        
        PREVIEW_FIELD_CONFIGS = [
            ('napari_streaming_config.enabled', lambda v: 'NAP' if v else None, 'step'),
            ('fiji_streaming_config.enabled', lambda v: 'FIJI' if v else None, 'step'),
        ]
        
        # Implement abstract hooks for domain-specific behavior
        def _perform_delete(self, index: int) -> None:
            """Delete step at index."""
            del self.pipeline_steps[index]
        
        def _show_item_editor(self, item: Any, index: int) -> None:
            """Show step editor dialog."""
            dialog = StepEditorDialog(item, parent=self)
            dialog.exec()
        
        def _format_list_item(self, item: Any, index: int) -> str:
            """Format step for display in list."""
            return f"{index + 1}. {item.name}"

Declarative Configuration
--------------------------

**Class Attributes**:

- ``TITLE``: Widget title (str)
- ``BUTTON_CONFIGS``: List of ``ButtonConfig`` objects defining toolbar buttons
- ``ITEM_HOOKS``: ``ItemHooks`` dataclass with lambdas for item access
- ``PREVIEW_FIELD_CONFIGS``: List of tuples ``(field_path, formatter, scope_root)`` for cross-window previews
- ``CODE_EDITOR_CONFIG``: Optional ``CodeEditorConfig`` for code editing support

**ButtonConfig**:

.. code-block:: python

    @dataclass
    class ButtonConfig:
        text: str
        action: str  # Maps to action_{action} method
        icon: Optional[str] = None
        tooltip: Optional[str] = None

**ItemHooks**:

.. code-block:: python

    @dataclass
    class ItemHooks:
        get_items: Callable[[Any], List[Any]]
        set_items: Callable[[Any, List[Any]], None]
        get_selected_index: Callable[[Any], int]
        get_item_at_index: Optional[Callable[[Any, int], Any]] = None

Template Methods
-----------------

The ABC provides template methods that orchestrate the workflow:

**CRUD Operations**:

- ``action_add()``: Add new item (calls ``_create_new_item()`` hook)
- ``action_delete()``: Delete selected item (calls ``_perform_delete()`` hook)
- ``action_edit()``: Edit selected item (calls ``_show_item_editor()`` hook)
- ``update_item_list()``: Refresh list widget (calls ``_format_list_item()`` hook)

**Code Editing**:

- ``action_view_code()``: Show code editor dialog
- ``_handle_edited_code(code)``: Execute edited code and apply to widget state

**Cross-Window Previews**:

- ``_init_cross_window_preview_mixin()``: Initialize preview system
- ``_process_pending_preview_updates()``: Apply incremental preview updates

Abstract Hooks
--------------

Subclasses must implement these abstract methods:

.. code-block:: python

    @abstractmethod
    def _perform_delete(self, index: int) -> None:
        """Delete item at index."""
        ...

    @abstractmethod
    def _show_item_editor(self, item: Any, index: int) -> None:
        """Show editor dialog for item."""
        ...

    @abstractmethod
    def _format_list_item(self, item: Any, index: int) -> str:
        """Format item for display in list widget."""
        ...

    @abstractmethod
    def _get_context_stack_for_resolution(self) -> List[Any]:
        """Get context stack for lazy config resolution."""
        ...

Optional hooks with default implementations:

- ``_create_new_item() -> Any``: Create new item (default: None)
- ``_get_code_editor_title() -> str``: Code editor title (default: "Code Editor")
- ``_apply_extracted_variables(vars: Dict[str, Any])``: Apply code execution results

Flash Callback Integration
~~~~~~~~~~~~~~~~~~~~~~~~~~

AbstractManagerWidget subscribes to ObjectState change notifications to trigger flash
animations when parameters change:

.. code-block:: python

    # In _subscribe_flash_for_item()
    state = ObjectStateRegistry.get_by_scope(scope_id)

    def on_change(changed_paths: Set[str]):
        self.queue_flash(scope_id)  # Trigger flash in all windows
        self.queue_visual_update()   # Refresh list item text

    state.on_resolved_changed(on_change)

See :doc:`flash_callback_system` for details on how the flash callback mechanism works.

See Also
--------

- :doc:`flash_callback_system` - How ObjectState triggers flash callbacks
- :doc:`flash_animation_system` - Flash animation rendering
- :doc:`widget_protocol_system` - ABC contracts for widget operations
- :doc:`ui_services_architecture` - Service layer for ParameterFormManager
- :doc:`gui_performance_patterns` - Cross-window preview system
- :doc:`zmq_server_browser_widget` - Generic browser ABC and kill/scan flow
- :doc:`tree_state_sync_system` - Stable tree keying and state-preserving rebuild
- :doc:`parametric_widget_creation` - Widget creation configuration
