"""Editor for ordered, copy-level LaTeX remarks.""" import tkinter as tk from tkinter import messagebox, ttk from copienator.general_remarks import remarks_for_copy, set_remarks from .scores import score_path_for_id class GeneralRemarksPanel(ttk.Frame): def __init__(self, parent, evaluation, on_change): super().__init__(parent) self.evaluation, self.on_change = evaluation, on_change self.busy = False self.valid = False self.remarks = [] self.id_var = tk.StringVar() self.status_var = tk.StringVar() self.columnconfigure(1, weight=1) ttk.Label(self, text="Id de copie").grid(row=0, column=0, sticky="w") self.id_entry = ttk.Entry(self, textvariable=self.id_var) self.id_entry.grid(row=0, column=1, sticky="ew") self.listbox = tk.Listbox(self, height=4, exportselection=False) self.listbox.grid(row=1, column=0, columnspan=2, sticky="ew", pady=6) self.listbox.bind("<>", self.select) self.editor = tk.Text(self, height=5, width=50, wrap="word", undo=True) self.editor.grid(row=2, column=0, columnspan=2, sticky="ew") actions = ttk.Frame(self) actions.grid(row=3, column=0, columnspan=2, sticky="w", pady=6) self.buttons = [] for text, command in ( ("Nouvelle", self.new), ("Enregistrer", self.save), ("Supprimer", self.delete), ("Monter", lambda: self.move(-1)), ("Descendre", lambda: self.move(1)), ): button = ttk.Button(actions, text=text, command=command) button.pack(side="left", padx=(0, 5)) self.buttons.append(button) ttk.Label(self, text="Texte LaTeX ; chaque remarque forme un paragraphe.").grid( row=4, column=0, columnspan=2, sticky="w") ttk.Label(self, textvariable=self.status_var, wraplength=650).grid( row=5, column=0, columnspan=2, sticky="w", pady=6) self.id_var.trace_add("write", self.load) self.load() def load(self, *_): self.valid = False self.remarks = [] try: path = score_path_for_id(self.evaluation, self.id_var.get()) self.remarks = remarks_for_copy(self.evaluation, self.id_var.get()) self.valid = True self.status_var.set(path.parent.name) except (OSError, ValueError) as exc: self.status_var.set(str(exc)) self.refresh() self.set_busy(self.busy) def refresh(self, index=None): self.listbox.configure(state="normal") self.listbox.delete(0, "end") for i, text in enumerate(self.remarks, 1): self.listbox.insert("end", f"{i}. {' '.join(text.split())}") self.editor.configure(state="normal") self.editor.delete("1.0", "end") if index is not None: self.listbox.selection_set(index) self.listbox.see(index) self.editor.insert("1.0", self.remarks[index]) self.editor.edit_reset() def select(self, *_): if self.busy: return selected = self.listbox.curselection() if selected: self.editor.delete("1.0", "end") self.editor.insert("1.0", self.remarks[selected[0]]) self.editor.edit_reset() def new(self): if self.valid and not self.busy: self.refresh() self.editor.focus_set() def commit(self, remarks, index=None): try: previous = set_remarks(self.evaluation, self.id_var.get(), remarks) self.remarks = remarks self.refresh(index) if previous != remarks: self.on_change(self.id_var.get(), previous, remarks) self.status_var.set("Remarques enregistrées — lecture des annotations à revalider, « Régénérer » coché.") except (OSError, ValueError) as exc: messagebox.showerror("Remarques générales", str(exc)) def save(self): if not self.valid or self.busy: return text = self.editor.get("1.0", "end-1c").strip() if not text: self.status_var.set("Saisissez une remarque ou utilisez « Supprimer ».") return remarks = self.remarks.copy() selected = self.listbox.curselection() index = selected[0] if selected else len(remarks) if selected: remarks[index] = text else: remarks.append(text) self.commit(remarks, index) def delete(self): selected = self.listbox.curselection() if self.valid and not self.busy and selected: remarks = self.remarks.copy() remarks.pop(selected[0]) self.commit(remarks) def move(self, offset): selected = self.listbox.curselection() if not self.valid or self.busy or not selected: return index = selected[0] target = index + offset if 0 <= target < len(self.remarks): remarks = self.remarks.copy() remarks[index], remarks[target] = remarks[target], remarks[index] self.commit(remarks, target) def set_busy(self, busy): self.busy = busy self.id_entry.configure(state="disabled" if busy else "normal") state = "normal" if self.valid and not busy else "disabled" self.listbox.configure(state=state) self.editor.configure(state=state) for button in self.buttons: button.configure(state=state)