Files
AccountForger-neuerUpload/utils/modal_manager.py
Claude Project Manager 04585e95b6 Initial commit
2025-08-01 23:50:28 +02:00

386 Zeilen
12 KiB
Python

"""
Modal Manager - Zentraler Manager für alle Progress-Modals
"""
import logging
from typing import Optional, Dict, Any
from PyQt5.QtCore import QObject, pyqtSignal, QTimer
from PyQt5.QtWidgets import QWidget
from views.widgets.progress_modal import ProgressModal
from styles.modal_styles import ModalStyles
logger = logging.getLogger("modal_manager")
class ModalManager(QObject):
"""
Zentraler Manager für alle Progress-Modals.
Koordiniert das Anzeigen und Verstecken von Modals während Automatisierungsprozessen.
"""
# Signale
modal_shown = pyqtSignal(str) # Modal-Typ
modal_hidden = pyqtSignal(str) # Modal-Typ
modal_force_closed = pyqtSignal(str) # Modal-Typ
def __init__(self, parent_window: QWidget = None, language_manager=None, style_manager=None):
super().__init__()
self.parent_window = parent_window
self.language_manager = language_manager
self.style_manager = style_manager or ModalStyles()
# Aktive Modals verwalten
self.active_modals: Dict[str, ProgressModal] = {}
self.modal_stack = [] # Stack für verschachtelte Modals
# Auto-Hide Timer für Fehler-Modals
self.auto_hide_timers: Dict[str, QTimer] = {}
logger.info("ModalManager initialisiert")
def show_modal(self, modal_type: str, title: str = None, status: str = None, detail: str = None) -> bool:
"""
Zeigt ein Progress-Modal an.
Args:
modal_type: Typ des Modals ('account_creation', 'login_process', etc.)
title: Optional - benutzerdefinierter Titel
status: Optional - benutzerdefinierter Status
detail: Optional - benutzerdefinierter Detail-Text
Returns:
bool: True wenn Modal erfolgreich angezeigt wurde
"""
try:
# Prüfe ob Modal bereits aktiv ist
if modal_type in self.active_modals:
logger.warning(f"Modal '{modal_type}' ist bereits aktiv")
return False
# Erstelle neues Modal
modal = ProgressModal(
parent=self.parent_window,
modal_type=modal_type,
language_manager=self.language_manager,
style_manager=self.style_manager
)
# Verbinde Signale
modal.force_closed.connect(lambda: self._handle_force_close(modal_type))
# Speichere Modal
self.active_modals[modal_type] = modal
self.modal_stack.append(modal_type)
# Benutzerdefinierte Texte setzen (falls angegeben)
if title or status or detail:
if title:
modal.title_label.setText(title)
if status:
modal.status_label.setText(status)
if detail:
modal.detail_label.setText(detail)
modal.detail_label.setVisible(True)
# Modal anzeigen
modal.show_process(modal_type)
# Signal senden
self.modal_shown.emit(modal_type)
logger.info(f"Modal '{modal_type}' angezeigt")
return True
except Exception as e:
logger.error(f"Fehler beim Anzeigen des Modals '{modal_type}': {e}")
return False
def hide_modal(self, modal_type: str) -> bool:
"""
Versteckt ein spezifisches Modal.
Args:
modal_type: Typ des zu versteckenden Modals
Returns:
bool: True wenn Modal erfolgreich versteckt wurde
"""
try:
if modal_type not in self.active_modals:
logger.warning(f"Modal '{modal_type}' ist nicht aktiv")
return False
modal = self.active_modals[modal_type]
# Modal verstecken
modal.hide_process()
# Aus aktiven Modals entfernen
del self.active_modals[modal_type]
# Aus Stack entfernen
if modal_type in self.modal_stack:
self.modal_stack.remove(modal_type)
# Auto-Hide Timer stoppen (falls vorhanden)
if modal_type in self.auto_hide_timers:
self.auto_hide_timers[modal_type].stop()
del self.auto_hide_timers[modal_type]
# Modal löschen
modal.deleteLater()
# Signal senden
self.modal_hidden.emit(modal_type)
logger.info(f"Modal '{modal_type}' versteckt")
return True
except Exception as e:
logger.error(f"Fehler beim Verstecken des Modals '{modal_type}': {e}")
return False
def update_modal_status(self, modal_type: str, status: str, detail: str = None) -> bool:
"""
Aktualisiert den Status eines aktiven Modals.
Args:
modal_type: Typ des Modals
status: Neuer Status-Text
detail: Optional - neuer Detail-Text
Returns:
bool: True wenn Update erfolgreich war
"""
try:
if modal_type not in self.active_modals:
logger.warning(f"Modal '{modal_type}' ist nicht aktiv für Status-Update")
return False
modal = self.active_modals[modal_type]
modal.update_status(status, detail)
logger.debug(f"Modal '{modal_type}' Status aktualisiert: {status}")
return True
except Exception as e:
logger.error(f"Fehler beim Aktualisieren des Modal-Status '{modal_type}': {e}")
return False
def show_modal_error(self, modal_type: str, error_message: str, auto_close_seconds: int = 3) -> bool:
"""
Zeigt eine Fehlermeldung in einem Modal an.
Args:
modal_type: Typ des Modals
error_message: Fehlermeldung
auto_close_seconds: Sekunden bis automatisches Schließen
Returns:
bool: True wenn Fehler erfolgreich angezeigt wurde
"""
try:
if modal_type not in self.active_modals:
# Erstelle neues Error-Modal
self.show_modal(modal_type, "❌ Fehler aufgetreten", error_message)
modal = self.active_modals[modal_type]
else:
modal = self.active_modals[modal_type]
modal.show_error(error_message, auto_close_seconds)
# Auto-Hide Timer setzen
if auto_close_seconds > 0:
timer = QTimer()
timer.setSingleShot(True)
timer.timeout.connect(lambda: self.hide_modal(modal_type))
timer.start(auto_close_seconds * 1000)
self.auto_hide_timers[modal_type] = timer
logger.info(f"Fehler in Modal '{modal_type}' angezeigt: {error_message}")
return True
except Exception as e:
logger.error(f"Fehler beim Anzeigen des Modal-Fehlers '{modal_type}': {e}")
return False
def hide_all_modals(self):
"""Versteckt alle aktiven Modals"""
modal_types = list(self.active_modals.keys())
for modal_type in modal_types:
self.hide_modal(modal_type)
logger.info("Alle Modals versteckt")
def is_modal_active(self, modal_type: str) -> bool:
"""
Prüft ob ein bestimmtes Modal aktiv ist.
Args:
modal_type: Typ des zu prüfenden Modals
Returns:
bool: True wenn Modal aktiv ist
"""
return modal_type in self.active_modals
def get_active_modals(self) -> list:
"""
Gibt eine Liste aller aktiven Modal-Typen zurück.
Returns:
list: Liste der aktiven Modal-Typen
"""
return list(self.active_modals.keys())
def get_current_modal(self) -> Optional[str]:
"""
Gibt den aktuell obersten Modal-Typ zurück.
Returns:
Optional[str]: Modal-Typ oder None wenn kein Modal aktiv
"""
return self.modal_stack[-1] if self.modal_stack else None
def _handle_force_close(self, modal_type: str):
"""
Behandelt das zwangsweise Schließen eines Modals (durch Timeout).
Args:
modal_type: Typ des geschlossenen Modals
"""
logger.warning(f"Modal '{modal_type}' wurde zwangsweise geschlossen")
# Modal aus aktiven Modals entfernen
if modal_type in self.active_modals:
del self.active_modals[modal_type]
# Aus Stack entfernen
if modal_type in self.modal_stack:
self.modal_stack.remove(modal_type)
# Signal senden
self.modal_force_closed.emit(modal_type)
def handle_event(self, action: str, modal_type: str, **kwargs):
"""
Zentrale Event-Behandlung für Modal-Aktionen.
Args:
action: Aktion ('show', 'hide', 'update', 'error')
modal_type: Typ des Modals
**kwargs: Zusätzliche Parameter je nach Aktion
"""
try:
if action == 'show':
title = kwargs.get('title')
status = kwargs.get('status')
detail = kwargs.get('detail')
self.show_modal(modal_type, title, status, detail)
elif action == 'hide':
self.hide_modal(modal_type)
elif action == 'update':
status = kwargs.get('status', '')
detail = kwargs.get('detail')
self.update_modal_status(modal_type, status, detail)
elif action == 'error':
error_message = kwargs.get('error_message', 'Unbekannter Fehler')
auto_close = kwargs.get('auto_close_seconds', 3)
self.show_modal_error(modal_type, error_message, auto_close)
else:
logger.warning(f"Unbekannte Modal-Aktion: {action}")
except Exception as e:
logger.error(f"Fehler bei Modal-Event-Behandlung: {e}")
def set_parent_window(self, parent_window: QWidget):
"""
Setzt das Parent-Fenster für neue Modals.
Args:
parent_window: Das Parent-Widget
"""
self.parent_window = parent_window
logger.debug("Parent-Fenster für ModalManager gesetzt")
# Globale Instanz für einfachen Zugriff
_global_modal_manager: Optional[ModalManager] = None
def get_modal_manager() -> Optional[ModalManager]:
"""
Gibt die globale ModalManager-Instanz zurück.
Returns:
Optional[ModalManager]: Die globale Instanz oder None
"""
return _global_modal_manager
def set_modal_manager(modal_manager: ModalManager):
"""
Setzt die globale ModalManager-Instanz.
Args:
modal_manager: Die zu setzende ModalManager-Instanz
"""
global _global_modal_manager
_global_modal_manager = modal_manager
def show_progress_modal(modal_type: str, **kwargs) -> bool:
"""
Convenience-Funktion zum Anzeigen eines Progress-Modals.
Args:
modal_type: Typ des Modals
**kwargs: Zusätzliche Parameter
Returns:
bool: True wenn erfolgreich
"""
manager = get_modal_manager()
if manager:
return manager.show_modal(modal_type, **kwargs)
return False
def hide_progress_modal(modal_type: str) -> bool:
"""
Convenience-Funktion zum Verstecken eines Progress-Modals.
Args:
modal_type: Typ des Modals
Returns:
bool: True wenn erfolgreich
"""
manager = get_modal_manager()
if manager:
return manager.hide_modal(modal_type)
return False
def update_progress_modal(modal_type: str, status: str, detail: str = None) -> bool:
"""
Convenience-Funktion zum Aktualisieren eines Progress-Modals.
Args:
modal_type: Typ des Modals
status: Neuer Status
detail: Optional - neuer Detail-Text
Returns:
bool: True wenn erfolgreich
"""
manager = get_modal_manager()
if manager:
return manager.update_modal_status(modal_type, status, detail)
return False