Source code for pyqt_reactive.widgets.shared.dirty_window_presenter

"""Dirty-state presentation for ObjectState-backed form windows."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Callable

from PyQt6.QtWidgets import QDialog, QLabel, QPushButton

if TYPE_CHECKING:
    from objectstate import ObjectState


[docs] @dataclass(frozen=True, slots=True) class DirtyWindowPresentation: """Presentation state for a form window's dirty/signature-diff markers.""" window_title: str header_text: str save_label: str is_dirty: bool has_signature_diff: bool mark_save_label_dirty: bool = True
[docs] @dataclass(slots=True) class DirtyWindowStateTracker: """Track ObjectState dirty status for managed form windows.""" state_provider: Callable[[], "ObjectState | None"] change_emitter: Callable[[bool], None] has_changes: bool = False @property def is_dirty(self) -> bool: state = self.state_provider() if state is None: return False return bool(state.is_raw_dirty) @property def has_signature_diff(self) -> bool: state = self.state_provider() if state is None: return False return bool(state.signature_diff_fields)
[docs] def detect_changes(self) -> bool: has_changes = self.is_dirty if has_changes != self.has_changes: self.has_changes = has_changes self.change_emitter(has_changes) return has_changes
[docs] class DirtyWindowPresenter: """Apply dirty/signature-diff state to common form-window affordances."""
[docs] def apply( self, *, window: QDialog, header_label: QLabel, save_button: QPushButton, presentation: DirtyWindowPresentation, ) -> None: dirty_prefix = "" if presentation.is_dirty: dirty_prefix = "* " window.setWindowTitle(f"{dirty_prefix}{presentation.window_title}") header_label.setText(f"{dirty_prefix}{presentation.header_text}") font = header_label.font() font.setUnderline(presentation.has_signature_diff) header_label.setFont(font) save_button.setEnabled(presentation.is_dirty) save_prefix = "" if presentation.mark_save_label_dirty and presentation.is_dirty: save_prefix = dirty_prefix save_button.setText(f"{save_prefix}{presentation.save_label}")