# target_simulator/gui/connection_settings_window.py """ Toplevel window for configuring Target and LRU connections. """ import tkinter as tk from tkinter import ttk, messagebox class ConnectionSettingsWindow(tk.Toplevel): """A dialog for configuring connection settings.""" def __init__(self, master, config_manager, connection_config): super().__init__(master) self.master_view = master self.config_manager = config_manager self.connection_config = connection_config self.title("Connection Settings") self.transient(master) self.grab_set() self.resizable(False, False) self._create_widgets() self._load_settings() self.protocol("WM_DELETE_WINDOW", self._on_cancel) # Center the window on the main view self.update_idletasks() main_x = master.winfo_rootx() main_y = master.winfo_rooty() main_w = master.winfo_width() main_h = master.winfo_height() win_w = self.winfo_width() win_h = self.winfo_height() x = main_x + (main_w // 2) - (win_w // 2) y = main_y + (main_h // 2) - (win_h // 2) self.geometry(f"{win_w}x{win_h}+{x}+{y}") def _load_settings(self): # --- Load Target Settings --- target_cfg = self.connection_config.get("target", {}) self.target_vars["conn_type"].set( "Serial" if target_cfg.get("type", "TFTP").lower() == "serial" else "TFTP" ) self.target_vars["tftp_ip"].set( target_cfg.get("tftp", {}).get("ip", "127.0.0.1") ) self.target_vars["tftp_port"].set(target_cfg.get("tftp", {}).get("port", 69)) self.target_vars["serial_port"].set( target_cfg.get("serial", {}).get("port", "COM1") ) self.target_vars["serial_baud"].set( target_cfg.get("serial", {}).get("baudrate", 9600) ) self._switch_view(self.target_vars) # --- Load LRU Settings --- lru_cfg = self.connection_config.get("lru", {}) self.lru_vars["conn_type"].set( "Serial" if lru_cfg.get("type", "TFTP").lower() == "serial" else "TFTP" ) self.lru_vars["tftp_ip"].set(lru_cfg.get("tftp", {}).get("ip", "127.0.0.1")) self.lru_vars["tftp_port"].set(lru_cfg.get("tftp", {}).get("port", 69)) self.lru_vars["serial_port"].set(lru_cfg.get("serial", {}).get("port", "COM1")) self.lru_vars["serial_baud"].set( lru_cfg.get("serial", {}).get("baudrate", 9600) ) self._switch_view(self.lru_vars) def _create_widgets(self): main_frame = ttk.Frame(self, padding="10") main_frame.pack(fill=tk.BOTH, expand=True) # --- Target Connection Frame --- target_frame = ttk.LabelFrame(main_frame, text="Target Connection") target_frame.pack(fill=tk.X, expand=True, pady=5, padx=5) self.target_vars = self._create_connection_panel(target_frame, "Target") # --- LRU Connection Frame --- lru_frame = ttk.LabelFrame(main_frame, text="LRU Connection") lru_frame.pack(fill=tk.X, expand=True, pady=5, padx=5) self.lru_vars = self._create_connection_panel(lru_frame, "LRU") # --- Buttons --- button_frame = ttk.Frame(main_frame) button_frame.pack(pady=10, fill=tk.X, side=tk.BOTTOM) ttk.Button(button_frame, text="Save", command=self._on_save).pack( side=tk.RIGHT, padx=5 ) ttk.Button(button_frame, text="Cancel", command=self._on_cancel).pack( side=tk.RIGHT, padx=5 ) def _create_connection_panel(self, parent_frame, name): vars = {} # --- Connection Type Selection --- conn_type_frame = ttk.Frame(parent_frame) conn_type_frame.pack(fill=tk.X, padx=5, pady=(5, 10)) vars["conn_type"] = tk.StringVar() ttk.Label(conn_type_frame, text="Type:").pack(side=tk.LEFT) ttk.Radiobutton( conn_type_frame, text="TFTP", variable=vars["conn_type"], value="TFTP", command=lambda: self._switch_view(vars), ).pack(side=tk.LEFT, padx=5) ttk.Radiobutton( conn_type_frame, text="Serial", variable=vars["conn_type"], value="Serial", command=lambda: self._switch_view(vars), ).pack(side=tk.LEFT, padx=5) # --- Configuration Frames (TFTP and Serial) --- vars["tftp_frame"] = ttk.Frame(parent_frame, padding=5) vars["serial_frame"] = ttk.Frame(parent_frame, padding=5) # --- TFTP Widgets --- tftp_grid = vars["tftp_frame"] ttk.Label(tftp_grid, text="IP Address:").grid( row=0, column=0, sticky=tk.W, pady=2 ) vars["tftp_ip"] = tk.StringVar() ttk.Entry(tftp_grid, textvariable=vars["tftp_ip"]).grid( row=0, column=1, sticky=tk.EW, padx=5 ) ttk.Label(tftp_grid, text="Port:").grid(row=1, column=0, sticky=tk.W, pady=2) vars["tftp_port"] = tk.IntVar() ttk.Spinbox( tftp_grid, from_=1, to=65535, textvariable=vars["tftp_port"], width=7 ).grid(row=1, column=1, sticky=tk.W, padx=5) tftp_grid.columnconfigure(1, weight=1) # --- Serial Widgets --- serial_grid = vars["serial_frame"] ttk.Label(serial_grid, text="COM Port:").grid( row=0, column=0, sticky=tk.W, pady=2 ) vars["serial_port"] = tk.StringVar() # In a real app, you might want to auto-detect available ports ttk.Combobox( serial_grid, textvariable=vars["serial_port"], values=[f"COM{i}" for i in range(1, 17)], ).grid(row=0, column=1, sticky=tk.EW, padx=5) ttk.Label(serial_grid, text="Baud Rate:").grid( row=1, column=0, sticky=tk.W, pady=2 ) vars["serial_baud"] = tk.IntVar() baud_rates = [9600, 19200, 38400, 57600, 115200] ttk.Combobox( serial_grid, textvariable=vars["serial_baud"], values=baud_rates, width=7 ).grid(row=1, column=1, sticky=tk.W, padx=5) serial_grid.columnconfigure(1, weight=1) # --- Test Button --- test_button = ttk.Button( parent_frame, text="Test Connection", command=lambda: self._test_connection(name, vars), ) test_button.pack(pady=5, padx=5, anchor=tk.E) # Initial view setup is now done in _load_settings # self._switch_view(vars) return vars def _switch_view(self, vars): conn_type = vars["conn_type"].get() if conn_type == "TFTP": vars["serial_frame"].pack_forget() vars["tftp_frame"].pack(fill=tk.X, expand=True, padx=5, pady=5) else: # Serial vars["tftp_frame"].pack_forget() vars["serial_frame"].pack(fill=tk.X, expand=True, padx=5, pady=5) def _test_connection(self, name, vars): conn_type = vars["conn_type"].get() result = False error = None if conn_type == "TFTP": ip = vars["tftp_ip"].get() port = vars["tftp_port"].get() try: port = int(port) from core.tftp_communicator import TFTPCommunicator comm = TFTPCommunicator() result = comm.connect({"ip": ip, "port": port}) except Exception as e: error = str(e) else: # Serial serial_port = vars["serial_port"].get() baudrate = vars["serial_baud"].get() try: baudrate = int(baudrate) from core.serial_communicator import SerialCommunicator comm = SerialCommunicator() result = comm.connect({"port": serial_port, "baudrate": baudrate}) except Exception as e: error = str(e) if result: messagebox.showinfo( "Connection Test", f"{name} connection successful!", parent=self ) else: msg = f"{name} connection failed." if error: msg += f"\nError: {error}" messagebox.showerror("Connection Test", msg, parent=self) def _on_save(self): # Save Target and LRU connection configs in a consistent structure new_config = { "target": { "type": self.target_vars["conn_type"].get().lower(), "tftp": { "ip": self.target_vars["tftp_ip"].get(), "port": self.target_vars["tftp_port"].get(), }, "serial": { "port": self.target_vars["serial_port"].get(), "baudrate": self.target_vars["serial_baud"].get(), }, }, "lru": { "type": self.lru_vars["conn_type"].get().lower(), "tftp": { "ip": self.lru_vars["tftp_ip"].get(), "port": self.lru_vars["tftp_port"].get(), }, "serial": { "port": self.lru_vars["serial_port"].get(), "baudrate": self.lru_vars["serial_baud"].get(), }, }, } self.master_view.update_connection_settings(new_config) print("Settings saved and applied.") self.destroy() def _on_cancel(self): self.destroy() if __name__ == "__main__": # Example usage for testing root = tk.Tk() root.withdraw() # Hide the root window app = ConnectionSettingsWindow(root) root.wait_window(app) root.destroy()