Source code for radioviz.models.app_state

#  Copyright 2025–2026 European Union
#  Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
#  SPDX-License-Identifier: EUPL-1.2
"""
Application state management module.

This module provides the :class:`AppState` class which manages the global application state,
including tracking whether images are available and managing the currently active window.
The state changes are propagated through Qt signals to notify interested components.
"""

from typing import TYPE_CHECKING, Any, Optional, Union

from PySide6.QtCore import QObject, Signal

if TYPE_CHECKING:
    from radioviz.controllers.sub_window_controller import SubWindowController


[docs] class AppState(QObject): """ Application state manager. This class maintains the global application state including image availability and the currently active window. It emits signals when the state changes, allowing other parts of the application to react to these changes. The state includes: - Whether images are available in the application - Which window is currently active """ changed = Signal() """Signal emitted when the application state changes.""" def __init__(self) -> None: """ Initialize the application state. Creates a new instance with default values where no images are available and no window is active. """ super().__init__() self._has_images = False self._active_window: Optional['SubWindowController[Any]'] = None @property def has_images(self) -> bool: """ Check if images are available in the application. :return: True if images are available, False otherwise :rtype: bool """ return self._has_images @has_images.setter def has_images(self, value: bool) -> None: """ Set the image availability status. Emits the :attr:`changed` signal if the value actually changes. :param value: The new image availability status :type value: bool """ if self._has_images != value: self._has_images = value self.changed.emit()
[docs] def _get_active_window(self) -> 'SubWindowController[Any] | None': """ Get the currently active window controller. :return: The active window controller or None if no window is active :rtype: Union['SubWindowController', None] """ return self._active_window
[docs] def on_window_change(self, window_controller: Union['SubWindowController[Any]', None]) -> None: """ Handle window change events. Updates the active window and image availability status based on the provided window controller. Emits the :attr:`changed` signal when state changes. :param window_controller: The new active window controller or None :type window_controller: Union['SubWindowController', None] """ self.active_window = window_controller
[docs] def _set_active_window(self, value: 'SubWindowController[Any] | None') -> None: """ Set the active window controller. Manages the transition between window states and updates image availability accordingly. Emits the :attr:`changed` signal when state changes. :param value: The new active window controller or None :type value: Union['SubWindowController', None] """ if value is None: # the active is None, so there are now windows # was it None before as well? if self._active_window is None: # then do nothing pass else: # it means that we closed the last window self._active_window = value self._has_images = False # propagate the state change self.changed.emit() else: # is the new active different from the previous if self._active_window != value: self._active_window = value self._has_images = True # propagate the state change self.changed.emit() if self._active_window != value: self._active_window = value if not self._has_images: self._has_images = True self.changed.emit()
active_window = property(_get_active_window, _set_active_window)