711 lines
30 KiB
Python
Executable File
711 lines
30 KiB
Python
Executable File
import tkinter as tk
|
|
import shutil
|
|
from tkinter import filedialog, messagebox, font, ttk, simpledialog, Toplevel, Label, Entry, Button, Checkbutton, IntVar
|
|
import time
|
|
import os
|
|
from queue import Queue
|
|
import subprocess
|
|
|
|
# Style einmalig konfigurieren (wird beim ersten Import ausgeführt)
|
|
_style_configured = False
|
|
|
|
def create_macos_button(parent, text, command=None, width=None, height=None, padx=10, pady=5):
|
|
"""Erstellt einen Button im macOS-Stil mit größerer, lesbarerer Darstellung"""
|
|
global _style_configured
|
|
# Style nur einmal konfigurieren
|
|
if not _style_configured:
|
|
style = ttk.Style()
|
|
style.configure('TButton', font=('Helvetica', 13))
|
|
_style_configured = True
|
|
|
|
# Verwende ttk.Button für besseres macOS-Aussehen
|
|
btn = ttk.Button(parent, text=text, command=command)
|
|
if width:
|
|
btn.config(width=width)
|
|
return btn
|
|
|
|
class SettingsDialog:
|
|
def __init__(self, parent, config):
|
|
self.config = config
|
|
self.top = Toplevel(parent)
|
|
self.top.title("Einstellungen")
|
|
# Erhöhe die Breite des Fensters
|
|
self.top.geometry('550x200') # Beispielgröße, anpassbar
|
|
|
|
Label(self.top, text="Server URL:").grid(row=0, column=0)
|
|
self.server_url_entry = Entry(self.top, width=40) # Erhöhe die Breite des Eingabefelds
|
|
self.server_url_entry.grid(row=0, column=1, padx=10, pady=5)
|
|
|
|
Label(self.top, text="Username:").grid(row=1, column=0)
|
|
self.username_entry = Entry(self.top, width=40) # Erhöhe die Breite des Eingabefelds
|
|
self.username_entry.grid(row=1, column=1, padx=10, pady=5)
|
|
|
|
Label(self.top, text="Password:").grid(row=2, column=0)
|
|
self.password_entry = Entry(self.top, show="*", width=40) # Erhöhe die Breite des Eingabefelds
|
|
self.password_entry.grid(row=2, column=1, padx=10, pady=5)
|
|
|
|
self.show_password_var = IntVar()
|
|
self.show_password_check = Checkbutton(self.top, text='Zeigen', variable=self.show_password_var, command=self.toggle_password_visibility)
|
|
self.show_password_check.grid(row=2, column=2)
|
|
|
|
# Checkbox für CD-Überprüfung hinzufügen
|
|
self.check_for_cd_var = IntVar(value=int(self.config.get('check_for_cd', '0')))
|
|
self.check_for_cd_check = Checkbutton(self.top, text="Bei Start nach CDs suchen", variable=self.check_for_cd_var)
|
|
self.check_for_cd_check.grid(row=3, column=0, columnspan=2, sticky="w", padx=10, pady=5)
|
|
|
|
self.load_config() # Laden der aktuellen Konfiguration
|
|
|
|
# Speichern-Button (macOS-Style) - größer und lesbarer
|
|
save_btn = create_macos_button(self.top, text="Speichern", command=self.save_config, width=20)
|
|
save_btn.grid(row=4, column=1, pady=15, padx=5)
|
|
|
|
def toggle_password_visibility(self):
|
|
"""Wechselt die Sichtbarkeit des Passworteingabefelds."""
|
|
if self.show_password_var.get() == 1:
|
|
self.password_entry.config(show="")
|
|
else:
|
|
self.password_entry.config(show="*")
|
|
|
|
def load_config(self):
|
|
config_path = os.path.join(os.path.expanduser('~'), '.dicom2pacs.conf')
|
|
try:
|
|
with open(config_path, 'r') as config_file:
|
|
for line in config_file:
|
|
key, value = line.strip().split('=', 1)
|
|
if key == 'server_url':
|
|
self.server_url_entry.insert(0, value)
|
|
elif key == 'server_username':
|
|
self.username_entry.insert(0, value)
|
|
elif key == 'server_pw':
|
|
self.password_entry.insert(0, value)
|
|
except FileNotFoundError:
|
|
print("Konfigurationsdatei nicht gefunden. Verwende Standardwerte.")
|
|
|
|
def save_config(self):
|
|
config = {
|
|
'server_url': self.server_url_entry.get(),
|
|
'server_username': self.username_entry.get(),
|
|
'server_pw': self.password_entry.get(),
|
|
'check_for_cd' : str(self.check_for_cd_var.get())
|
|
}
|
|
config_path = os.path.join(os.path.expanduser('~'), '.dicom2pacs.conf')
|
|
with open(config_path, 'w') as config_file:
|
|
for key, value in config.items():
|
|
config_file.write(f'{key}={value}\n')
|
|
self.top.destroy()
|
|
|
|
|
|
class GUI:
|
|
def __init__(self, on_folder_selected_callback, transfer_folder, on_close_callback, config):
|
|
self.config = config
|
|
self.on_folder_selected = on_folder_selected_callback
|
|
self.transfer_folder = transfer_folder
|
|
self.on_close = on_close_callback
|
|
|
|
self.root = tk.Tk()
|
|
self.root.title("Bilder einlesen")
|
|
# Erstellen der Menüleiste
|
|
menubar = tk.Menu(self.root)
|
|
self.root.config(menu=menubar) # Diese Zeile weist das 'menubar' Objekt dem 'menu' Attribut des Hauptfensters zu
|
|
|
|
# Erstellen des Einstellungsmenüs
|
|
settings_menu = tk.Menu(menubar, tearoff=0)
|
|
settings_menu.add_command(label="Einstellungen... \u2318,", command=self.open_settings_dialog)
|
|
menubar.add_cascade(label="Einstellungen", menu=settings_menu)
|
|
|
|
self.bind_shortcuts()
|
|
|
|
# Fenstergröße und -position festlegen
|
|
window_width = 350
|
|
window_height = 150
|
|
screen_width = self.root.winfo_screenwidth()
|
|
screen_height = self.root.winfo_screenheight()
|
|
center_x = int(screen_width / 2 - window_width / 2)
|
|
center_y = int(screen_height / 2 - window_height / 2)
|
|
self.root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
|
|
|
|
# Erstelle die Progressbar
|
|
self.progress = ttk.Progressbar(self.root, orient="horizontal", length=300, mode='determinate')
|
|
self.progress.pack(pady=20)
|
|
|
|
# Frame für die Buttons am unteren Rand des Fensters
|
|
self.button_frame = tk.Frame(self.root)
|
|
self.button_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=15)
|
|
|
|
# Durchsuchen Button (macOS-Style) - größer und lesbarer
|
|
self.browse_button = create_macos_button(self.button_frame, text="Durchsuchen", command=self.browse, width=18)
|
|
self.browse_button.pack(side=tk.LEFT, padx=15, expand=True, pady=5)
|
|
|
|
# Schließen Button (macOS-Style) - größer und lesbarer
|
|
self.close_button = create_macos_button(self.button_frame, text="Abbruch", command=self.on_app_close, width=18)
|
|
self.close_button.pack(side=tk.RIGHT, padx=15, expand=True, pady=5)
|
|
|
|
self.hint_label = tk.Label(self.root, text="Bitte wählen Sie den Ordner mit den Bilddaten aus!")
|
|
self.hint_label.pack(pady=5) # Pady hinzugefügt für etwas Abstand nach oben und unten
|
|
|
|
self.root.protocol("WM_DELETE_WINDOW", self.on_close)
|
|
|
|
self.searching = False
|
|
|
|
self.searching_label = None
|
|
self.labels_frame = tk.Frame(self.root) # Ein Frame für die animierten Labels
|
|
self.labels_frame.pack(fill=tk.BOTH, expand=True)
|
|
self.label_widgets = []
|
|
self.text_queue = Queue()
|
|
self.currently_animating = False
|
|
|
|
|
|
def save_cd_check_setting(self):
|
|
# Speichert den Zustand der Checkbox in der Konfigurationsdatei
|
|
self.config['check_for_cd'] = str(self.check_for_cd_var.get())
|
|
config_path = os.path.join(os.path.expanduser('~'), '.dicom2pacs.conf')
|
|
with open(config_path, 'w') as config_file:
|
|
for key, value in self.config.items():
|
|
config_file.write(f'{key}={value}\n')
|
|
|
|
def load_cd_check_setting(self):
|
|
# Lädt den Zustand der Checkbox aus der Konfigurationsdatei
|
|
self.check_for_cd_var.set(int(self.config.get('check_for_cd', 0)))
|
|
|
|
def start_animation(self, text):
|
|
self.text_queue.put(text)
|
|
if not self.currently_animating:
|
|
self.currently_animating = True
|
|
self.process_next_animation()
|
|
|
|
def process_next_animation(self):
|
|
if not self.text_queue.empty():
|
|
text = self.text_queue.get()
|
|
label = tk.Label(self.labels_frame, text=text)
|
|
label.pack()
|
|
self.label_widgets.append(label)
|
|
self.blink(label)
|
|
else:
|
|
self.currently_animating = False
|
|
|
|
def blink(self, label, is_visible=True):
|
|
if label in self.label_widgets and self.currently_animating:
|
|
label.config(foreground=self.root.cget('bg') if is_visible else 'black')
|
|
self.root.after(1000, lambda: self.blink(label, not is_visible))
|
|
|
|
def stop_animation(self):
|
|
self.currently_animating = False
|
|
self.clear_labels()
|
|
|
|
def clear_labels(self):
|
|
for label in self.label_widgets:
|
|
label.destroy()
|
|
self.label_widgets.clear()
|
|
|
|
def update_searching_label(self, text):
|
|
# Aktualisiere das Suchlabel
|
|
if hasattr(self, 'searching_label'):
|
|
self.searching_label.config(text=text)
|
|
self.root.update_idletasks()
|
|
|
|
def reset_progress(self, total_files):
|
|
self.progress['value'] = 0
|
|
self.progress['maximum'] = total_files
|
|
print("Fortschrittsanzeige wurde zurückgesetzt.")
|
|
self.root.update_idletasks()
|
|
|
|
def update_progress(self, incremental_progress, total_files):
|
|
if self.progress['value'] == 0 and incremental_progress == 0:
|
|
# Initialisierung bei Beginn des Upload-Prozesses
|
|
print("Initialisiere Fortschrittsanzeige auf 0")
|
|
else:
|
|
self.progress['value'] += incremental_progress
|
|
|
|
new_value = self.progress['value']
|
|
|
|
print(f"Aktualisiere Fortschritt: {new_value}/{total_files}")
|
|
print(f"Aktueller Wert der Progressbar: {new_value - incremental_progress}")
|
|
print(f"Neuer Wert der Progressbar: {new_value}")
|
|
|
|
self.progress['maximum'] = total_files
|
|
self.root.update_idletasks()
|
|
|
|
|
|
def start(self):
|
|
self.root.mainloop()
|
|
|
|
def browse(self):
|
|
# Öffne das Browse-Fenster
|
|
self.hint_label.pack_forget()
|
|
# Öffne standardmäßig den Downloads-Ordner
|
|
downloads_folder = os.path.join(os.path.expanduser('~'), 'Downloads')
|
|
if not os.path.exists(downloads_folder):
|
|
downloads_folder = os.path.expanduser('~') # Fallback auf Home-Verzeichnis
|
|
|
|
source_folder = filedialog.askdirectory(initialdir=downloads_folder, title="Wählen Sie den Ordner mit den DICOM-Dateien")
|
|
if source_folder: # Prüfe, ob ein Ordner ausgewählt wurde
|
|
print(f"Ausgewähltes Verzeichnis: {source_folder}")
|
|
print("Vor dem Aufruf von on_folder_selected") # Debugging-Ausgabe
|
|
self.on_folder_selected(source_folder) # Ruf den Callback mit dem ausgewählten Ordner auf
|
|
print("Nach dem Aufruf von on_folder_selected") # Debugging-Ausgabe
|
|
else:
|
|
print("Kein Ordner ausgewählt.")
|
|
|
|
def close(self):
|
|
self.root.destroy()
|
|
|
|
def show_discrepancy_dialog(self, message):
|
|
dialog = JaAbbruchDialog(self.root, "Unstimmigkeiten gefunden", message, self.on_app_close, self.transfer_folder)
|
|
response = dialog.show()
|
|
return response
|
|
|
|
def show_confirm_keep_original_dialog(self, tomedo_data, original_data):
|
|
"""Zeigt einen Bestätigungsdialog, wenn Original-Daten behalten werden sollen"""
|
|
dialog = ConfirmKeepOriginalDialog(self.root, self.on_app_close, self.transfer_folder, tomedo_data, original_data)
|
|
response = dialog.show()
|
|
return response
|
|
|
|
def ask_for_more(self, message):
|
|
dialog = JaNeinAbbruchDialog(self.root, "Weitere DICOM Dateien einlesen?", message, self.on_app_close, self.transfer_folder)
|
|
response = dialog.show()
|
|
if response: # Wenn die Antwort True ist, also der Benutzer mit Ja antwortet
|
|
print(response)
|
|
# Öffne standardmäßig den Downloads-Ordner
|
|
downloads_folder = os.path.join(os.path.expanduser('~'), 'Downloads')
|
|
if not os.path.exists(downloads_folder):
|
|
downloads_folder = os.path.expanduser('~') # Fallback auf Home-Verzeichnis
|
|
|
|
source_folder = filedialog.askdirectory(initialdir=downloads_folder, title="Wählen Sie den Ordner mit den DICOM-Dateien")
|
|
if not source_folder: # Prüfen, ob der Benutzer den Vorgang abgebrochen hat, ohne einen Ordner auszuwählen
|
|
return False # Sie können hier entscheiden, ob False oder eine andere Kennzeichnung zurückgegeben wird
|
|
return response, source_folder
|
|
else:
|
|
print(response)
|
|
return response, None
|
|
|
|
|
|
def on_app_close(self):
|
|
print("App wird beendet...")
|
|
|
|
|
|
# Beende den Tkinter Event-Loop und schließe alle Fenster
|
|
try:
|
|
self.root.quit()
|
|
except Exception as e:
|
|
print(f"Fehler beim Beenden des Tkinter Event-Loops: {e}")
|
|
|
|
# Lösche den Transferordner
|
|
try:
|
|
shutil.rmtree(self.transfer_folder)
|
|
print(f"Transferordner {self.transfer_folder} wurde gelöscht.")
|
|
except Exception as e:
|
|
print(f"Fehler beim Löschen des Transferordners: {e}")
|
|
|
|
# Datei existiert nicht, keine Aktion erforderlich
|
|
|
|
|
|
def upload_progress(self, incremental_progress, total_files):
|
|
if incremental_progress == 0:
|
|
self.progress['value'] = 0
|
|
# Initialisierung bei Beginn des Upload-Prozesses
|
|
print("Initialisiere Fortschrittsanzeige auf 0")
|
|
else:
|
|
self.progress['value'] += incremental_progress
|
|
|
|
new_value = self.progress['value']
|
|
|
|
print(f"Aktualisiere Fortschritt: {new_value}/{total_files}")
|
|
print(f"Aktueller Wert der Progressbar: {new_value - incremental_progress}")
|
|
print(f"Neuer Wert der Progressbar: {new_value}")
|
|
|
|
self.progress['maximum'] = total_files
|
|
self.root.update_idletasks()
|
|
|
|
async def upload_success(self, message):
|
|
try:
|
|
# Angenommen, wir führen eine Aktion aus, die fehlschlagen könnte
|
|
print("Upload erfolgreich:", message) # Beispiel: Drucke die Erfolgsmeldung in der Konsole
|
|
|
|
# Planen Sie GUI-Updates im Hauptthread
|
|
#self.root.after(0, self.show_success_message, message)
|
|
except Exception as e:
|
|
print(f"Fehler in upload_success: {e}")
|
|
# Planen Sie die Fehlermeldung im Hauptthread, um Thread-Sicherheit zu gewährleisten
|
|
#self.root.after(0, self.show_error_message, str(e))
|
|
|
|
def show_success_message(self, message):
|
|
messagebox.showinfo("Upload Erfolg", message)
|
|
|
|
def show_error_message(self, message):
|
|
messagebox.showerror("Fehler", message)
|
|
def disable_browse_button(self):
|
|
"""Deaktiviert den Durchsuchen Button."""
|
|
self.browse_button.config(state=tk.DISABLED)
|
|
|
|
def enable_browse_button(self):
|
|
"""Aktiviert den Durchsuchen Button."""
|
|
self.browse_button.config(state=tk.NORMAL)
|
|
def bind_shortcuts(self):
|
|
self.root.bind('<Command-comma>', lambda event: self.open_settings_dialog())
|
|
def open_settings_dialog(self):
|
|
# Erstellt eine Instanz der SettingsDialog Klasse
|
|
SettingsDialog(self.root, self.config)
|
|
|
|
class JaAbbruchDialog(tk.Toplevel):
|
|
def __init__(self, parent, title, message, on_app_close, transfer_folder=None):
|
|
super().__init__(parent)
|
|
self.result = None
|
|
self.on_app_close = on_app_close
|
|
self.transfer_folder = transfer_folder
|
|
|
|
self.title(title)
|
|
self.geometry("900x500") # Größeres Fenster für bessere Lesbarkeit
|
|
self.minsize(850, 480) # Minimale Größe erhöht
|
|
|
|
# Hauptframe für besseres Layout
|
|
main_frame = tk.Frame(self)
|
|
main_frame.pack(fill=tk.BOTH, expand=True, padx=40, pady=30)
|
|
|
|
italic_font = font.Font(family="Helvetica", size=14, slant="italic")
|
|
bold_font = font.Font(family="Helvetica", size=15, weight="bold")
|
|
normal_font = font.Font(family="Helvetica", size=14)
|
|
header_font = font.Font(family="Helvetica", size=17, weight="bold")
|
|
|
|
# Titel
|
|
title_label = tk.Label(main_frame, text=title, font=header_font)
|
|
title_label.pack(pady=(0, 30))
|
|
|
|
# Erwartete Daten - in einem Frame mit Hintergrund
|
|
expected_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.SUNKEN, bd=1)
|
|
expected_frame.pack(fill=tk.X, pady=(0, 20))
|
|
|
|
expected_inner = tk.Frame(expected_frame, bg='#ffffff')
|
|
expected_inner.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
|
|
|
|
tk.Label(expected_inner, text="Erwartete Daten (Tomedo):", font=italic_font,
|
|
bg='#ffffff', fg='#0066cc', anchor="w").pack(pady=(0, 8), fill=tk.X)
|
|
expected_label = tk.Label(expected_inner, text=message.split('\n\n')[0],
|
|
font=normal_font, justify=tk.LEFT, wraplength=800,
|
|
bg='#ffffff', fg='#000000', anchor="w")
|
|
expected_label.pack(pady=(0, 0), fill=tk.X)
|
|
|
|
# Gefundene Daten - in einem Frame mit Hintergrund
|
|
found_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.SUNKEN, bd=1)
|
|
found_frame.pack(fill=tk.X, pady=(0, 30))
|
|
|
|
found_inner = tk.Frame(found_frame, bg='#ffffff')
|
|
found_inner.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
|
|
|
|
tk.Label(found_inner, text="Gefundene Daten (DICOM):", font=italic_font,
|
|
bg='#ffffff', fg='#cc6600', anchor="w").pack(pady=(0, 8), fill=tk.X)
|
|
found_label = tk.Label(found_inner, text=message.split('\n\n')[1],
|
|
font=normal_font, justify=tk.LEFT, wraplength=800,
|
|
bg='#ffffff', fg='#000000', anchor="w")
|
|
found_label.pack(pady=(0, 0), fill=tk.X)
|
|
|
|
# Frage
|
|
question_label = tk.Label(main_frame,
|
|
text="Welche Daten sollen verwendet werden?",
|
|
font=bold_font, wraplength=800)
|
|
question_label.pack(pady=(0, 25))
|
|
|
|
# Button-Frame mit besserem Layout - Standard macOS Buttons
|
|
btn_frame = tk.Frame(main_frame)
|
|
btn_frame.pack(pady=20)
|
|
|
|
# Standard macOS Buttons (ttk.Button für besseres macOS-Aussehen) - größer und lesbarer
|
|
yes_btn = create_macos_button(btn_frame, text="Tomedo-Daten übernehmen",
|
|
command=self.on_yes, width=35)
|
|
yes_btn.pack(side=tk.LEFT, padx=12, pady=8)
|
|
|
|
no_btn = create_macos_button(btn_frame, text="Original-Daten behalten",
|
|
command=self.on_no, width=35)
|
|
no_btn.pack(side=tk.LEFT, padx=12, pady=8)
|
|
|
|
cancel_btn = create_macos_button(btn_frame, text="Abbruch",
|
|
command=self.on_cancel, width=25)
|
|
cancel_btn.pack(side=tk.LEFT, padx=12, pady=8)
|
|
|
|
self.center_window()
|
|
|
|
def center_window(self):
|
|
self.update_idletasks() # Aktualisiere das Layout, um die Fenstergröße zu erhalten
|
|
dialog_width = self.winfo_width()
|
|
dialog_height = self.winfo_height()
|
|
|
|
# Position des Hauptfensters
|
|
parent_x = self.master.winfo_x()
|
|
parent_y = self.master.winfo_y()
|
|
parent_width = self.master.winfo_width()
|
|
parent_height = self.master.winfo_height()
|
|
|
|
# Berechne die Position für das zentrierte Dialogfenster
|
|
center_x = int(parent_x + (parent_width - dialog_width) / 2)
|
|
center_y = int(parent_y + (parent_height - dialog_height) / 2)
|
|
|
|
self.geometry(f"{dialog_width}x{dialog_height}+{center_x}+{center_y}")
|
|
|
|
|
|
def on_yes(self):
|
|
self.result = True # Tomedo-Daten übernehmen
|
|
self.destroy()
|
|
|
|
def on_no(self):
|
|
self.result = False # Original-Daten behalten
|
|
self.destroy()
|
|
|
|
def on_cancel(self):
|
|
self.result = None # Abbruch
|
|
# Lösche Transfer-Ordner bei Abbruch
|
|
if self.transfer_folder:
|
|
self._delete_transfer_folder()
|
|
self.on_app_close() # Rufe on_app_close auf
|
|
self.destroy()
|
|
|
|
def on_close(self):
|
|
self.result = None # Abbruch
|
|
# Lösche Transfer-Ordner bei Abbruch
|
|
if self.transfer_folder:
|
|
self._delete_transfer_folder()
|
|
self.on_app_close() # Rufe on_app_close auf
|
|
self.destroy()
|
|
|
|
def _delete_transfer_folder(self):
|
|
"""Löscht den Transfer-Ordner"""
|
|
import shutil
|
|
try:
|
|
if os.path.exists(self.transfer_folder):
|
|
shutil.rmtree(self.transfer_folder)
|
|
print(f"Transferordner {self.transfer_folder} wurde gelöscht.")
|
|
except Exception as e:
|
|
print(f"Fehler beim Löschen des Transferordners: {e}")
|
|
|
|
def show(self):
|
|
# Binden des Schließ-Events des Fensters an on_close
|
|
self.protocol("WM_DELETE_WINDOW", self.on_close)
|
|
self.wait_window(self)
|
|
return self.result
|
|
|
|
|
|
class ConfirmKeepOriginalDialog(tk.Toplevel):
|
|
"""Bestätigungsdialog, wenn Original-Daten behalten werden sollen"""
|
|
def __init__(self, parent, on_app_close, transfer_folder=None, tomedo_data="", original_data=""):
|
|
super().__init__(parent)
|
|
self.result = None
|
|
self.on_app_close = on_app_close
|
|
self.transfer_folder = transfer_folder
|
|
|
|
self.title("Bestätigung")
|
|
self.geometry("900x620") # Größeres Fenster für vollständige Datenanzeige und bessere Lesbarkeit
|
|
self.minsize(850, 600) # Minimale Größe erhöht
|
|
|
|
main_frame = tk.Frame(self)
|
|
main_frame.pack(fill=tk.BOTH, expand=True, padx=40, pady=30)
|
|
|
|
bold_font = font.Font(family="Helvetica", size=15, weight="bold")
|
|
normal_font = font.Font(family="Helvetica", size=14)
|
|
italic_font = font.Font(family="Helvetica", size=14, slant="italic")
|
|
header_font = font.Font(family="Helvetica", size=17, weight="bold")
|
|
|
|
# Titel
|
|
title_label = tk.Label(main_frame, text="Bestätigung", font=header_font)
|
|
title_label.pack(pady=(0, 20))
|
|
|
|
# Warnung
|
|
warning_label = tk.Label(main_frame,
|
|
text="⚠️ Warnung",
|
|
font=bold_font, fg='#cc6600')
|
|
warning_label.pack(pady=(0, 20))
|
|
|
|
# Erwartete Daten (Tomedo) - in einem Frame mit Hintergrund (wie im ersten Dialog)
|
|
tomedo_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.SUNKEN, bd=1)
|
|
tomedo_frame.pack(fill=tk.X, pady=(0, 20))
|
|
|
|
tomedo_inner = tk.Frame(tomedo_frame, bg='#ffffff')
|
|
tomedo_inner.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
|
|
|
|
tk.Label(tomedo_inner, text="Erwartete Daten (Tomedo):", font=italic_font,
|
|
bg='#ffffff', fg='#0066cc', anchor="w").pack(pady=(0, 8), fill=tk.X)
|
|
tomedo_label = tk.Label(tomedo_inner, text=tomedo_data,
|
|
font=normal_font, justify=tk.LEFT, wraplength=800,
|
|
bg='#ffffff', fg='#000000', anchor="w")
|
|
tomedo_label.pack(pady=(0, 0), fill=tk.X)
|
|
|
|
# Gefundene Daten (DICOM) - in einem Frame mit Hintergrund (wie im ersten Dialog)
|
|
original_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.SUNKEN, bd=1)
|
|
original_frame.pack(fill=tk.X, pady=(0, 25))
|
|
|
|
original_inner = tk.Frame(original_frame, bg='#ffffff')
|
|
original_inner.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
|
|
|
|
tk.Label(original_inner, text="Gefundene Daten (DICOM):", font=italic_font,
|
|
bg='#ffffff', fg='#cc6600', anchor="w").pack(pady=(0, 8), fill=tk.X)
|
|
original_label = tk.Label(original_inner, text=original_data,
|
|
font=normal_font, justify=tk.LEFT, wraplength=800,
|
|
bg='#ffffff', fg='#000000', anchor="w")
|
|
original_label.pack(pady=(0, 0), fill=tk.X)
|
|
|
|
# Frage
|
|
question_label = tk.Label(main_frame,
|
|
text="Sind Sie sicher, dass Sie die Original-Daten behalten möchten?",
|
|
font=bold_font, wraplength=800, justify=tk.CENTER)
|
|
question_label.pack(pady=(0, 10))
|
|
|
|
info_label = tk.Label(main_frame,
|
|
text="Die Tomedo-Daten sind der Standard und sollten normalerweise verwendet werden.",
|
|
font=normal_font, wraplength=800, justify=tk.CENTER, fg='#666666')
|
|
info_label.pack(pady=(0, 20))
|
|
|
|
# Button-Frame
|
|
btn_frame = tk.Frame(main_frame)
|
|
btn_frame.pack(pady=15)
|
|
|
|
# Buttons (macOS-Style) - größer und lesbarer
|
|
tomedo_btn = create_macos_button(btn_frame, text="Tomedo-Daten verwenden",
|
|
command=self.on_use_tomedo, width=32)
|
|
tomedo_btn.pack(side=tk.LEFT, padx=10, pady=8)
|
|
|
|
keep_btn = create_macos_button(btn_frame, text="Original behalten",
|
|
command=self.on_keep_original, width=28)
|
|
keep_btn.pack(side=tk.LEFT, padx=10, pady=8)
|
|
|
|
cancel_btn = create_macos_button(btn_frame, text="Abbruch",
|
|
command=self.on_cancel, width=22)
|
|
cancel_btn.pack(side=tk.LEFT, padx=10, pady=8)
|
|
|
|
self.center_window()
|
|
|
|
def center_window(self):
|
|
self.update_idletasks()
|
|
dialog_width = self.winfo_width()
|
|
dialog_height = self.winfo_height()
|
|
|
|
parent_x = self.master.winfo_x()
|
|
parent_y = self.master.winfo_y()
|
|
parent_width = self.master.winfo_width()
|
|
parent_height = self.master.winfo_height()
|
|
|
|
center_x = int(parent_x + (parent_width - dialog_width) / 2)
|
|
center_y = int(parent_y + (parent_height - dialog_height) / 2)
|
|
|
|
self.geometry(f"{dialog_width}x{dialog_height}+{center_x}+{center_y}")
|
|
|
|
def on_use_tomedo(self):
|
|
self.result = True # Tomedo-Daten verwenden
|
|
self.destroy()
|
|
|
|
def on_keep_original(self):
|
|
self.result = False # Original-Daten behalten
|
|
self.destroy()
|
|
|
|
def on_cancel(self):
|
|
self.result = None # Abbruch
|
|
# Lösche Transfer-Ordner bei Abbruch
|
|
if self.transfer_folder:
|
|
self._delete_transfer_folder()
|
|
self.on_app_close()
|
|
self.destroy()
|
|
|
|
def on_close(self):
|
|
self.result = None # Abbruch
|
|
# Lösche Transfer-Ordner bei Abbruch
|
|
if self.transfer_folder:
|
|
self._delete_transfer_folder()
|
|
self.on_app_close()
|
|
self.destroy()
|
|
|
|
def _delete_transfer_folder(self):
|
|
"""Löscht den Transfer-Ordner"""
|
|
try:
|
|
if os.path.exists(self.transfer_folder):
|
|
shutil.rmtree(self.transfer_folder)
|
|
print(f"Transferordner {self.transfer_folder} wurde gelöscht.")
|
|
except Exception as e:
|
|
print(f"Fehler beim Löschen des Transferordners: {e}")
|
|
|
|
def show(self):
|
|
self.protocol("WM_DELETE_WINDOW", self.on_close)
|
|
self.wait_window(self)
|
|
return self.result
|
|
|
|
|
|
class JaNeinAbbruchDialog(tk.Toplevel):
|
|
def __init__(self, parent, title, message, on_app_close, transfer_folder=None):
|
|
super().__init__(parent)
|
|
self.result = None
|
|
self.on_app_close = on_app_close
|
|
self.transfer_folder = transfer_folder
|
|
self.message = message # Speichere die Nachricht
|
|
|
|
self.title(title)
|
|
|
|
self.geometry("450x200") # Größeres Fenster für bessere Lesbarkeit
|
|
tk.Label(self, text=self.message, font=('Helvetica', 13)).pack(pady=25)
|
|
|
|
btn_frame = tk.Frame(self)
|
|
btn_frame.pack(pady=15)
|
|
|
|
# Buttons (macOS-Style) - größer und lesbarer
|
|
ja_btn = create_macos_button(btn_frame, text="Ja", command=self.on_ja, width=20)
|
|
ja_btn.pack(side=tk.LEFT, padx=12, pady=10)
|
|
|
|
nein_btn = create_macos_button(btn_frame, text="Nein", command=self.on_nein, width=20)
|
|
nein_btn.pack(side=tk.LEFT, padx=12, pady=10)
|
|
|
|
abbruch_btn = create_macos_button(btn_frame, text="Abbruch", command=self.on_abbruch, width=20)
|
|
abbruch_btn.pack(side=tk.LEFT, padx=12, pady=10)
|
|
|
|
self.center_window()
|
|
|
|
def center_window(self):
|
|
self.update_idletasks() # Aktualisiere das Layout, um die Fenstergröße zu erhalten
|
|
dialog_width = self.winfo_width()
|
|
dialog_height = self.winfo_height()
|
|
|
|
# Position des Hauptfensters
|
|
parent_x = self.master.winfo_x()
|
|
parent_y = self.master.winfo_y()
|
|
parent_width = self.master.winfo_width()
|
|
parent_height = self.master.winfo_height()
|
|
|
|
# Berechne die Position für das zentrierte Dialogfenster
|
|
center_x = int(parent_x + (parent_width - dialog_width) / 2)
|
|
center_y = int(parent_y + (parent_height - dialog_height) / 2)
|
|
|
|
self.geometry(f"{dialog_width}x{dialog_height}+{center_x}+{center_y}")
|
|
|
|
def on_ja(self):
|
|
self.result = True
|
|
self.destroy()
|
|
|
|
def on_nein(self):
|
|
self.result = False
|
|
self.destroy()
|
|
|
|
def on_abbruch(self):
|
|
self.result = False
|
|
# Lösche Transfer-Ordner bei Abbruch
|
|
if self.transfer_folder:
|
|
self._delete_transfer_folder()
|
|
self.on_app_close() # Rufe on_app_close auf
|
|
self.destroy()
|
|
|
|
def on_close(self):
|
|
self.result = False
|
|
# Lösche Transfer-Ordner bei Abbruch
|
|
if self.transfer_folder:
|
|
self._delete_transfer_folder()
|
|
self.on_app_close() # Rufe on_app_close auf
|
|
self.destroy()
|
|
|
|
def _delete_transfer_folder(self):
|
|
"""Löscht den Transfer-Ordner"""
|
|
try:
|
|
if os.path.exists(self.transfer_folder):
|
|
shutil.rmtree(self.transfer_folder)
|
|
print(f"Transferordner {self.transfer_folder} wurde gelöscht.")
|
|
except Exception as e:
|
|
print(f"Fehler beim Löschen des Transferordners: {e}")
|
|
|
|
def show(self):
|
|
# Binden des Schließ-Events des Fensters an on_close
|
|
self.protocol("WM_DELETE_WINDOW", self.on_close)
|
|
self.wait_window(self)
|
|
return self.result
|
|
|