def queryCache(self, SPath, manageLocalStorage): projectModel = QSqlQueryModel() if self.db.open(): query = QSqlQuery(self.db) # print("in queryCache") # print(SPath) query.prepare( "select SPathRec, Title, Artist from cache WHERE SPath=:SPath " ) query.bindValue(":SPath", SPath) query.exec_() projectModel.setQuery(query) # print("num of row returned queryCache:") # print(query.numRowsAffected()) # print("query row count") if projectModel.rowCount() == 0: print("get recommendation, nothing is in Cache for this song") recommendedSongsPathList = [] getRecom = GetRecommendation(manageLocalStorage) relevantSongDict = getRecom.fetchRelevantSongOffline(SPath) if SPath: recommendedSongsPathList = getRecom.predict( SPath, relevantSongDict) else: print("problem with SongPath so can't call predict") # if playing song is also recommended then remove it if SPath in recommendedSongsPathList: recommendedSongsPathList.remove(SPath) # for item in recommendedSongsPathList: # print(item) # build cache if self.writeCache(recommendedSongsPathList, SPath): print("re Querying ") projectModel.clear() requery = QSqlQuery(self.db) requery.prepare( "select SPathRec, Title, Artist from cache WHERE SPath=:SPath " ) requery.bindValue(":SPath", SPath) requery.exec_() projectModel.setQuery(requery) # print("row Count After re query ") # print(projectModel.rowCount()) else: print("Query failed") return projectModel
class Filtrage_bope_dialog(QDialog, Ui_dlgBopeRechercheForm): ''' Class de la fenêtre permettant le filtrage attributaire des baux de pêche :param QDialog: Permet d'afficher l'interface graphique comme une fenêtre indépendante :type QDialog: QDialog :param Ui_dlgBopeRechercheForm: Class du script de l'interface graphique du formulaire, apporte les éléments de l'interface :type Ui_dlgBopeRechercheForm: class ''' def __init__(self, db, dbType, dbSchema, modelBauxPe, parent=None): ''' Constructeur, récupération de variable, connection des événements et remplissage des combobox :param db: définie dans le setupModel(), représente la connexion avec la base de données :type db: QSqlDatabase :param dbType: type de la base de données (postgre) :type dbType: str :param dbSchema: nom du schéma sous PostgreSQL contenant les données (data) :type dbSchema: unicode :param modelBauxPe: modèle droit de pêche qui contient les données de la base de données :type modelBauxPe: QSqlRelationalTableModel :param parent: défini que cette fenêtre n'hérite pas d'autres widgets :type parent: NoneType ''' super(Filtrage_bope_dialog, self).__init__(parent) self.db = db self.dbType = dbType self.dbSchema = dbSchema self.modelBauxPe = modelBauxPe self.setupUi(self) self.btnAnnuler.clicked.connect(self.reject) self.btnExec.clicked.connect(self.execution) self.btnRaz.clicked.connect(self.raz) self.btnEt.clicked.connect(self.et) self.btnOu.clicked.connect(self.ou) self.btnPrevisualiser.clicked.connect(self.previSql) self.btnId.clicked.connect(self.ajoutId) self.btnRiviere.clicked.connect(self.ajoutRiviere) self.btnAappma.clicked.connect(self.ajoutAappma) self.btnPossession.clicked.connect(self.ajoutPossession) self.btnSign.clicked.connect(self.ajoutDateSign) self.btnFin.clicked.connect(self.ajoutDateFin) self.btnC.clicked.connect(self.ajoutCommune) self.btnCS.clicked.connect(self.ajoutComSection) self.btnCSP.clicked.connect(self.ajoutComSecParcelle) self.btnProprio.clicked.connect(self.ajoutProprio) self.btnAdresse.clicked.connect(self.ajoutAdresse) self.btnEt.setEnabled(False) self.btnOu.setEnabled(False) self.leTel.setInputMask("#9999999999999") self.possessionBool = False self.aappmaBool = False self.anneeSignBool = False self.anneeFinBool = False self.CBool = False self.CSBool = False self.CSPBool = False self.wwhere = "" self.wwherePossession = "" self.wwhereProprio = "" self.modelAappma = QSqlTableModel(self, self.db) wrelation = "aappma" if self.dbType == "postgres": wrelation = self.dbSchema + "." + wrelation self.modelAappma.setTable(wrelation) self.modelAappma.setSort(1, Qt.AscendingOrder) if (not self.modelAappma.select()): QMessageBox.critical(self, u"Remplissage du modèle AAPPMA", self.modelAappma.lastError().text(), QMessageBox.Ok) self.cmbAappma.setModel(self.modelAappma) self.cmbAappma.setModelColumn(self.modelAappma.fieldIndex("apma_nom")) self.modelRiviere = QSqlTableModel(self, self.db) wrelation = "cours_eau" if self.dbType == "postgres": wrelation = self.dbSchema + "." + wrelation self.modelRiviere.setTable(wrelation) self.modelRiviere.setFilter("ceau_nom <> 'NR'") self.modelRiviere.setSort(2, Qt.AscendingOrder) if (not self.modelRiviere.select()): QMessageBox.critical(self, u"Remplissage du modèle Rivière", self.modelRiviere.lastError().text(), QMessageBox.Ok) self.cmbRiviere.setModel(self.modelRiviere) self.cmbRiviere.setModelColumn( self.modelRiviere.fieldIndex("ceau_nom")) self.modelCommune = QSqlTableModel(self, self.db) wrelation = "commune" if self.dbType == "postgres": wrelation = self.dbSchema + "." + wrelation self.modelCommune.setTable(wrelation) self.modelCommune.setSort(2, Qt.AscendingOrder) if (not self.modelCommune.select()): QMessageBox.critical(self, u"Remplissage du modèle Commune", self.modelCommune.lastError().text(), QMessageBox.Ok) self.cmbCommune.setModel(self.modelCommune) self.cmbCommune.setModelColumn(self.modelCommune.fieldIndex("com_nom")) self.cmbCommune.setCurrentIndex(1) self.modelSection = QSqlQueryModel(self) self.modelParcelle = QSqlQueryModel(self) self.cmbSection.setModel(self.modelSection) self.cmbSection.setModelColumn(2) self.cmbParcelle.setModel(self.modelParcelle) self.cmbParcelle.setModelColumn(1) self.cmbCommune.currentIndexChanged.connect(self.changeCmbCommune) self.cmbSection.currentIndexChanged.connect(self.changeCmbSection) self.cmbCommune.setCurrentIndex(0) def reject(self): '''Ferme la fenêtre si clic sur le bouton annuler''' QDialog.reject(self) def changeCmbCommune(self, newInd): ''' Filtre la combobox section en fonction de la commune affichée dans celle des communes :param newInd: index courant dans la combobox :type newInd: int ''' self.modelParcelle.clear() self.cmbParcelle.clear() self.cmbParcelle.setModel(self.modelParcelle) self.cmbParcelle.setModelColumn(1) record = self.modelCommune.record(newInd) wcom_insee = record.value(self.modelCommune.fieldIndex("com_insee")) self.modelSection.clear() wrelation = "section" if self.dbType == "postgres": wrelation = self.dbSchema + "." + wrelation self.modelSection.setQuery( "select sec_id, sec_nom || ' ; ' || sec_com_abs from " + wrelation + " where sec_com_insee = '%s' order by sec_nom;" % str(wcom_insee), self.db) if self.modelSection.lastError().isValid(): QMessageBox.critical(self, u"Remplissage du modèle Section", self.modelSection.lastError().text(), QMessageBox.Ok) self.cmbSection.setModel(self.modelSection) self.cmbSection.setModelColumn(1) self.cmbSection.setCurrentIndex(0) def changeCmbSection(self, newInd): ''' Filtre la combobox parcelle en fonction de la section affichée dans celle des sections :param newInd: index courant dans la combobox :type newInd: int ''' record = self.modelSection.record(newInd) wsec_id = record.value(0) self.cmbParcelle.clear() self.modelParcelle.clear() wrelation = "parcelle" if self.dbType == "postgres": wrelation = self.dbSchema + "." + wrelation self.modelParcelle.setQuery( "select par_id, par_numero from " + wrelation + " where par_sec_id = '%s' order by par_numero;" % str(wsec_id), self.db) if self.modelParcelle.lastError().isValid(): QMessageBox.critical(self, u"Remplissage du modèle Parcelle", self.modelParcelle.lastError().text(), QMessageBox.Ok) self.cmbParcelle.setModel(self.modelParcelle) self.cmbParcelle.setModelColumn(1) def raz(self): '''Réinitialise toutes les variables de la fenêtre afin de recommencer une nouvelle requête''' self.possessionBool = False self.aappmaBool = False self.anneeSignBool = False self.anneeFinBool = False self.CBool = False self.CSBool = False self.CSPBool = False self.spnId.setValue(0) self.wrq = "" self.txtSql.setText("") self.wwhere = "" self.wwherePossession = "" self.wwhereProprio = "" self.chkPossession.setChecked(False) self.dateSign.setDate(QDate(2000, 1, 1)) self.dateFin.setDate(QDate(2000, 1, 1)) self.btnEt.setEnabled(False) self.btnOu.setEnabled(False) self.btnId.setEnabled(True) self.btnSign.setEnabled(True) self.btnFin.setEnabled(True) self.btnRiviere.setEnabled(True) self.btnAappma.setEnabled(True) self.btnPossession.setEnabled(True) self.btnC.setEnabled(True) self.btnCS.setEnabled(True) self.btnCSP.setEnabled(True) self.btnProprio.setEnabled(True) self.btnAdresse.setEnabled(True) def et(self): '''Change l'état des boutons et ajoute "and" à la requête''' self.btnEt.setEnabled(False) self.btnOu.setEnabled(False) self.btnId.setEnabled(True) self.btnRiviere.setEnabled(True) self.btnProprio.setEnabled(True) self.btnAdresse.setEnabled(True) if self.possessionBool == False: self.btnPossession.setEnabled(True) if self.aappmaBool == False: self.btnAappma.setEnabled(True) if self.anneeSignBool == False: self.btnSign.setEnabled(True) if self.anneeFinBool == False: self.btnFin.setEnabled(True) if self.CBool == False: self.btnC.setEnabled(True) if self.CSBool == False: self.btnCS.setEnabled(True) if self.CSPBool == False: self.btnCSP.setEnabled(True) self.wwhere += " AND " def ou(self): '''Change l'état des boutons et ajoute "or" à la requête''' self.btnEt.setEnabled(False) self.btnOu.setEnabled(False) self.btnId.setEnabled(True) self.btnSign.setEnabled(True) self.btnFin.setEnabled(True) self.btnRiviere.setEnabled(True) self.btnAappma.setEnabled(True) self.btnC.setEnabled(True) self.btnCS.setEnabled(True) self.btnCSP.setEnabled(True) self.btnProprio.setEnabled(True) self.btnAdresse.setEnabled(True) self.btnPossession.setEnabled(True) self.possessionBool = False self.aappmaBool = False self.anneeSignBool = False self.anneeFinBool = False self.CBool = False self.CSBool = False self.CSPBool = False self.wwhere += " OR " def ajoutId(self): '''Change l'état des boutons et ajoute un critère d'id à la requête''' self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.wid = self.spnId.value() if self.spnId.value() != "": if self.wid != "": self.wwhere += "bope_id = '" + str(self.wid) + "'" self.spnId.setValue(0) self.spnId.setFocus() def ajoutRiviere(self): '''Change l'état des boutons et ajoute un critère de cours d'eau à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) wfrombce = "bail_cours_eau" if self.dbType == "postgres": self.wfromCeau = self.dbSchema + "." + wfrombce wrecord = self.cmbRiviere.model().record( self.cmbRiviere.currentIndex()) self.wCeau = wrecord.value(0) if self.cmbRiviere.currentText() != "": if self.wCeau != "": self.wwhere += "bope_id in (select distinct bce_bope_id from " + self.wfromCeau + " where bce_ceau_id = '" + str( self.wCeau) + "')" def ajoutAappma(self): '''Change l'état des boutons et ajoute un critère d'aappma à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.aappmaBool = True wrecord = self.cmbAappma.model().record(self.cmbAappma.currentIndex()) self.wbope_aappma = wrecord.value(0) if self.cmbAappma.currentText() != "": if self.wbope_aappma != "": self.wwhere += "bope_apma_id = '" + str( self.wbope_aappma) + "'" def ajoutPossession(self): '''Change l'état des boutons et ajoute un critère de possession à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnSign.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.possessionBool = True if self.chkPossession.isChecked() == True: self.wwherePossession = "bope_existe = True" else: self.wwherePossession = "bope_existe = False" self.wwhere += self.wwherePossession def ajoutDateSign(self): '''Change l'état des boutons et ajoute un critère de date de signature à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnSign.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.anneeSignBool = True self.wbope_date_sign = self.dateSign.date().toString("yyyy") if self.wbope_date_sign != "": self.wwhere += "date_part('year', bope_date_sign) = '" + str( self.wbope_date_sign) + "'" def ajoutDateFin(self): '''Change l'état des boutons et ajoute un critère de date d'expiration à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.anneeFinBool = True self.wbope_date_fin = self.dateFin.date().toString("yyyy") if self.wbope_date_fin != "": self.wwhere += "date_part('year', bope_date_fin) = '" + str( self.wbope_date_fin) + "'" def ajoutCommune(self): '''Change l'état des boutons et ajoute un critère de commune à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.CBool = True wrecord = self.cmbCommune.model().record( self.cmbCommune.currentIndex()) self.wcommune = wrecord.value(0) if self.cmbCommune.currentText() != "": if self.wcommune != "": self.wwhere += "bope_id in (select bope_id from data.droit_peche, data.parcelle, data.section where bope_id = par_bope_id and par_sec_id = sec_id and sec_com_insee = '" + str( self.wcommune) + "')" def ajoutComSection(self): '''Change l'état des boutons et ajoute un critère de commune et section à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.CSBool = True wrecord = self.cmbSection.model().record( self.cmbSection.currentIndex()) self.wsection = wrecord.value(0) if self.cmbSection.currentText() != "": if self.wsection != "": self.wwhere += "bope_id in (select bope_id from data.droit_peche, data.parcelle where par_bope_id = bope_id and par_sec_id = '" + str( self.wsection) + "')" def ajoutComSecParcelle(self): '''Change l'état des boutons et ajoute un critère de commune, section et parcelle à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.CSPBool = True wrecord = self.cmbParcelle.model().record( self.cmbParcelle.currentIndex()) self.wparcelle = wrecord.value(0) if self.cmbParcelle.currentText() != "": if self.wparcelle != "": self.wwhere += "bope_id in (select par_bope_id from data.parcelle where par_id = '" + str( self.wparcelle) + "')" def ajoutProprio(self): ''' Change l'état des boutons et ajoute un critère de nom de propriétaire et / ou de mail et / ou de téléphone à la requête ''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.wwhereProprio = "" self.wnom = self.leNom.text() if "'" in self.wnom and "''" not in self.wnom: self.wnom = self.wnom.replace("'", "''") self.wmail = self.leMail.text() self.wtel = self.leTel.text() if self.leNom.text() != "": if self.wnom != "": self.wwhereProprio += " bope_id in (select bope_id from data.droit_peche, data.proprietaire where bope_pro_id = pro_id and pro_nom ilike '%" + self.wnom + "%')" if self.leMail.text() != "": if self.wmail != "": if self.wnom != "": self.wwhereProprio += " and " self.wwhereProprio += " bope_id in (select bope_id from data.droit_peche, data.proprietaire where bope_pro_id = pro_id and pro_mail = '" + self.wmail + "')" if self.leTel.text() != "": if self.wtel != "": if self.wnom != "" or self.wmail != "": self.wwhereProprio += " and " self.wwhereProprio += " bope_id in (select bope_id from data.droit_peche, data.proprietaire where bope_pro_id = pro_id and pro_telephone = '" + str( self.wtel) + "')" if self.wwhereProprio != "": self.wwhere += self.wwhereProprio self.leNom.setText("") self.leMail.setText("") self.leTel.setText("") self.leNom.setFocus() def ajoutAdresse(self): '''Change l'état des boutons et ajoute un critère d'adresse à la requête''' self.btnEt.setEnabled(True) self.btnOu.setEnabled(True) self.btnId.setEnabled(False) self.btnSign.setEnabled(False) self.btnFin.setEnabled(False) self.btnRiviere.setEnabled(False) self.btnAappma.setEnabled(False) self.btnPossession.setEnabled(False) self.btnC.setEnabled(False) self.btnCS.setEnabled(False) self.btnCSP.setEnabled(False) self.btnProprio.setEnabled(False) self.btnAdresse.setEnabled(False) self.wadresse = self.leAdresse.text() if "'" in self.wadresse and "''" not in self.wadresse: self.wadresse = self.wadresse.replace("'", "''") if self.leAdresse.text() != "": if self.wadresse != "": self.wwhere += " bope_id in (select distinct bope_id from data.droit_peche, data.proprietaire where (bope_pro_id = pro_id ) and (pro_adresse ilike '%" + self.wadresse + "%'))" else: if self.leAdresse.text() == "": if self.wadresse == "": self.wwhere += " bope_id in (select distinct bope_id from data.droit_peche, data.proprietaire where (bope_pro_id = pro_id )" self.leAdresse.setText("") self.leAdresse.setFocus() def creaRequete(self): # def previSql(self): '''Regroupe les différentes variables contenant les clauses de la requête SQL et les concatène pour en faire une requête exécutable''' self.wrq = "" # Construit la clause FROM de la requête cfrom = "droit_peche" if self.dbType == "postgres": cfrom = self.dbSchema + "." + cfrom # Construit la clause SELECT et ajoute la clause FROM à la requête self.wrq = "SELECT DISTINCT bope_id FROM " + cfrom # Construit la clause WHERE et ORDER BY et l'ajoute à la requête if self.wwhere != "": #Supprime l'opérateur "and" ou "or" si celui-ci n'est pas suivi d'un critère operateurs = ["AND", "OR"] fin_where = self.wwhere[-5:] for ext in operateurs: if ext in fin_where: self.wwhere = self.wwhere[:-4] self.wrq += " WHERE " + self.wwhere + " ORDER BY bope_id" else: self.wrq += " ORDER BY bope_id" def previSql(self): '''Permet de prévisualiser la requête avant de l'éxecuter''' self.txtSql.setText("") self.creaRequete() # Affiche la requête self.txtSql.setText(self.wrq) def execution(self): '''Permet d'éxecuter la requête''' # Vérifie la non présence de mot pouvant endommager la base de données erreur = False interdit = [ "update", "delete", "insert", "intersect", "duplicate", "merge", "truncate", "create", "drop", "alter" ] if self.txtSql.toPlainText() != "": self.requete = self.txtSql.toPlainText() else: self.creaRequete() self.requete = self.wrq testRequete = self.requete.lower() for mot in interdit: if mot in testRequete: erreur = True if erreur == True: QMessageBox.critical( self, u"Erreur SQL", u"Vous essayez d'exécuter une requête qui peut endommager la base de données !", QMessageBox.Ok) # Après récupération du contenu de la zone de texte, exécute la requête else: query = QSqlQuery(self.db) query.prepare(self.requete) if query.exec_(): wparam = "" while query.next(): wparam += str(query.value(0)) + "," if (wparam != ""): wparam = "(" + wparam[0:len(wparam) - 1] + ")" if self.modelBauxPe: # Filtre le modèle des droits de pêche et ferme la fenêtre self.modelBauxPe.setFilter("bope_id in %s" % wparam) self.modelBauxPe.select() QDialog.accept(self) else: QMessageBox.information( self, "Filtrage", u"Aucun bail de pêche ne correspond aux critères ...", QMessageBox.Ok) else: QMessageBox.critical(self, u"Erreur SQL", query.lastError().text(), QMessageBox.Ok)
class HomeWidget(QWidget): def __init__(self, py_db: Database): super().__init__() self._py_db = py_db self._logger = logging.getLogger(self.__class__.__name__) self.setWindowTitle(self.__class__.__module__.rsplit('.', 1)[0]) self.setContentsMargins(0, 0, 0, 0) self.setAcceptDrops(True) self.vbox = QVBoxLayout(self) self.vbox.setContentsMargins(0, 0, 0, 0) self.vbox.setSpacing(0) self.text = QLineEdit() self.text.setContentsMargins(10, 10, 10, 10) self.text.returnPressed.connect(self._start_query) self.vbox.addWidget(self.text) self.model = QSqlQueryModel() self.model.setQuery("SELECT media_id from Media;") # self.model.setQuery("SELECT DISTINCT media_id from ManifoldItems NATURAL JOIN Manifolds WHERE ready;") self.grid = MediaView() self.grid.setModel(self.model) self.grid.doubleClicked.connect(self._grid_dbl_clicked) self.vbox.addWidget(self.grid) def sizeHint(self) -> QSize: return QSize(1070, 700) def closeEvent(self, a0: QCloseEvent) -> None: # self.grid.wbig.close() pass def _grid_dbl_clicked(self, index: QModelIndex): _id: QByteArray = index.data() self.text.setText(_id.data().hex()) self._start_query() def _start_query(self): self.setCursor(Qt.WaitCursor) QCoreApplication.processEvents() # noinspection PyBroadException try: self.model.clear() QCoreApplication.processEvents() line = self.text.text().strip() if not line: self.model.setQuery("SELECT media_id from Media;") # self.model.setQuery("SELECT DISTINCT media_id from ManifoldItems NATURAL JOIN Manifolds WHERE ready;") return if line == '@import': _source_dir = QFileDialog.getExistingDirectory( self, "Select a directory to import", "", QFileDialog.DontResolveSymlinks | QFileDialog.ReadOnly) _source_dir = os.path.abspath(_source_dir) assert os.path.isdir(_source_dir) self._logger.info(f"Starting ingestion of {_source_dir}") self._py_db.ingest_file_directory( _source_dir ) # NOTE: this will freeze the GUI for a long time! self._py_db.notify_bg_manifold_build() self._py_db.thumbs_load() self._logger.info(f"Ingestion finished. ") _source_dir_url_like = 'file:' + pathname2url( _source_dir) + '%' query = QSqlQuery() query.prepare( 'SELECT media_id FROM MediaLocations WHERE url LIKE ? ORDER BY url' ) query.bindValue(0, _source_dir_url_like) self.model.setQuery(query) return results_id, inserted = self._py_db.search(line, n=1000, search_k=-1) query_s = (f'SELECT media_id FROM results.ResultsMediaFiltered ' f'WHERE results_id = {results_id:d} ORDER BY rank ASC') query = QSqlQuery() query.exec(query_s) if not query.isActive(): self._logger.debug(f'results query: {query.lastQuery():s}') self._logger.error( f'results query error: {query.lastError().text():s}') self.model.setQuery(query) except Exception: import traceback traceback.print_exc() finally: self.setCursor(Qt.ArrowCursor) def dragEnterEvent(self, a0: QDragEnterEvent) -> None: data = a0.mimeData() if not data.hasFormat('text/uri-list'): a0.ignore() return a0.accept() a0.setDropAction(Qt.LinkAction) def dropEvent(self, a0: QDropEvent) -> None: data = a0.mimeData() action = a0.dropAction() if action == Qt.IgnoreAction: a0.ignore() return if not data.hasFormat('text/uri-list'): a0.ignore() return a0.accept() self.setCursor(Qt.WaitCursor) self.model.clear() QCoreApplication.processEvents() ul = data.data('text/uri-list').data().decode().splitlines() ul = map(str.strip, ul) ul = filter(lambda _uri: not _uri.startswith('#'), ul) ul = [ 'file:/' + _uri[len('file:///'):] if _uri.startswith('file:///') else _uri for _uri in ul ] ul = list(ul) file_binds = [] dir_binds = [] # Ingest file and dirs from received uri-list for uri in ul: if uri.startswith('file:'): pathname = url2pathname(uri[len('file:'):]) if os.path.isdir(pathname): self._logger.info(f'RECURSIVELY ADDING {pathname}') out = self._py_db.ingest_file_directory(pathname) dir_binds.append(f'{uri}%') self._logger.debug( f'ingest_file_directory({pathname}) -> {out}') continue self._logger.info(f'ADDING {uri}') media_id, flags, ex = self._py_db.try_ingest_url(uri) if ex is not None: self._logger.exception(f'FAILING {uri}: {ex}') else: file_binds.append(uri) self._logger.debug(f'{media_id=} {flags=} {ex=}') self._py_db.notify_bg_manifold_build() self._py_db.thumbs_load() # Build WHERE expression with file and dir binds conditions = [] file_placeholders = ', '.join('?' * len(file_binds)) if file_placeholders: file_placeholders = f'url IN ({file_placeholders})' conditions.append(file_placeholders) conditions.extend(['url LIKE ?'] * len(dir_binds)) # Prepare query and bind values for file and dirs query = QSqlQuery() query.prepare( f'SELECT media_id FROM MediaLocations WHERE {" OR ".join(conditions)} ORDER BY url' ) i = -1 for i, bind in enumerate(file_binds): query.bindValue(i, bind) for j, bind in zip(range(i + 1, i + 1 + len(dir_binds)), dir_binds): query.bindValue(j, bind) query.exec() if not query.isActive(): self._logger.debug(f'results query: {query.lastQuery():s}') self._logger.error( f'results query error: {query.lastError().text():s}') self.model.setQuery(query) self.setCursor(Qt.ArrowCursor)