""" 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