Initial commit
Dieser Commit ist enthalten in:
386
utils/modal_manager.py
Normale Datei
386
utils/modal_manager.py
Normale Datei
@ -0,0 +1,386 @@
|
||||
"""
|
||||
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
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren