SXXXXXXX_FlightMonitor/flightmonitor/controller/cleanup_manager.py
2025-06-04 13:25:59 +02:00

155 lines
7.3 KiB
Python

# FlightMonitor/controller/cleanup_manager.py
"""
Manages the orderly shutdown and cleanup of application resources,
including closing database connections, stopping background threads,
and destroying secondary GUI windows upon application exit or specific events.
"""
from typing import Any, Optional, TYPE_CHECKING
from ..utils.logger import get_logger
# Type checking imports to avoid circular dependencies at runtime
if TYPE_CHECKING:
from .app_controller import AppController
from ..data.storage import DataStorage
from ..data.aircraft_database_manager import AircraftDatabaseManager
from ..gui.main_window import MainWindow
from ..gui.dialogs.full_flight_details_window import FullFlightDetailsWindow
from ..map.map_canvas_manager import MapCanvasManager
module_logger = get_logger(__name__)
class CleanupManager:
"""
Handles all application shutdown and resource cleanup operations.
It orchestrates the closing of various modules and components.
"""
def __init__(self, app_controller: "AppController"):
"""
Initializes the CleanupManager.
Args:
app_controller: The main AppController instance, providing access
to all application components that need cleanup.
"""
self.app_controller = app_controller
module_logger.debug("CleanupManager initialized.")
def on_application_exit(self):
"""
Performs a coordinated shutdown of all application resources.
This method is called when the main application window is closing.
"""
module_logger.info("CleanupManager: Application exit requested. Cleaning up resources.")
# --- Close active Full Flight Details window (if any) ---
# Access active_detail_window_ref and active_detail_window_icao via app_controller
if (
self.app_controller.active_detail_window_ref
and self.app_controller.active_detail_window_ref.winfo_exists()
):
try:
module_logger.info(
f"CleanupManager: Closing active detail window for {self.app_controller.active_detail_window_icao} on app exit."
)
self.app_controller.active_detail_window_ref.destroy()
except Exception as e_close_detail:
module_logger.error(
f"CleanupManager: Error closing detail window on app exit: {e_close_detail}"
)
finally:
# Clear references in AppController directly or via a method
self.app_controller.active_detail_window_ref = None
self.app_controller.active_detail_window_icao = None
# --- Shutdown MapCanvasManager worker (if active) ---
# Access map_manager_instance via app_controller.main_window
main_window = self.app_controller.main_window
if (
main_window
and hasattr(main_window, "map_manager_instance")
and main_window.map_manager_instance is not None
):
map_manager: "MapCanvasManager" = main_window.map_manager_instance
if hasattr(map_manager, "shutdown_worker") and callable(map_manager.shutdown_worker):
try:
map_manager.shutdown_worker()
module_logger.info("CleanupManager: Main MapCanvasManager worker shutdown requested.")
except Exception as e_map_shutdown:
module_logger.error(
f"CleanupManager: Error during Main MapCanvasManager worker shutdown: {e_map_shutdown}",
exc_info=True,
)
# --- Stop live monitoring (adapter thread and data processor) ---
# Access live_adapter_thread, is_live_monitoring_active via app_controller
# Access stop_live_monitoring via app_controller
is_adapter_considered_running = (
self.app_controller.live_adapter_thread and self.app_controller.live_adapter_thread.is_alive()
) or self.app_controller.is_live_monitoring_active
if is_adapter_considered_running:
module_logger.info("CleanupManager: Live monitoring is active, requesting AppController to stop it.")
self.app_controller.stop_live_monitoring(from_error=False)
# --- Close DataStorage connection ---
# Access data_storage via app_controller
if self.app_controller.data_storage:
try:
self.app_controller.data_storage.close_connection()
module_logger.info("CleanupManager: DataStorage connection closed.")
except Exception as e_db_close:
module_logger.error(
f"CleanupManager: Error closing DataStorage: {e_db_close}", exc_info=True
)
finally:
self.app_controller.data_storage = None # Clear reference in AppController
# --- Close AircraftDatabaseManager connection ---
# Access aircraft_db_manager via app_controller
if self.app_controller.aircraft_db_manager:
try:
self.app_controller.aircraft_db_manager.close_connection()
module_logger.info("CleanupManager: AircraftDatabaseManager connection closed.")
except Exception as e_ac_db_close:
module_logger.error(
f"CleanupManager: Error closing AircraftDatabaseManager: {e_ac_db_close}",
exc_info=True,
)
finally:
self.app_controller.aircraft_db_manager = None # Clear reference in AppController
module_logger.info("CleanupManager: Cleanup on application exit finished.")
def details_window_closed(self, closed_icao24: str):
"""
Handles the event when a full flight details window is closed.
Clears the AppController's references to the closed window if it was the active one.
Args:
closed_icao24: The ICAO24 of the flight whose details window was closed.
"""
normalized_closed_icao24 = closed_icao24.lower().strip()
# Access active_detail_window_icao and active_detail_window_ref via app_controller
if self.app_controller.active_detail_window_icao == normalized_closed_icao24:
module_logger.info(
f"CleanupManager: Detail window for {normalized_closed_icao24} reported closed. Clearing references in AppController."
)
self.app_controller.active_detail_window_ref = None
self.app_controller.active_detail_window_icao = None
# Also clear MainWindow's convenience reference if it matches (accessed via app_controller)
main_window = self.app_controller.main_window
if (
main_window
and hasattr(main_window, "full_flight_details_window")
and main_window.full_flight_details_window
and not main_window.full_flight_details_window.winfo_exists()
): # Check if already destroyed by Tkinter
main_window.full_flight_details_window = None
else:
module_logger.debug(
f"CleanupManager: A detail window for {normalized_closed_icao24} closed, but it was not the currently tracked active one ({self.app_controller.active_detail_window_icao}). No action on active_detail references."
)