Files
Plugin_SN_Basis/functions/dialog_wrapper.py

227 lines
6.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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"
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)