# Copyright 2025–2026 European Union
# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
# SPDX-License-Identifier: EUPL-1.2
"""
Main entry point for the RadioViz application.
This module contains the main execution logic for the RadioViz desktop application.
It initializes the Qt application, sets up the application icon, installs exception
handling, and starts the main application window with the configured tools.
"""
from __future__ import annotations
import ctypes
import faulthandler
import sys
from pathlib import Path
import matplotlib
from PySide6.QtCore import Qt
from PySide6.QtGui import QIcon, QPainter, QPixmap
from PySide6.QtWidgets import QApplication, QMessageBox
from radioviz.controllers.main_controller import MainController
from radioviz.services.exception_handler import install_exception_handler
from radioviz.tools.tool_discovery import discover_tools
from radioviz.views.loading_splash import LoadingSplash
from radioviz.views.main_window import MainWindow
faulthandler.enable()
def _create_splash(icon_path: Path) -> LoadingSplash:
icon_pixmap = QPixmap(str(icon_path)) if icon_path.exists() else QPixmap()
if icon_pixmap.isNull():
base = QPixmap(480, 240)
base.fill(Qt.GlobalColor.white)
return LoadingSplash(base)
margin = 24
base = QPixmap(icon_pixmap.width() + margin * 2, icon_pixmap.height() + margin * 2)
base.fill(Qt.GlobalColor.white)
painter = QPainter(base)
painter.drawPixmap(margin, 0, icon_pixmap)
painter.end()
return LoadingSplash(base)
[docs]
def main() -> None:
"""
Main entry point function for the RadioViz application.
Initializes the matplotlib configuration, sets up the Qt application with
Windows-specific application ID, configures the application icon, installs
the custom exception handler, and starts the main application window.
:return: None
:rtype: NoneType
:raise SystemExit: When the application exits normally
"""
# all plt.figure included in the sub windows are closed when its parent window is closed, but
# nobody can prevent the user to open more than 20 figures simultaneously.
matplotlib.rcParams['figure.max_open_warning'] = -1
if sys.platform == 'win32':
app_id = 'jrc.kada.radioviz.1'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id)
app = QApplication(sys.argv)
# Set application icon
icon_path = Path(__file__).parent.parent / 'resources' / 'radioviz-logo-trasp.ico'
if icon_path.exists():
app.setWindowIcon(QIcon(str(icon_path)))
# Install our custom exception handler
install_exception_handler()
try:
splash = _create_splash(icon_path)
splash.show()
app.processEvents()
def _progress(group: str, current: int, total: int) -> None:
label = 'Loading external plugins' if group == 'external' else 'Loading built-in tools'
splash.set_status(label, current, total)
app.processEvents()
# tool_list= discover_tools(progress_cb=_progress)
main_controller = MainController(tool_list=discover_tools(progress_cb=_progress))
main_window = MainWindow(main_controller)
main_window.show()
splash.finish(main_window)
sys.exit(app.exec())
except Exception as e:
# This will be caught by our exception handler,
# but we'll add this as a fallback just in case
# noinspection PyUnboundLocalVariable
QMessageBox.critical(None, 'Fatal Error', f'An unexpected error occurred: {str(e)}')
raise # Re-raise to get a proper exit code
if __name__ == '__main__':
main()