Files
Plugin_SN_Basis/functions/dialog_wrapper.py

227 lines
6.6 KiB
Python
Raw Permalink Normal View History

"""
sn_basis/functions/dialog_wrapper.py Benutzer-Dialoge (Qt5/6/Mock-kompatibel)
"""
from typing import Any
from typing import Literal, Optional
from sn_basis.functions.qt_wrapper import (
QMessageBox, YES, NO, CANCEL, QT_VERSION, exec_dialog, ICON_QUESTION,
QProgressDialog, QCoreApplication, Qt, QInputDialog, QLineEdit,
)
def ask_yes_no(
title: str,
message: str,
default: bool = True,
parent: Any = None,
) -> bool:
"""
Stellt Ja/Nein-Frage. Funktioniert in PyQt5/6 UND Mock-Modus.
"""
try:
if QT_VERSION == 0: # Mock-Modus
print(f"🔍 Mock-Modus: ask_yes_no('{title}') → {default}")
return default
# ✅ KORREKT: Verwende YES/NO-Aliase aus qt_wrapper!
buttons = YES | NO
default_button = YES if default else NO
result = QMessageBox.question(
parent, title, message, buttons, default_button
)
# ✅ int(result) == int(YES) funktioniert Qt5/6/Mock
print(f"DEBUG ask_yes_no: result={result}, YES={YES}, match={int(result) == int(YES)}")
return int(result) == int(YES)
except Exception as e:
print(f"⚠️ ask_yes_no Fehler: {e}")
return default
def show_info_dialog(title: str, message: str, parent: Any = None) -> None:
"""
Zeigt einen modalen Info-Dialog mit OK-Button.
Blockiert bis der Nutzer bestätigt.
"""
try:
if QT_VERSION == 0: # Mock-Modus
print(f"Mock-Modus: show_info_dialog('{title}')")
return
QMessageBox.information(parent, title, message)
except Exception as e:
print(f"⚠️ show_info_dialog Fehler: {e}")
def ask_text(
title: str,
label: str,
default_text: str = "",
parent: Any = None,
) -> tuple[str, bool]:
"""Zeigt einen modalen Texteingabe-Dialog und gibt Text + OK-Status zurück."""
try:
if QT_VERSION == 0: # Mock-Modus
print(f"Mock-Modus: ask_text('{title}') -> '{default_text}'")
return default_text, True
# PyQt6: QLineEdit.EchoMode.Normal / PyQt5: QLineEdit.Normal
echo_mode = (
getattr(QLineEdit, "Normal", None)
or getattr(getattr(QLineEdit, "EchoMode", None), "Normal", None)
or 0
)
text, accepted = QInputDialog.getText(
parent,
title,
label,
echo_mode,
default_text,
)
return str(text or ""), bool(accepted)
except Exception as e:
print(f"⚠️ ask_text Fehler: {e}")
return default_text, False
OverwriteDecision = Optional[Literal["overwrite", "append", "cancel"]]
def ask_overwrite_append_cancel_custom(
parent,
title: str,
message: str,
) -> Literal["overwrite", "append", "cancel"]:
"""Zeigt Dialog mit benutzerdefinierten Buttons: Überschreiben/Anhängen/Abbrechen.
Parameters
----------
parent :
Eltern-Widget oder None.
title : str
Dialog-Titel.
message : str
Hauptmeldung mit Erklärung.
Returns
-------
Literal["overwrite", "append", "cancel"]
Genaue Entscheidung des Nutzers.
"""
msg = QMessageBox(parent)
msg.setIcon(ICON_QUESTION)
msg.setWindowTitle(title)
msg.setText(message)
# Eigene Buttons mit exakten Texten
overwrite_btn = msg.addButton("Überschreiben", QMessageBox.ButtonRole.AcceptRole)
append_btn = msg.addButton("Anhängen", QMessageBox.ButtonRole.ActionRole)
cancel_btn = msg.addButton("Abbrechen", QMessageBox.ButtonRole.RejectRole)
exec_dialog(msg)
clicked = msg.clickedButton()
if clicked == overwrite_btn:
return "overwrite"
elif clicked == append_btn:
return "append"
else: # cancel_btn
return "cancel"
2026-03-12 16:14:02 +01:00
class ProgressDialog:
def __init__(self, total: int, title: str = "Fortschritt", label: str = "Verarbeite..."):
self.total = max(total, 1)
self._canceled = False
if QT_VERSION == 0:
self.value = 0
self.label = label
self.title = title
return
self._dlg = QProgressDialog(label, "Abbrechen", 0, self.total)
self._dlg.setWindowTitle(title)
# Qt5 vs Qt6: WindowModality-Enum unterschiedlich verfügbar
modality = None
if hasattr(Qt, "WindowModality"):
try:
modality = Qt.WindowModality.WindowModal
except Exception:
modality = None
if modality is None and hasattr(Qt, "WindowModal"):
modality = Qt.WindowModal
if modality is not None:
try:
self._dlg.setWindowModality(modality)
except Exception:
pass
self._dlg.setMinimumDuration(0)
self._dlg.setAutoClose(False)
self._dlg.setAutoReset(False)
self._dlg.setValue(0)
def on_cancel():
if self._dlg and self._dlg.value() >= self.total:
# OK-Button am Ende
self._dlg.close()
return
self._canceled = True
self._dlg.close()
try:
self._dlg.canceled.connect(on_cancel)
except Exception:
pass
def set_total(self, total: int) -> None:
self.total = max(total, 1)
if QT_VERSION == 0:
return
if self._dlg is not None:
self._dlg.setMaximum(self.total)
def set_value(self, value: int) -> None:
if QT_VERSION == 0:
self.value = value
return
if self._dlg is not None:
self._dlg.setValue(min(value, self.total))
if value >= self.total:
self._dlg.setLabelText("Fertig. Klicken Sie auf OK, um das Fenster zu schließen.")
self._dlg.setCancelButtonText("OK")
QCoreApplication.processEvents()
def set_label(self, text: str) -> None:
if QT_VERSION == 0:
self.label = text
return
if self._dlg is not None:
self._dlg.setLabelText(text)
QCoreApplication.processEvents()
def is_canceled(self) -> bool:
if QT_VERSION == 0:
return self._canceled
if self._dlg is not None:
return self._canceled or self._dlg.wasCanceled()
return self._canceled
def close(self) -> None:
if QT_VERSION == 0:
return
if self._dlg is not None:
self._dlg.close()
def create_progress_dialog(total: int, title: str = "Fortschritt", label: str = "Verarbeite...") -> ProgressDialog:
return ProgressDialog(total, title, label)