"""Onglet « Configuration » de la GUI V6 (G3-B). Édite un :class:`ConfigState` partagé : profil métier, raster burn, NER local, dossier de sortie. Affiche l'état des managers NER. Les options sensibles ne sont visibles/éditables qu'en mode admin (``admin_mode.is_admin``). Aucune logique de détection : on édite seulement l'état lu par l'onglet Utilisation. Les widgets ne sont créés qu'à l'instanciation (import sûr pour ``--self-test``). """ from __future__ import annotations from pathlib import Path from tkinter import filedialog import customtkinter as ctk from gui_v6.config_state import ConfigState, default_profile_key, list_profile_keys def _is_admin() -> bool: try: from admin_mode import is_admin return bool(is_admin()) except Exception: return False class ConfigTab(ctk.CTkFrame): def __init__(self, master, state: ConfigState | None = None, **kwargs): super().__init__(master, **kwargs) self._state = state if state is not None else ConfigState() self._admin = _is_admin() self._build() @property def state(self) -> ConfigState: return self._state def _build(self) -> None: ctk.CTkLabel( self, text="Configuration", font=ctk.CTkFont(size=16, weight="bold") ).pack(anchor="w", padx=16, pady=(16, 8)) # Profil métier profiles = list_profile_keys() current = self._state.profile or default_profile_key() or (profiles[0] if profiles else "") self._state.profile = current or None row = ctk.CTkFrame(self) row.pack(fill="x", padx=16, pady=4) ctk.CTkLabel(row, text="Profil :").pack(side="left", padx=(0, 8)) self._profile_menu = ctk.CTkOptionMenu( row, values=profiles or ["(aucun profil)"], command=self._on_profile, ) if current: self._profile_menu.set(current) self._profile_menu.pack(side="left") # Options simples self._raster = ctk.CTkCheckBox( self, text="Caviardage raster (burn)", command=self._on_raster ) self._raster.select() if self._state.raster_burn else self._raster.deselect() self._raster.pack(anchor="w", padx=16, pady=4) self._ner = ctk.CTkCheckBox( self, text="NER local actif", command=self._on_ner ) self._ner.select() if self._state.use_local_ner else self._ner.deselect() self._ner.pack(anchor="w", padx=16, pady=4) # Dossier de sortie out_row = ctk.CTkFrame(self) out_row.pack(fill="x", padx=16, pady=4) ctk.CTkButton(out_row, text="Dossier de sortie…", command=self._pick_output).pack( side="left", padx=(0, 8) ) self._output_label = ctk.CTkLabel( out_row, text=str(self._state.output_dir or "(défaut anonymise/)") ) self._output_label.pack(side="left") # Options admin-only if self._admin: ctk.CTkLabel(self, text="Options avancées (admin)").pack( anchor="w", padx=16, pady=(12, 4) ) self._gliner = ctk.CTkCheckBox( self, text="GLiNER (vote croisé)", command=self._on_gliner ) self._gliner.pack(anchor="w", padx=16, pady=2) self._eds = ctk.CTkCheckBox( self, text="EDS-Pseudo", command=self._on_eds ) self._eds.pack(anchor="w", padx=16, pady=2) # État des managers self._managers_label = ctk.CTkLabel(self, text="Managers NER : non chargé", anchor="w") self._managers_label.pack(anchor="w", padx=16, pady=(12, 16)) # -- callbacks -------------------------------------------------------- def _on_profile(self, value: str) -> None: self._state.profile = value def _on_raster(self) -> None: self._state.raster_burn = bool(self._raster.get()) def _on_ner(self) -> None: self._state.use_local_ner = bool(self._ner.get()) def _on_gliner(self) -> None: self._state.enable_gliner = bool(self._gliner.get()) def _on_eds(self) -> None: self._state.enable_eds = bool(self._eds.get()) def _pick_output(self) -> None: path = filedialog.askdirectory(title="Dossier de sortie") if path: self._state.output_dir = Path(path) self._output_label.configure(text=str(self._state.output_dir)) def set_managers_state(self, state_text: str) -> None: self._managers_label.configure(text=f"Managers NER : {state_text}")