""" Dialog di ricerca film - Replica VBA Search Form Adattato da ProssimeUscite\src\gui\search_dialog.py """ from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLineEdit, QComboBox, QTableWidget, QTableWidgetItem, QPushButton, QCheckBox, QLabel, QMessageBox) from PyQt6.QtGui import QFont import pandas as pd import logging logger = logging.getLogger(__name__) class SearchDialog(QDialog): """ Dialog per ricerca film/serie nelle tabelle IMDB o CUSTOM_ANAGR_ORIZ (OnAir). Equivalente VBA: frmRicerca """ _last_su: str = 'IMDB' # persiste la selezione SU tra aperture successive def __init__(self, search_text: str = "", credits: str = "", database=None, source_row: int = -1, search_mode: str = 'TITOLO', parent=None): super().__init__(parent) self.search_text = search_text self.credits = credits self.database = database self.source_row = source_row self.selected_imdb_code = None self.selected_rifer = None self._initial_search_mode = search_mode window_title = search_text if search_text else "Ricerca" if credits: window_title = f"{search_text} - {credits}" self.setWindowTitle(window_title) self.setModal(True) self.setFixedSize(900, 500) self._setup_ui() # Ripristina ultima sorgente (IMDB / OnAir) idx_su = self.su_combo.findText(SearchDialog._last_su) if idx_su >= 0: self.su_combo.setCurrentIndex(idx_su) # Imposta modalità di ricerca iniziale idx = self.search_type_combo.findText(search_mode) if idx >= 0: self.search_type_combo.setCurrentIndex(idx) if search_text: # Per REGISTA non troncare il nome if search_mode == 'REGISTA': self.search_input.setText(search_text) else: truncated = search_text[:10] if len(search_text) > 10 else search_text self.search_input.setText(truncated) logger.info(f"SearchDialog inizializzato: '{window_title}', modalità: {search_mode}") if search_text and self.database: from PyQt6.QtCore import QTimer QTimer.singleShot(100, self._on_search) logger.info("Ricerca automatica schedulata") def _setup_ui(self): layout = QVBoxLayout(self) layout.setSpacing(10) layout.setContentsMargins(15, 15, 15, 15) # Riga ricerca search_layout = QHBoxLayout() search_layout.setSpacing(8) self.search_input = QLineEdit() self.search_input.setPlaceholderText("Inserisci testo da cercare...") self.search_input.setFont(QFont("Calibri", 10)) self.search_input.setMinimumWidth(300) search_layout.addWidget(self.search_input) ricerca_label = QLabel("RICERCA PER") ricerca_label.setFont(QFont("Calibri", 9)) search_layout.addWidget(ricerca_label) self.search_type_combo = QComboBox() self.search_type_combo.addItems(["TITOLO", "REGISTA"]) self.search_type_combo.setFont(QFont("Calibri", 10)) self.search_type_combo.setMinimumWidth(100) search_layout.addWidget(self.search_type_combo) su_label = QLabel("SU") su_label.setFont(QFont("Calibri", 9)) search_layout.addWidget(su_label) self.su_combo = QComboBox() self.su_combo.addItems(["IMDB", "OnAir"]) self.su_combo.setFont(QFont("Calibri", 10)) self.su_combo.setMinimumWidth(100) search_layout.addWidget(self.su_combo) search_layout.addStretch() layout.addLayout(search_layout) # Tabella risultati self.results_table = QTableWidget() self.results_table.setFont(QFont("Calibri", 9)) self.results_table.setAlternatingRowColors(True) self.results_table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows) self.results_table.setSelectionMode(QTableWidget.SelectionMode.SingleSelection) self.results_table.setColumnCount(6) self.results_table.setHorizontalHeaderLabels(["TIPOL", "TO", "TI", "ANNO", "REGISTA", "IMDB"]) self.results_table.setSortingEnabled(True) header = self.results_table.horizontalHeader() header.setStretchLastSection(True) self.results_table.setColumnWidth(0, 80) self.results_table.setColumnWidth(1, 200) self.results_table.setColumnWidth(2, 200) self.results_table.setColumnWidth(3, 60) self.results_table.setColumnWidth(4, 150) self.results_table.setStyleSheet(""" QTableWidget { background-color: #FFFFCC; gridline-color: #D0D0D0; } QTableWidget::item { padding: 4px; } QTableWidget::item:selected { background-color: #4A90E2; color: white; } """) layout.addWidget(self.results_table) # Sezione inferiore bottom_layout = QHBoxLayout() bottom_layout.setSpacing(10) ordina_label = QLabel("ORDINA PER") ordina_label.setFont(QFont("Calibri", 9, QFont.Weight.Bold)) bottom_layout.addWidget(ordina_label) self.sort_combo = QComboBox() self.sort_combo.addItems(["TO", "TITOLO", "ANNO"]) self.sort_combo.setFont(QFont("Calibri", 10)) self.sort_combo.setMinimumWidth(150) bottom_layout.addWidget(self.sort_combo) self.inizia_con_checkbox = QCheckBox("INIZIA CON") self.inizia_con_checkbox.setFont(QFont("Calibri", 9)) self.inizia_con_checkbox.setChecked(True) bottom_layout.addWidget(self.inizia_con_checkbox) bottom_layout.addStretch() self.refresh_button = QPushButton("AGGANCIA") self.refresh_button.setFont(QFont("Calibri", 10, QFont.Weight.Bold)) self.refresh_button.setMinimumWidth(120) self.refresh_button.setStyleSheet(""" QPushButton { background-color: #4A90E2; color: white; border: none; padding: 8px 16px; border-radius: 3px; } QPushButton:hover { background-color: #357ABD; } QPushButton:pressed { background-color: #2968A8; } """) bottom_layout.addWidget(self.refresh_button) layout.addLayout(bottom_layout) self.search_input.returnPressed.connect(self._on_search) self.search_input.textChanged.connect(self._on_text_changed) self.refresh_button.clicked.connect(self._on_aggancia) self.results_table.doubleClicked.connect(self._on_result_selected) self.su_combo.currentIndexChanged.connect(self._on_source_changed) def _on_source_changed(self): """Aggiorna intestazione colonna 5 e svuota risultati quando cambia la sorgente.""" is_onair = self.su_combo.currentText() == 'OnAir' last_header = "RIFER" if is_onair else "IMDB" self.results_table.setHorizontalHeaderLabels( ["TIPOL", "TO", "TI", "ANNO", "REGISTA", last_header] ) self.results_table.setRowCount(0) SearchDialog._last_su = self.su_combo.currentText() if self.search_input.text().strip(): self._on_search() def _on_text_changed(self, text): text = text.strip() if len(text) >= 3: self._on_search() else: self.results_table.setRowCount(0) def _on_search(self): search_text = self.search_input.text().strip() if not search_text: return if not self.database: QMessageBox.warning(self, "Errore", "Database non disponibile") return try: by_regista = self.search_type_combo.currentText() == 'REGISTA' on_air = self.su_combo.currentText() == 'OnAir' if on_air: # Per CUSTOM il cognome è il campo di ricerca: usa l'ultima parola term = search_text.split()[-1] if by_regista else search_text df_results = self.database.search_custom(term, by_regista=by_regista) else: df_results = self.database.search_imdb(search_text, by_regista=by_regista) self._populate_results(df_results) except Exception as e: error_msg = f"Errore durante ricerca: {str(e)}" logger.error(error_msg, exc_info=True) QMessageBox.critical(self, "Errore Ricerca", error_msg) def _on_aggancia(self): selected_rows = self.results_table.selectionModel().selectedRows() if not selected_rows: QMessageBox.warning(self, "Attenzione", "Seleziona un risultato dalla griglia") return row = selected_rows[0].row() self._select_row(row) def _on_result_selected(self, index): self._select_row(index.row()) def _select_row(self, row: int): item = self.results_table.item(row, 5) if not item or not item.text(): QMessageBox.warning(self, "Errore", "Valore non trovato nella riga selezionata") return if self.su_combo.currentText() == 'OnAir': self.selected_rifer = item.text() else: self.selected_imdb_code = item.text() self.accept() def get_selected_imdb_code(self): return self.selected_imdb_code def get_selected_rifer(self): return self.selected_rifer def _populate_results(self, df_results): if df_results.empty: self.results_table.setRowCount(0) return is_onair = self.su_combo.currentText() == 'OnAir' self.results_table.setSortingEnabled(False) self.results_table.setRowCount(len(df_results)) for row_idx, row in df_results.iterrows(): def _item(val): if pd.notna(val) and isinstance(val, float): s = str(int(val)) elif pd.notna(val) and isinstance(val, int): s = str(val) else: s = str(val) if pd.notna(val) else '' it = QTableWidgetItem(s) it.setFont(QFont("Calibri", 9)) return it self.results_table.setItem(row_idx, 0, _item(row.get('TIPOL', ''))) self.results_table.setItem(row_idx, 1, _item(row.get('TO', ''))) self.results_table.setItem(row_idx, 2, _item(row.get('TI', ''))) anno = row.get('ANNO', '') if pd.notna(anno) and isinstance(anno, float): anno = str(int(anno)) self.results_table.setItem(row_idx, 3, QTableWidgetItem(str(anno) if pd.notna(anno) else '')) if is_onair: reg_c = str(row.get('REGISTA_COGN', '') or '') reg_n = str(row.get('REGISTA_NOME', '') or '') regista = (reg_n + ' ' + reg_c).strip() self.results_table.setItem(row_idx, 4, QTableWidgetItem(regista)) self.results_table.setItem(row_idx, 5, _item(row.get('RIFER', ''))) else: self.results_table.setItem(row_idx, 4, _item(row.get('REGISTA', ''))) self.results_table.setItem(row_idx, 5, _item(row.get('IMDB_CODICE', ''))) self.results_table.setSortingEnabled(True)