miscs (Interro02) : horizontal cutting resolution

This commit is contained in:
2026-09-14 22:20:46 +02:00
parent 5080274e8f
commit 0a86403ca6
28 changed files with 1447 additions and 59 deletions
+84 -2
View File
@@ -21,6 +21,9 @@ from copienator.platform import (
)
from .diagnostics import collect_diagnostics
from .batch_monitor import BatchMonitor
from .notifications import notify_desktop
from .manual_resolution import ManualResolutionPanel
from .refaire import SECTION as REFAIRE_SECTION
from .refaire import (
RefaireSelection,
@@ -274,6 +277,10 @@ class CopienatorApp(tk.Tk):
self.extra_var = tk.StringVar()
self.command_var = tk.StringVar(value="Sélectionnez une étape.")
self.info_var = tk.StringVar(value="Choisissez un dossier d’évaluation.")
self.batch_watch_status = tk.StringVar(value="Vérification automatique arrêtée.")
self.batch_monitor = BatchMonitor(
self, self._batch_results_ready, self._batch_watch_status_changed, self._append_console
)
self._build_ui(show_personal_steps)
self.extra_var.trace_add("write", lambda *_args: self._update_command_preview())
@@ -543,6 +550,7 @@ class CopienatorApp(tk.Tk):
if not evaluation or not evaluation.is_dir():
messagebox.showerror("Dossier invalide", "Choisissez un dossier d’évaluation existant.")
return
self.batch_monitor.stop()
self._save_current_form()
self.state_store.load(evaluation)
for step in self.steps:
@@ -744,7 +752,7 @@ class CopienatorApp(tk.Tk):
return
self._rendering = True
redo = step.section == REFAIRE_SECTION
expanded_form = redo or step.id in {"page_splitter", "crop_blank_margins", "cutleft", "labels"}
expanded_form = redo or step.id in {"page_splitter", "crop_blank_margins", "cutleft", "labels", "manual_resolution"}
self.console.configure(height=8 if expanded_form else 14)
self.rowconfigure(1, weight=4 if expanded_form else 3)
self.rowconfigure(2, weight=1 if expanded_form else 2)
@@ -830,6 +838,18 @@ class CopienatorApp(tk.Tk):
attach_tooltip(widget, spec.help)
row += 1
if step.id == "manual_resolution":
def manual_evaluation():
target = self.arg_vars.get("target")
value = target.get().strip() if target else ""
return (self.repository / value).resolve() if value else self.evaluation
self.manual_panel = ManualResolutionPanel(self.form, manual_evaluation)
self.manual_panel.grid(row=row, column=0, columnspan=2, sticky="nsew", pady=8)
if "target" in self.arg_vars:
self.arg_vars["target"].trace_add("write", lambda *_args: self.manual_panel.reload())
row += 1
show_extra = bool(step.extra_arguments_help) and (
not step.extra_arguments_variants
or variant.id in step.extra_arguments_variants
@@ -852,6 +872,23 @@ class CopienatorApp(tk.Tk):
self._update_controls()
def _render_context_controls(self, step: StepDefinition, row: int) -> int:
if step.id == "batch_status":
controls = ttk.Frame(self.form)
controls.grid(row=row, column=0, columnspan=2, sticky="w", pady=8)
self.watch_batches_button = ttk.Button(
controls, text="Vérifier toutes les 5 minutes", command=self._start_batch_watch
)
self.watch_batches_button.pack(side="left")
self.stop_watch_batches_button = ttk.Button(
controls, text="Arrêter les vérifications", command=self.batch_monitor.stop
)
self.stop_watch_batches_button.pack(side="left", padx=8)
ttk.Label(self.form, textvariable=self.batch_watch_status).grid(
row=row + 1, column=0, columnspan=2, sticky="w"
)
ttk.Label(self.form, text="Gardez Copienator ouvert. Une notification de bureau sera envoyée lorsque tous les résultats seront prêts.",
wraplength=650).grid(row=row + 2, column=0, columnspan=2, sticky="w", pady=8)
return row + 3
if step.id == "rename":
self.validate_rename_button = ttk.Button(
self.form, text="Valider sans renommer", command=self._validate_rename_step
@@ -1299,6 +1336,8 @@ class CopienatorApp(tk.Tk):
if not step or not evaluation or not self.state_store.evaluation:
messagebox.showerror("Évaluation absente", "Chargez dabord un dossier d’évaluation.")
return
if step.id == "batch_status" and self.batch_monitor.active:
return
if self.active_step_id or self.runner.running:
messagebox.showwarning("Traitement en cours", "Interrompez le traitement actuel avant den lancer un autre.")
return
@@ -1448,6 +1487,39 @@ class CopienatorApp(tk.Tk):
self._finish_process(int(return_code), bool(interrupted))
self.after(60, self._poll_runner)
def _batch_watch_status_changed(self, message: str) -> None:
self.batch_watch_status.set(message)
self._update_controls()
def _start_batch_watch(self) -> None:
if self.active_step_id or self.runner.running or not self.state_store.evaluation:
return
step = self.step_by_id["batch_status"]
command = build_command(self.repository, step, step.variants[0], {},
str(self.state_store.evaluation))
environment = build_runner_environment(
os.environ, self.api_key_var.get(), self.proxy_var.get(), self.use_proxy_var.get()
)
self.batch_monitor.start(command, self.repository, environment,
self.state_store.workspace.log_path("batch_status_watch"))
def _batch_results_ready(self) -> None:
evaluation = self.state_store.evaluation
if evaluation is None:
return
self.state_store.update_step("batch_status", status="success", return_code=0)
self._populate_tree()
message = f"{evaluation.name} : tous les résultats batch sont prêts à récupérer."
self.info_var.set(message)
try:
notify_desktop("Copienator — batchs terminés", message)
except (OSError, RuntimeError) as exc:
self.bell()
self._append_console(f"Notification de bureau indisponible : {exc}\n{message}\n")
if (self.current_step and self.current_step.id == "batch_status"
and not self.active_step_id and not self.runner.running):
self._move_selection_from("batch_status", 1)
def _finish_process(self, return_code: int, interrupted: bool) -> None:
step_id = self.active_step_id
if not step_id:
@@ -1509,6 +1581,10 @@ class CopienatorApp(tk.Tk):
self._populate_tree()
self._update_controls()
if status == "success":
if step_id == "batch_status" and self.batch_monitor.active:
self.batch_monitor.stop()
self._batch_results_ready()
return
self.after_idle(lambda completed_id=step_id: self._move_selection_from(completed_id, 1))
def _send_input(self) -> None:
@@ -1552,13 +1628,18 @@ class CopienatorApp(tk.Tk):
def _update_controls(self) -> None:
running = bool(self.active_step_id) or self.runner.running
if self.current_step and self.current_step.id == "batch_status":
self.watch_batches_button.configure(state="disabled" if running or self.batch_monitor.active or not self.state_store.evaluation else "normal")
self.stop_watch_batches_button.configure(state="normal" if self.batch_monitor.active else "disabled")
if running and self.current_step and self.current_step.id in {"page_splitter", "cutleft"}:
self.marked_copies_button.configure(state="disabled")
if self.current_step and self.current_step.id == "rename":
self.validate_rename_button.configure(
state="disabled" if running or not self.state_store.evaluation else "normal"
)
self.run_button.configure(state="disabled" if running or not self.current_step else "normal")
watching_current = bool(self.current_step and self.current_step.id == "batch_status"
and self.batch_monitor.active)
self.run_button.configure(state="disabled" if running or not self.current_step or watching_current else "normal")
self.skip_button.configure(state="normal" if not running and self.current_step and self.current_step.optional else "disabled")
self.interrupt_button.configure(state="normal" if running else "disabled")
self.force_button.configure(state="normal" if running else "disabled")
@@ -1593,4 +1674,5 @@ class CopienatorApp(tk.Tk):
except OSError:
pass
self._save_current_form()
self.batch_monitor.stop()
self.destroy()