Files
IPSExtractor/gui/tabs/postprocess_tab.py
T

228 lines
8.1 KiB
Python

"""Pestaña de Post-Procesamiento con agente inteligente."""
import customtkinter as ctk
from gui.styles import AppStyles
class PostProcessTab:
"""UI de la pestaña de Post-Procesamiento de CSV."""
def __init__(self, parent_tab):
self.tab = parent_tab
self.fonts = AppStyles.get_fonts()
self.colors = AppStyles.get_colors()
self.spacing = AppStyles.get_spacing()
self._setup_layout()
self._create_file_section()
self._create_preview_section()
self._create_instructions_section()
self._create_code_section()
self._create_log_section()
self._create_result_section()
# -- Layout ------------------------------------------------------------------
def _setup_layout(self):
self.tab.grid_columnconfigure(0, weight=1)
self.tab.grid_rowconfigure(0, weight=1)
self.scroll = ctk.CTkScrollableFrame(self.tab, fg_color="transparent")
self.scroll.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
self.scroll.grid_columnconfigure(0, weight=1)
# -- Sección archivo ---------------------------------------------------------
def _create_file_section(self):
frame = ctk.CTkFrame(self.scroll)
frame.grid(row=0, column=0, sticky="ew", padx=5, pady=(5, 2))
frame.grid_columnconfigure(1, weight=1)
lbl_title = ctk.CTkLabel(frame, text="Archivo CSV", font=self.fonts["section"])
lbl_title.grid(row=0, column=0, columnspan=3, sticky="w", padx=15, pady=(10, 5))
self.btn_select_csv = ctk.CTkButton(
frame, text="Seleccionar CSV", font=self.fonts["ui"], width=160,
)
self.btn_select_csv.grid(row=1, column=0, padx=15, pady=8, sticky="w")
self.lbl_csv_path = ctk.CTkLabel(
frame, text="Ningún archivo seleccionado",
font=self.fonts["italic_small"], text_color=self.colors["gray_light"],
)
self.lbl_csv_path.grid(row=1, column=1, padx=10, pady=8, sticky="w")
# -- Preview datos -----------------------------------------------------------
def _create_preview_section(self):
frame = ctk.CTkFrame(self.scroll)
frame.grid(row=1, column=0, sticky="ew", padx=5, pady=2)
frame.grid_columnconfigure(0, weight=1)
lbl = ctk.CTkLabel(frame, text="Vista previa (muestra)", font=self.fonts["section"])
lbl.grid(row=0, column=0, sticky="w", padx=15, pady=(10, 5))
self.txt_preview = ctk.CTkTextbox(
frame, height=200, font=self.fonts["mono_small"],
state="disabled", wrap="none",
)
self.txt_preview.grid(row=1, column=0, sticky="ew", padx=15, pady=(0, 10))
# -- Instrucciones -----------------------------------------------------------
def _create_instructions_section(self):
frame = ctk.CTkFrame(self.scroll)
frame.grid(row=2, column=0, sticky="ew", padx=5, pady=2)
frame.grid_columnconfigure(0, weight=1)
lbl = ctk.CTkLabel(
frame, text="Instrucciones de transformación", font=self.fonts["section"],
)
lbl.grid(row=0, column=0, sticky="w", padx=15, pady=(10, 2))
hint = ctk.CTkLabel(
frame,
text="Describe qué cambios quieres aplicar y en qué columnas. Ejemplo: "
"\"En la columna 'monto', multiplicar por 1.19 para agregar IVA\"",
font=self.fonts["italic_small"], text_color=self.colors["gray_light"],
wraplength=900, justify="left",
)
hint.grid(row=1, column=0, sticky="w", padx=15, pady=(0, 5))
self.txt_instructions = ctk.CTkTextbox(
frame, height=90, font=self.fonts["ui"], wrap="word",
)
self.txt_instructions.grid(row=2, column=0, sticky="ew", padx=15, pady=(0, 5))
btn_frame = ctk.CTkFrame(frame, fg_color="transparent")
btn_frame.grid(row=3, column=0, sticky="ew", padx=15, pady=(0, 10))
self.btn_run = ctk.CTkButton(
btn_frame, text="Generar y Aplicar", font=self.fonts["button_large"],
fg_color=self.colors["primary_button"], hover_color=self.colors["primary_hover"],
height=38,
)
self.btn_run.pack(side="left")
self.lbl_status = ctk.CTkLabel(
btn_frame, text="", font=self.fonts["italic_small"],
text_color=self.colors["gray_light"],
)
self.lbl_status.pack(side="left", padx=15)
# -- Código generado ---------------------------------------------------------
def _create_code_section(self):
frame = ctk.CTkFrame(self.scroll)
frame.grid(row=3, column=0, sticky="ew", padx=5, pady=2)
frame.grid_columnconfigure(0, weight=1)
lbl = ctk.CTkLabel(frame, text="Código generado", font=self.fonts["section"])
lbl.grid(row=0, column=0, sticky="w", padx=15, pady=(10, 5))
self.txt_code = ctk.CTkTextbox(
frame, height=180, font=self.fonts["mono_small"],
state="disabled", wrap="none",
)
self.txt_code.grid(row=1, column=0, sticky="ew", padx=15, pady=(0, 10))
# -- Log de ejecución --------------------------------------------------------
def _create_log_section(self):
frame = ctk.CTkFrame(self.scroll)
frame.grid(row=4, column=0, sticky="ew", padx=5, pady=2)
frame.grid_columnconfigure(0, weight=1)
lbl = ctk.CTkLabel(frame, text="Log de ejecución", font=self.fonts["section"])
lbl.grid(row=0, column=0, sticky="w", padx=15, pady=(10, 5))
self.txt_log = ctk.CTkTextbox(
frame, height=100, font=self.fonts["mono_small"],
state="disabled", wrap="word",
)
self.txt_log.grid(row=1, column=0, sticky="ew", padx=15, pady=(0, 10))
# -- Resultado ---------------------------------------------------------------
def _create_result_section(self):
frame = ctk.CTkFrame(self.scroll)
frame.grid(row=5, column=0, sticky="ew", padx=5, pady=(2, 5))
frame.grid_columnconfigure(0, weight=1)
top = ctk.CTkFrame(frame, fg_color="transparent")
top.grid(row=0, column=0, sticky="ew", padx=15, pady=(10, 5))
top.grid_columnconfigure(0, weight=1)
lbl = ctk.CTkLabel(top, text="Vista previa del resultado", font=self.fonts["section"])
lbl.pack(side="left")
self.btn_save = ctk.CTkButton(
top, text="Guardar CSV", font=self.fonts["ui"], width=140,
fg_color=self.colors["success"], hover_color=self.colors["success_hover"],
state="disabled",
)
self.btn_save.pack(side="right")
self.txt_result = ctk.CTkTextbox(
frame, height=200, font=self.fonts["mono_small"],
state="disabled", wrap="none",
)
self.txt_result.grid(row=1, column=0, sticky="ew", padx=15, pady=(0, 10))
# -- API pública -------------------------------------------------------------
def set_on_select_csv(self, callback):
self.btn_select_csv.configure(command=callback)
def set_on_run(self, callback):
self.btn_run.configure(command=callback)
def set_on_save(self, callback):
self.btn_save.configure(command=callback)
def set_csv_path(self, path: str):
self.lbl_csv_path.configure(text=path or "Ningún archivo seleccionado")
def get_instructions(self) -> str:
return self.txt_instructions.get("1.0", "end").strip()
def set_status(self, text: str):
self.lbl_status.configure(text=text)
def set_preview(self, text: str):
self.txt_preview.configure(state="normal")
self.txt_preview.delete("1.0", "end")
self.txt_preview.insert("1.0", text)
self.txt_preview.configure(state="disabled")
def set_code(self, text: str):
self.txt_code.configure(state="normal")
self.txt_code.delete("1.0", "end")
self.txt_code.insert("1.0", text)
self.txt_code.configure(state="disabled")
def append_log(self, text: str):
self.txt_log.configure(state="normal")
self.txt_log.insert("end", text + "\n")
self.txt_log.see("end")
self.txt_log.configure(state="disabled")
def clear_log(self):
self.txt_log.configure(state="normal")
self.txt_log.delete("1.0", "end")
self.txt_log.configure(state="disabled")
def set_result(self, text: str):
self.txt_result.configure(state="normal")
self.txt_result.delete("1.0", "end")
self.txt_result.insert("1.0", text)
self.txt_result.configure(state="disabled")
def enable_save(self, enabled: bool):
self.btn_save.configure(state="normal" if enabled else "disabled")
def enable_controls(self, enabled: bool):
state = "normal" if enabled else "disabled"
self.btn_select_csv.configure(state=state)
self.btn_run.configure(state=state)
self.txt_instructions.configure(state=state)