from PyQt6.QtWidgets import ( QDialog, QVBoxLayout, QFormLayout, QHBoxLayout, QGridLayout, QLineEdit, QComboBox, QDialogButtonBox, QTextEdit, QLabel, QMessageBox, QFrame, ) from PyQt6.QtCore import Qt, QThread, pyqtSignal from loguru import logger from client.session import GemmaSession from client.detail import save_detail from app.searchable_combo import SearchableCombo # Campi editabili nell'ordine della scheda GEMMA originale _EDITABLE_FIELDS = [ ("titolo", "Titolo"), ("codprod", "Codice Prodotto"), ("tipologiaCode", "Tipologia"), ("data", "Data"), ("autore", "Autore / Regista"), ("starring", "Cast"), ("codiceImdb", "Codice IMDB"), ("prestito.deadline", "Deadline"), ("prestito.notePubbliche", "Note pubbliche"), ("prestito.notePrivate", "Note private"), ("acquistatoVenduto", "Acquistato/Venduto"), ] _COMBOS = { "acquistatoVenduto": [("", "—"), ("A", "Acquistato"), ("V", "Venduto")], "tipologiaCode": [("F", "Film"), ("S", "Serie"), ("D", "Documentario"), ("M", "Mini-serie"), ("CORTOMETRAGGIO", "Cortometraggio")], } _MULTILINE = {"prestito.notePubbliche", "prestito.notePrivate"} class _SaveWorker(QThread): done = pyqtSignal() error = pyqtSignal(str) def __init__(self, session, form_data): super().__init__() self._session = session self._form_data = form_data def run(self): try: save_detail(self._session, self._form_data) self.done.emit() except Exception as e: self.error.emit(str(e)) class DetailDialog(QDialog): saved = pyqtSignal() def __init__(self, form_data: dict, session: GemmaSession, distributori: list[tuple[str, str]] | None = None, parent=None): super().__init__(parent) self._form_data = dict(form_data) self._session = session self._distributori = distributori or [] self._widgets: dict[str, QLineEdit | QComboBox | QTextEdit] = {} self._distrib_combo: SearchableCombo | None = None self._save_worker: _SaveWorker | None = None self._init_ui() def _init_ui(self): titolo = self._form_data.get("titolo", "—") prod_id = self._form_data.get("id", "") self.setWindowTitle(f"{titolo} (id: {prod_id})") self.setMinimumWidth(600) self.setModal(True) layout = QVBoxLayout(self) layout.setSpacing(10) # ── Distributore ─────────────────────────────────────────────────── distrib_row = QHBoxLayout() distrib_row.addWidget(QLabel("Distributore:")) self._distrib_combo = SearchableCombo() self._distrib_combo.setMinimumWidth(350) if self._distributori: self._distrib_combo.set_items(self._distributori) self._distrib_combo.setText(self._form_data.get("distributore.ragioneSociale", "")) else: self._distrib_combo.setText(self._form_data.get("distributore.ragioneSociale", "")) self._distrib_combo.setReadOnly(True) self._distrib_combo.setStyleSheet("background: #f0f0f0; color: #333;") distrib_row.addWidget(self._distrib_combo, stretch=1) layout.addLayout(distrib_row) sep = QFrame() sep.setFrameShape(QFrame.Shape.HLine) sep.setFrameShadow(QFrame.Shadow.Sunken) layout.addWidget(sep) # ── Campi editabili ──────────────────────────────────────────────── form = QFormLayout() form.setLabelAlignment(Qt.AlignmentFlag.AlignRight) form.setHorizontalSpacing(16) form.setVerticalSpacing(6) for field_name, label in _EDITABLE_FIELDS: value = self._form_data.get(field_name, "") if field_name in _COMBOS: w: QComboBox | QLineEdit | QTextEdit = QComboBox() for val, text in _COMBOS[field_name]: w.addItem(text, val) idx = w.findData(value) w.setCurrentIndex(idx if idx >= 0 else 0) elif field_name in _MULTILINE: w = QTextEdit(value) w.setFixedHeight(70) else: w = QLineEdit(value) if field_name == "titolo": w.setMinimumWidth(300) self._widgets[field_name] = w form.addRow(label + ":", w) layout.addLayout(form) # ── Metadati read-only (fondo scheda) ────────────────────────────── meta = { "utenteInserimento": "Utente inserimento", "dataInserimento": "Creazione", "utenteModifica": "Utente modifica", "dataModifica": "Modifica", } meta_values = {k: self._form_data.get(k, "") for k in meta if self._form_data.get(k)} if meta_values: sep2 = QFrame() sep2.setFrameShape(QFrame.Shape.HLine) sep2.setFrameShadow(QFrame.Shadow.Sunken) layout.addWidget(sep2) grid = QGridLayout() grid.setHorizontalSpacing(20) col = 0 for key, lbl in meta.items(): val = self._form_data.get(key, "") if not val: continue lbl_w = QLabel(f"{lbl}:") lbl_w.setStyleSheet("color: #666; font-size: 11px;") val_w = QLineEdit(val) val_w.setReadOnly(True) val_w.setStyleSheet("background: #f0f0f0; color: #555; font-size: 11px;") val_w.setFixedWidth(150) row_idx, col_idx = divmod(col, 2) grid.addWidget(lbl_w, row_idx, col_idx * 2) grid.addWidget(val_w, row_idx, col_idx * 2 + 1) col += 1 layout.addLayout(grid) # ── Pulsanti ─────────────────────────────────────────────────────── buttons = QDialogButtonBox( QDialogButtonBox.StandardButton.Save | QDialogButtonBox.StandardButton.Cancel ) self._save_btn = buttons.button(QDialogButtonBox.StandardButton.Save) self._save_btn.setText("Salva") buttons.button(QDialogButtonBox.StandardButton.Cancel).setText("Annulla") buttons.accepted.connect(self._save) buttons.rejected.connect(self.reject) layout.addWidget(buttons) def _save(self): for field_name, w in self._widgets.items(): if isinstance(w, QComboBox): self._form_data[field_name] = w.currentData() or "" elif isinstance(w, QTextEdit): self._form_data[field_name] = w.toPlainText() else: self._form_data[field_name] = w.text() # Aggiorna distributore se modificato if self._distrib_combo: sel_id = self._distrib_combo.selected_id() sel_name = self._distrib_combo.text().strip() if not sel_id and sel_name: # Nessuna voce cliccata dal popup — cerca corrispondenza esatta nella lista match = next((i for n, i in self._distributori if n.lower() == sel_name.lower()), None) if match: sel_id = match elif sel_name != self._form_data.get("distributore.ragioneSociale", ""): QMessageBox.warning(self, "Attenzione", "Distributore non trovato nella lista. Digita almeno 3 lettere e scegli una voce dal popup.") return if sel_id: self._form_data["distributore.id"] = sel_id self._form_data["distributore.ragioneSociale"] = sel_name self._save_btn.setEnabled(False) self._save_btn.setText("Salvataggio...") self._save_worker = _SaveWorker(self._session, self._form_data) self._save_worker.done.connect(self._on_saved) self._save_worker.error.connect(self._on_save_error) self._save_worker.start() def _on_saved(self): self.saved.emit() QMessageBox.information(self, "OK", "Salvato con successo.") self.accept() def _on_save_error(self, msg: str): self._save_btn.setEnabled(True) self._save_btn.setText("Salva") logger.error(f"Errore salvataggio: {msg}") QMessageBox.critical(self, "Errore salvataggio", msg)