# profileAnalyzer/gui/launch_manager_window.py """ GUI Window for managing and executing launch profiles. """ import tkinter as tk from tkinter import ttk, filedialog, messagebox import os from typing import Optional from ..core.core import LaunchProfile from ..core.profile_manager import LaunchProfileManager class LaunchManagerWindow(tk.Toplevel): """A Toplevel window for managing and running profiling launch profiles.""" def __init__(self, master, profile_manager: LaunchProfileManager): super().__init__(master) self.profile_manager = profile_manager self.selected_profile_to_run: Optional[LaunchProfile] = None self._init_window() self._init_vars() self._create_widgets() self._populate_profile_list() self.protocol("WM_DELETE_WINDOW", self._on_close) self._toggle_view() # Set initial view state def _init_window(self): self.title("Launch Profile Manager") self.geometry("900x400") self.transient(self.master) self.grab_set() def _init_vars(self): self.profile_name_var = tk.StringVar() self.target_path_var = tk.StringVar() self.module_name_var = tk.StringVar() self.script_args_var = tk.StringVar() self.run_as_module_var = tk.BooleanVar() self.selected_listbox_item = None self.run_as_module_var.trace_add("write", self._toggle_view) def _create_widgets(self): main_frame = ttk.Frame(self, padding="10") main_frame.pack(fill=tk.BOTH, expand=True) main_frame.rowconfigure(0, weight=1) main_frame.columnconfigure(1, weight=3) # Detail frame expands more # --- Left and Middle Frames --- list_action_frame = ttk.Frame(main_frame) list_action_frame.grid(row=0, column=0, sticky="ns", padx=(0, 10)) list_action_frame.rowconfigure(0, weight=1) list_frame = ttk.LabelFrame(list_action_frame, text="Profiles") list_frame.pack(fill=tk.BOTH, expand=True) list_frame.rowconfigure(0, weight=1) list_frame.columnconfigure(0, weight=1) self.profile_listbox = tk.Listbox(list_frame, exportselection=False) self.profile_listbox.grid(row=0, column=0, sticky="nsew") self.profile_listbox.bind("<>", self._on_profile_select) list_scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.profile_listbox.yview) list_scrollbar.grid(row=0, column=1, sticky="ns") self.profile_listbox.config(yscrollcommand=list_scrollbar.set) action_btn_frame = ttk.Frame(list_action_frame) action_btn_frame.pack(fill=tk.X, pady=5) ttk.Button(action_btn_frame, text="New", command=self._on_new).pack(side=tk.LEFT, expand=True, fill=tk.X) ttk.Button(action_btn_frame, text="Delete", command=self._on_delete).pack(side=tk.LEFT, expand=True, fill=tk.X) # --- Right Frame: Profile Details --- self.detail_frame = ttk.LabelFrame(main_frame, text="Profile Details") self.detail_frame.grid(row=0, column=1, sticky="nsew") self.detail_frame.columnconfigure(1, weight=1) # --- Common Details (Name, Module Checkbox) --- name_frame = ttk.Frame(self.detail_frame) name_frame.grid(row=0, column=0, columnspan=2, sticky="ew", padx=5, pady=5) name_frame.columnconfigure(0, weight=1) ttk.Label(name_frame, text="Profile Name:").pack(side=tk.LEFT) ttk.Entry(name_frame, textvariable=self.profile_name_var).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) ttk.Checkbutton(name_frame, text="Run as Module", variable=self.run_as_module_var).pack(side=tk.LEFT, padx=5) # --- Dynamic View Frames --- self.script_frame = ttk.Frame(self.detail_frame) self.script_frame.grid(row=1, column=0, columnspan=2, sticky="ew") self.script_frame.columnconfigure(1, weight=1) self.module_frame = ttk.Frame(self.detail_frame) self.module_frame.grid(row=1, column=0, columnspan=2, sticky="ew") self.module_frame.columnconfigure(1, weight=1) # --- Widgets for Script Mode --- ttk.Label(self.script_frame, text="Script Path:").grid(row=0, column=0, sticky="w", padx=5, pady=5) ttk.Entry(self.script_frame, textvariable=self.target_path_var).grid(row=0, column=1, sticky="ew", padx=5) ttk.Button(self.script_frame, text="...", width=3, command=self._browse_script).grid(row=0, column=2, padx=5) # --- Widgets for Module Mode --- ttk.Label(self.module_frame, text="Project Root Folder:").grid(row=0, column=0, sticky="w", padx=5, pady=5) ttk.Entry(self.module_frame, textvariable=self.target_path_var).grid(row=0, column=1, sticky="ew", padx=5) ttk.Button(self.module_frame, text="...", width=3, command=self._browse_folder).grid(row=0, column=2, padx=5) ttk.Label(self.module_frame, text="Module Name:").grid(row=1, column=0, sticky="w", padx=5, pady=5) ttk.Entry(self.module_frame, textvariable=self.module_name_var).grid(row=1, column=1, sticky="ew", padx=5) # --- Common Arguments and Save Button --- args_frame = ttk.Frame(self.detail_frame) args_frame.grid(row=2, column=0, columnspan=2, sticky="ew", padx=5, pady=5) args_frame.columnconfigure(1, weight=1) ttk.Label(args_frame, text="Arguments:").grid(row=0, column=0, sticky="w") ttk.Entry(args_frame, textvariable=self.script_args_var).grid(row=0, column=1, sticky="ew", padx=5) ttk.Button(self.detail_frame, text="Save Changes", command=self._on_save).grid(row=3, column=1, sticky="e", padx=5, pady=10) bottom_frame = ttk.Frame(main_frame) bottom_frame.grid(row=1, column=0, columnspan=2, sticky="ew", pady=(10, 0)) self.run_button = ttk.Button(bottom_frame, text="Run & Profile Selected", command=self._on_run_profile, state=tk.DISABLED) self.run_button.pack(side=tk.RIGHT) def _toggle_view(self, *args): if self.run_as_module_var.get(): self.script_frame.grid_remove() self.module_frame.grid() else: self.module_frame.grid_remove() self.script_frame.grid() def _populate_profile_list(self): self.profile_listbox.delete(0, tk.END) for profile in self.profile_manager.get_profiles(): self.profile_listbox.insert(tk.END, profile.name) def _on_profile_select(self, event=None): selection_indices = self.profile_listbox.curselection() if not selection_indices: self.selected_listbox_item = None self.run_button.config(state=tk.DISABLED) return self.selected_listbox_item = self.profile_listbox.get(selection_indices[0]) profile = self.profile_manager.get_profile_by_name(self.selected_listbox_item) if profile: self.profile_name_var.set(profile.name) self.target_path_var.set(profile.target_path) self.module_name_var.set(profile.module_name) self.script_args_var.set(profile.script_args) self.run_as_module_var.set(profile.run_as_module) self.run_button.config(state=tk.NORMAL) def _on_new(self): self.profile_listbox.selection_clear(0, tk.END) self.selected_listbox_item = None self.profile_name_var.set("New Profile") self.target_path_var.set("") self.module_name_var.set("") self.script_args_var.set("") self.run_as_module_var.set(False) self.run_button.config(state=tk.DISABLED) def _on_save(self): new_name = self.profile_name_var.get().strip() if not new_name: messagebox.showerror("Error", "Profile Name cannot be empty.", parent=self) return new_profile = LaunchProfile( name=new_name, run_as_module=self.run_as_module_var.get(), target_path=self.target_path_var.get().strip(), module_name=self.module_name_var.get().strip(), script_args=self.script_args_var.get().strip() ) if self.selected_listbox_item and self.selected_listbox_item != new_name: if not self.profile_manager.update_profile(self.selected_listbox_item, new_profile): messagebox.showerror("Error", f"Could not rename profile. A profile with the name '{new_name}' might already exist.", parent=self) else: self.selected_listbox_item = new_name elif self.selected_listbox_item: self.profile_manager.update_profile(self.selected_listbox_item, new_profile) else: if not self.profile_manager.add_profile(new_profile): messagebox.showerror("Error", f"A profile with the name '{new_name}' already exists.", parent=self) self._populate_profile_list() def _on_delete(self): if not self.selected_listbox_item: return if messagebox.askyesno("Confirm Delete", f"Delete '{self.selected_listbox_item}'?", parent=self): self.profile_manager.delete_profile(self.selected_listbox_item) self._populate_profile_list() self._on_new() def _browse_script(self): filepath = filedialog.askopenfilename(title="Select Python Script", filetypes=[("Python files", "*.py"), ("All files", "*.*")]) if filepath: self.target_path_var.set(filepath) def _browse_folder(self): folder_path = filedialog.askdirectory(title="Select Project Root Folder") if folder_path: self.target_path_var.set(folder_path) def _on_run_profile(self): if not self.selected_listbox_item: return self.selected_profile_to_run = self.profile_manager.get_profile_by_name(self.selected_listbox_item) self.destroy() def _on_close(self): self.selected_profile_to_run = None self.destroy()