import sys import os import asyncio from gui import GUI import file_management import threading import dicom_processing import shutil import network_utils from tkinter import filedialog import tkinter as tk # Konfigurationsvariablen HOME_DIRECTORY = os.path.expanduser('~') TRANSFER_FOLDER = os.path.join(HOME_DIRECTORY, 'Downloads/D2OTrans') AUSGABE_DATEI = os.path.join(HOME_DIRECTORY, 't2o_modality.txt') name = None vorname = None geburtsdatum = None patienten_id = None CONFIG_PATH = os.path.join(HOME_DIRECTORY, '.dicom2pacs.conf') # Standardkonfigurationswerte DEFAULT_CONFIG = { 'server_url': 'http://192.168.188.23:8042/instances', 'server_username': 'orthanc', 'server_pw': 'Praxis' } def save_default_config(): """Speichert die Standardkonfiguration in der Konfigurationsdatei.""" try: with open(CONFIG_PATH, 'w', encoding='utf-8') as config_file: for key, value in DEFAULT_CONFIG.items(): config_file.write(f'{key}={value}\n') except Exception as e: print(f"Fehler beim Speichern der Standardkonfiguration: {e}") def load_config(): """Lädt die Konfiguration aus der Konfigurationsdatei. Erstellt die Datei mit Standardwerten, falls nicht vorhanden.""" config = {} try: with open(CONFIG_PATH, 'r', encoding='utf-8') as config_file: for line in config_file: line = line.strip() if not line or line.startswith('#'): # Überspringe leere Zeilen und Kommentare continue if '=' in line: key, value = line.split('=', 1) config[key.strip()] = value.strip() except FileNotFoundError: print("Konfigurationsdatei nicht gefunden. Erstelle eine mit Standardwerten.") save_default_config() config = DEFAULT_CONFIG.copy() # Verwende Kopie der Standardwerte except Exception as e: print(f"Fehler beim Laden der Konfiguration: {e}") print("Verwende Standardwerte.") config = DEFAULT_CONFIG.copy() return config config = load_config() server_url = config.get('server_url') server_username = config.get('server_username') server_pw = config.get('server_pw') loop = asyncio.new_event_loop() # Initialisiere loop hier # Erstelle den Event-Loop für asynchronen Code def start_asyncio_loop(): global loop # Verweise auf die globale Variable loop asyncio.set_event_loop(loop) loop.run_forever() asyncio_thread = threading.Thread(target=start_asyncio_loop, daemon=True) asyncio_thread.start() async def on_folder_selected_coro(folder_path, gui): print("on_folder_selected gestartet") await get_patientfiles(folder_path, gui) upload_files = file_management.get_files_in_folder(TRANSFER_FOLDER) if upload_files == 'no_transfer_folder': results, folder_path = gui.ask_for_more("Bisher keine Bilder ausgewählt.\nAndere Orte durchsuchen?") if results is False: gui.on_app_close() else: if folder_path: await get_patientfiles(folder_path, gui) else: file_paths = upload_files print(file_paths) if not file_paths or len(file_paths) == 0: gui.start_animation("Keine Dateien zum Hochladen gefunden") print("Keine Dateien zum Hochladen gefunden") gui.on_app_close() return if not server_url: gui.start_animation("FEHLER: Server-URL nicht konfiguriert") print("FEHLER: Server-URL nicht konfiguriert") gui.on_app_close() return availability = await network_utils.check_server_availability(server_url) if availability: print("Server ist verfügbar. Dateien werden hochgeladen.") # Hier wird die Funktion upload_single_file asynchron aufgerufen # In dicom_processing.process_dicom_files gui.start_animation("Lade DICOM Dateien zum PACS Server hoch") print(f"Starte Upload von {len(file_paths)} Dateien...") uploaded_count, failed_count = await network_utils.upload_multiple_files(file_paths, server_url, server_username, server_pw, gui.upload_success, gui.upload_progress) gui.stop_animation() if failed_count == 0: gui.start_animation("Bilddaten Im PACS erfolgreich eingelesen!") await asyncio.sleep(3) else: gui.start_animation(f"Upload abgeschlossen: {uploaded_count}/{len(file_paths)} Dateien hochgeladen") await asyncio.sleep(5) # Mehr Zeit, damit Benutzer die Meldung lesen kann shutil.rmtree(TRANSFER_FOLDER) print(f"Transferordner {TRANSFER_FOLDER} wurde gelöscht.") gui.on_app_close() else: gui.start_animation("PACS SERVER NICHT ERREICHBAR") print("Server ist nicht verfügbar.") print("on_folder_selected abgeschlossen") # Debugging-Ausgabe async def get_patientfiles(folder_path, gui): print("Debugging-Ausgabe vor der Suche") # Debugging-Ausgabe gui.hint_label.pack_forget() while True: gui.disable_browse_button() gui.start_animation("Suche nach DICOM Dateien") # Starte die Suchanimation print(folder_path) files_found = file_management.find_dicom_files(folder_path) if files_found == 'non_found': gui.stop_animation() results, folder_path = gui.ask_for_more("In diesem Ordner wurde keine Bilddaten gefunden.\nAndere Orte durchsuchen?") if not results: # Wenn der Benutzer 'Nein' auswählt break else: dicom_files, total_files = files_found print(dicom_files) gui.stop_animation() # Erhalte Dateien und Anzahl print(f"Dicom-Dateien gefunden: {total_files}") gui.start_animation("Kopiere DICOM Dateien in den Transfer Ordner") await file_management.copy_dicom_files(dicom_files, folder_path, TRANSFER_FOLDER, gui.update_progress) gui.stop_animation() print(f"Dicom-Dateien wurden nach {TRANSFER_FOLDER} kopiert.") current_dat_folder = file_management.get_latest_dat_folder(TRANSFER_FOLDER) if not current_dat_folder: gui.stop_animation() gui.start_animation("FEHLER: Transferordner nicht gefunden") print("FEHLER: Transferordner nicht gefunden") break gui.start_animation("Patienten ID wird mit Tomedo ID aktualisiert") dicom_processing.update_patient_id_in_transfer_folder(current_dat_folder, patienten_id) print("ID wurde aktualisiert") gui.stop_animation() print("Erstelle Ausgabedatei") acq_date, modality = dicom_processing.extract_modality(current_dat_folder) if acq_date and modality: file_management.write_to_file(acq_date, modality, AUSGABE_DATEI) else: print("Warnung: Konnte Modality-Daten nicht extrahieren") # Verarbeite die kopierten DICOM-Dateien synchron await dicom_processing.process_dicom_files(current_dat_folder, gui, name, vorname, geburtsdatum, server_url, server_username, server_pw) gui.stop_animation() gui.enable_browse_button() file_management.eject_cd_if_volume_path(folder_path) results, new_folder_path = gui.ask_for_more("Sollen mehr Bilddaten für den Patienten eingelesen werden?") print(f"Dialogergebnis: {results}") if results and new_folder_path: # Wenn der Benutzer 'Ja' auswählt gui.reset_progress(total_files) folder_path = new_folder_path if not results: # Wenn der Benutzer 'Nein' auswählt break def main(): global config, name, vorname, geburtsdatum, patienten_id # Argumente prüfen if len(sys.argv) != 5: print("Bitte genau vier Argumente angeben: Name, Vorname, Geburtsdatum, Patienten_ID") sys.exit(1) # Argumente zuweisen _, name, vorname, geburtsdatum, patienten_id = sys.argv print(f"Name: {name}, Vorname: {vorname}, Geburtsdatum: {geburtsdatum}, Patienten_ID: {patienten_id}") config = load_config() # Stellen Sie sicher, dass config geladen wird, bevor GUI initiiert wird gui = GUI(None, TRANSFER_FOLDER, lambda: None, config) # Definiere den Callback nach der Erstellung der GUI-Instanz def on_folder_selected_callback(folder): # Plane die Coroutine im asyncio Event-Loop asyncio.run_coroutine_threadsafe(on_folder_selected_coro(folder, gui), loop) # Setze den Callback in der GUI-Instanz gui.on_folder_selected = on_folder_selected_callback # Funktion, die überprüft, ob eine CD eingelegt ist, und diese verarbeitet def check_cd_and_select(): cd_path = file_management.check_for_cd_at_start() if cd_path: print(f"CD gefunden: {cd_path}") gui.root.after(100, lambda: on_folder_selected_callback(cd_path)) else: print("Keine CD gefunden, bitte Ordner manuell auswählen.") # Stelle sicher, dass on_app_close als Methode der GUI-Klasse definiert ist gui.root.protocol("WM_DELETE_WINDOW", gui.on_app_close) # Überprüfe, ob eine CD eingelegt ist, bevor die GUI vollständig gestartet wird # Überprüfe die Einstellung und führe ggf. die CD-Überprüfung aus if config.get('check_for_cd', '0') == '1': check_cd_and_select() # Starte die GUI gui.start() if __name__ == "__main__": main()