# 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()