# LauncherTool/gui/dialogs/parameter_dialogs.py """ Dialogs for adding and editing application parameters. """ import tkinter as tk from tkinter import ttk, messagebox import logging from typing import Optional, Dict, Any, Callable # Aggiunto Callable from ..utils_gui import GuiUtils logger = logging.getLogger(__name__) class BaseParameterDialog(tk.Toplevel): """ Base class for Add and Edit Parameter dialogs. """ def __init__(self, parent: tk.Widget, title: str, load_data_method: Optional[Callable[[], None]] = None): # Aggiunto load_data_method logger.debug(f"BaseParameterDialog __init__ - START - Title: '{title}'") super().__init__(parent) self.transient(parent) self.title(title) self.parent_widget = parent self.result: Optional[Dict[str, Any]] = None self._parameter_types = ["string", "integer", "boolean", "float", "file", "folder"] logger.debug("BaseParameterDialog: Calling _setup_widgets()") self._setup_widgets() logger.debug("BaseParameterDialog: _setup_widgets() completed.") # === MODIFICA CHIAVE === if load_data_method: logger.debug("BaseParameterDialog: Calling provided load_data_method.") load_data_method() logger.debug("BaseParameterDialog: load_data_method completed.") else: logger.debug("BaseParameterDialog: No load_data_method provided.") # ======================= GuiUtils.center_window(self, parent) self.protocol("WM_DELETE_WINDOW", self._on_cancel) self.grab_set() self.focus_set() logger.debug(f"BaseParameterDialog __init__ for '{title}': Now calling wait_window().") self.wait_window(self) logger.debug(f"BaseParameterDialog __init__ - END - Title: '{title}' (after wait_window)") def _setup_widgets(self): main_frame = ttk.Frame(self, padding="10") main_frame.pack(expand=True, fill=tk.BOTH) # --- Parameter Name --- name_frame = ttk.Frame(main_frame) name_frame.pack(fill=tk.X, pady=(0, 5)) ttk.Label(name_frame, text="Name:").grid(row=0, column=0, sticky=tk.W, padx=(0,5)) self.name_entry_var = tk.StringVar() self.name_entry = ttk.Entry(name_frame, textvariable=self.name_entry_var, width=40) self.name_entry.grid(row=0, column=1, sticky=tk.EW) name_frame.columnconfigure(1, weight=1) # --- Description --- desc_frame = ttk.Frame(main_frame) desc_frame.pack(fill=tk.X, pady=(0, 5)) ttk.Label(desc_frame, text="Description:").grid(row=0, column=0, sticky=tk.NW, padx=(0,5)) # Assicurati che self.description_text sia creato correttamente self.description_text = tk.Text(desc_frame, width=40, height=4, wrap=tk.WORD) self.description_text.grid(row=0, column=1, sticky=tk.EW) desc_scrollbar = ttk.Scrollbar(desc_frame, orient=tk.VERTICAL, command=self.description_text.yview) desc_scrollbar.grid(row=0, column=2, sticky=tk.NS) self.description_text.config(yscrollcommand=desc_scrollbar.set) desc_frame.columnconfigure(1, weight=1) # --- Default Value --- def_val_frame = ttk.Frame(main_frame) def_val_frame.pack(fill=tk.X, pady=(0, 5)) ttk.Label(def_val_frame, text="Default Value:").grid(row=0, column=0, sticky=tk.W, padx=(0,5)) self.default_value_entry_var = tk.StringVar() self.default_value_entry = ttk.Entry(def_val_frame, textvariable=self.default_value_entry_var, width=40) self.default_value_entry.grid(row=0, column=1, sticky=tk.EW) def_val_frame.columnconfigure(1, weight=1) # --- Parameter Type --- type_frame = ttk.Frame(main_frame) type_frame.pack(fill=tk.X, pady=(0, 10)) ttk.Label(type_frame, text="Type:").grid(row=0, column=0, sticky=tk.W, padx=(0,5)) self.type_combo_var = tk.StringVar() self.type_combo = ttk.Combobox( type_frame, textvariable=self.type_combo_var, values=self._parameter_types, state="readonly", width=38 ) self.type_combo.grid(row=0, column=1, sticky=tk.EW) self.type_combo.set("string") type_frame.columnconfigure(1, weight=1) # --- Dialog Buttons (Save, Cancel) --- dialog_buttons_frame = ttk.Frame(main_frame) dialog_buttons_frame.pack(fill=tk.X, pady=(10, 0)) ttk.Frame(dialog_buttons_frame).pack(side=tk.LEFT, expand=True) self.save_button = ttk.Button(dialog_buttons_frame, text="Save", command=self._on_save) self.save_button.pack(side=tk.LEFT, padx=(0,5)) self.cancel_button = ttk.Button(dialog_buttons_frame, text="Cancel", command=self._on_cancel) self.cancel_button.pack(side=tk.LEFT) def _validate_inputs(self) -> bool: name = self.name_entry_var.get().strip() if not name: messagebox.showerror("Validation Error", "Parameter Name cannot be empty.", parent=self) self.name_entry.focus_set() return False return True def _on_save(self): raise NotImplementedError("Subclasses must implement _on_save") def _on_cancel(self): logger.debug(f"BaseParameterDialog: '{self.title()}' cancelled or closed by user.") self.result = None self.destroy() class AddParameterDialog(BaseParameterDialog): """Dialog for adding a new application parameter.""" def __init__(self, parent: tk.Widget): # Non serve caricare dati super().__init__(parent, title="Add New Parameter", load_data_method=None) logger.debug("AddParameterDialog __init__ completed.") def _on_save(self): if not self._validate_inputs(): return param_name = self.name_entry_var.get().strip() param_description = self.description_text.get("1.0", tk.END).strip() param_default_value = self.default_value_entry_var.get() param_type = self.type_combo_var.get() self.result = { "name": param_name, "description": param_description, "default_value": param_default_value, "type": param_type } logger.info(f"AddParameterDialog: Parameter '{param_name}' data prepared.") self.destroy() class EditParameterDialog(BaseParameterDialog): """Dialog for editing an existing application parameter.""" def __init__(self, parent: tk.Widget, parameter_data_to_edit: Dict[str, Any]): logger.debug(f"EditParameterDialog __init__ - START - Parameter to edit: {parameter_data_to_edit.get('name', 'N/A')}") self.parameter_data_to_edit = parameter_data_to_edit # Imposta PRIMA di super() # Passa il metodo _load_initial_data a super() param_name_for_title = parameter_data_to_edit.get('name', 'Unknown') super().__init__(parent, title=f"Edit Parameter: {param_name_for_title}", load_data_method=self._load_initial_data) # Il codice qui viene eseguito solo dopo la chiusura del dialogo (wait_window) logger.debug(f"EditParameterDialog __init__ - END - for '{param_name_for_title}' (after super call completed)") def _load_initial_data(self): # Chiamato da BaseParameterDialog.__init__ if not self.parameter_data_to_edit: logger.error("EditParameterDialog _load_initial_data: parameter_data_to_edit is missing.") if self.parent_widget: messagebox.showerror("Initialization Error", "Cannot edit parameter: Initial data is missing.", parent=self.parent_widget) # Mostra su ApplicationDialog self.after_idle(self.destroy) return param_name = self.parameter_data_to_edit.get("name", "") logger.debug(f"EditParameterDialog _load_initial_data: Loading data for parameter '{param_name}'") try: self.name_entry_var.set(param_name) # Pulisci e inserisci nella Textbox self.description_text.delete("1.0", tk.END) # Tenta di pulire self.description_text.insert("1.0", self.parameter_data_to_edit.get("description", "")) # Tenta di inserire logger.debug(f"EditParameterDialog _load_initial_data: Description set in Text widget.") self.default_value_entry_var.set(self.parameter_data_to_edit.get("default_value", "")) param_type = self.parameter_data_to_edit.get("type", "string") if param_type in self._parameter_types: self.type_combo_var.set(param_type) else: logger.warning(f"EditParameterDialog: Unknown type '{param_type}' for param '{param_name}'. Defaulting to 'string'.") self.type_combo_var.set("string") logger.info(f"EditParameterDialog _load_initial_data: Data loaded successfully for '{param_name}'.") except tk.TclError as e: # Cattura specificamente l'errore TclError logger.error(f"EditParameterDialog _load_initial_data: TclError operating on widget (likely description_text): {e}", exc_info=True) if self.parent_widget: messagebox.showerror("Widget Error", f"Error loading data into the description field for '{param_name}'.\n" "The dialog might not have initialized correctly.", parent=self.parent_widget) self.after_idle(self.destroy) # Chiudi se il widget non รจ utilizzabile except Exception as e: # Cattura altri errori logger.error(f"EditParameterDialog _load_initial_data: Unexpected error loading data for '{param_name}': {e}", exc_info=True) if self.parent_widget: messagebox.showerror("Load Error", f"Could not load data for parameter '{param_name}':\n{e}", parent=self.parent_widget) self.after_idle(self.destroy) def _on_save(self): if not self.parameter_data_to_edit: # Sicurezza se _load fallisce messagebox.showerror("Save Error", "Cannot save: Initial parameter data was not loaded correctly.", parent=self) logger.error("EditParameterDialog _on_save: Attempted to save without valid initial data.") return if not self._validate_inputs(): return new_param_name = self.name_entry_var.get().strip() new_param_description = self.description_text.get("1.0", tk.END).strip() new_param_default_value = self.default_value_entry_var.get() new_param_type = self.type_combo_var.get() self.result = { "name": new_param_name, "description": new_param_description, "default_value": new_param_default_value, "type": new_param_type } original_param_name = self.parameter_data_to_edit.get('name', 'N/A') logger.info(f"EditParameterDialog: Parameter data for '{new_param_name}' (original: '{original_param_name}') prepared.") self.destroy()