# -*- coding: utf-8 -*- """ Module Flux Editor pour le plugin CenRA_FLUX Permet de gérer et charger des couches depuis les bases de données PostGIS (SIG et REF) """ from __future__ import absolute_import # Import des bibliothèques PyQt et QGIS from builtins import str from qgis.PyQt import QtCore, QtGui from qgis.PyQt.QtCore import QSettings from qgis.PyQt import QtWidgets from qgis.PyQt.QtGui import QIcon from qgis.core import ( QgsDataSourceUri, QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsProject, QgsSettings, QgsApplication, QgsVectorLayer, QgsRasterLayer, QgsWkbTypes ) from qgis.PyQt.QtWidgets import ( QDialog, QPushButton, QTableWidgetItem, QMessageBox, QVBoxLayout, ) from .tools.SQLRequet import schemaname_list, schemaname_list_ref, schemaname_distinct from .tools.resources import ( load_ui, resources_path, ) try: from .tools.PythonSQL import login_base except NameError: print('Pas de fichier PythonSQL') from qgis.utils import iface import psycopg2 import psycopg2.extras # Variable globale pour le mode debug global DeBUG DeBUG = 0 # Création des icônes pour les couches raster et vecteur itemIconRaster = QTableWidgetItem() icon = QIcon() icon.addPixmap(QtGui.QPixmap(resources_path('icons', 'mIconRaster.svg')), QIcon.Mode(0), QIcon.State(1)) itemIconRaster.setIcon(icon) itemIconVecteur = QTableWidgetItem() icon = QIcon() icon.addPixmap(QtGui.QPixmap(resources_path('icons', 'mIconVecteur.svg')), QIcon.Mode(0), QIcon.State(1)) itemIconVecteur.setIcon(icon) # Récupération des informations de connexion à la base de données try: account = login_base('account') user = account[0] # Nom d'utilisateur mdp = account[1] # Mot de passe host = account[2] # Hôte de la base de données port = account[3] # Port de connexion dbname = account[4] # Nom de la base de données sigdb = account[5] # Base de données SIG refdb = account[6] # Base de données REF except NameError: print('Fails to login DB for account') # Chargement de l'interface utilisateur depuis le fichier .ui EDITOR_CLASS = load_ui('CenRa_Flux_base.ui') # Configuration des systèmes de coordonnées de référence (CRS) targetCrs = QgsCoordinateReferenceSystem('EPSG:4326') # WGS84 (coordonnées géographiques) layerCrs = QgsCoordinateReferenceSystem('EPSG:2154') # Lambert 93 (projection française) TranformCRS = QgsCoordinateTransform(layerCrs, targetCrs, QgsProject.instance()) class Flux_Editor(QDialog, EDITOR_CLASS): """ Classe principale de l'éditeur de flux Gère l'interface de sélection et de chargement des couches depuis les bases de données """ def __init__(self, parent=None): """Initialisation de l'interface et des composants""" _ = parent super().__init__() self.setupUi(self) self.settings = QgsSettings() self.s = QSettings() self.setWindowIcon(QtGui.QIcon(resources_path('icons', 'icon.png'))) self.first_start = None self.iface = iface # Configuration des éléments visuels de l'interface self.label_3.setPixmap(QtGui.QPixmap(resources_path('ui', 'logo.png'))) self.commandLinkButton.setIcon(QtGui.QIcon(resources_path('ui', 'arrow-bottom.png'))) self.commandLinkButton_2.setIcon(QtGui.QIcon(resources_path('ui', 'arrow-up.png'))) # Configuration du tableau des couches disponibles self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger(0)) self.toolButton.setIcon(QtGui.QIcon(resources_path('ui', 'find.png'))) self.toolButton_2.setIcon(QtGui.QIcon(resources_path('ui', 'star.png'))) # Ajout des options de base de données (SIG ou REF) self.comboBox_2.addItem("SIG") self.comboBox_2.addItem('REF') # Connexion des signaux aux slots (événements de l'interface) self.commandLinkButton.clicked.connect(self.selection_flux) # Bouton de sélection de flux self.tableWidget.itemDoubleClicked.connect(self.selection_flux) # Double-clic sur une couche self.pushButton_2.clicked.connect(self.limite_flux) # Bouton de chargement self.commandLinkButton_2.clicked.connect(self.suppression_flux) # Bouton de suppression self.tableWidget_2.itemDoubleClicked.connect(self.suppression_flux) # Double-clic pour supprimer self.comboBox_2.currentIndexChanged.connect(self.bd_source) # Changement de base de données self.checkBox.hide() self.toolButton.clicked.connect(self.getCanevas) # Filtrer par emprise du canevas self.toolButton.setToolTip('Filtrer uniquement les couche Contour/Habitat/Travaux \nqui ce trouve dans le canvas de la carte.') self.toolButton_2.clicked.connect(self.filtre_favorit) # Filtrer par favoris self.toolButton_2.setToolTip('Afficher uniquement les favoris.') layout = QVBoxLayout() self.lineEdit.textChanged.connect(self.filtre_dynamique) # Recherche dynamique layout.addWidget(self.lineEdit) self.viewer.hide() # Configuration du menu de debug (caché par défaut) self.DeBUG.addItem('') self.DeBUG.addItem('Dev') self.DeBUG.addItem('01') self.DeBUG.addItem('0726') self.DeBUG.addItem('4269') self.comboBox.currentIndexChanged.connect(self.initialisation_flux) self.DeBUG.currentIndexChanged.connect(self.SwitchDEBUG) self.DeBUG.hide() # Menu debug caché par défaut def raise_(self): """Run method that performs all the real work""" self.bd_source() def SwitchDEBUG(self): """Change les paramètres de connexion selon le mode debug sélectionné""" try: global user, mdp, host, port, dbname, sigdb, refdb account = login_base(self.DeBUG.currentText()) user = account[0] mdp = account[1] host = account[2] port = account[3] dbname = account[4] sigdb = account[5] refdb = account[6] self.bd_source() except NameError: print('Fails to switch DB for account') def ModeDeBUG(self): self.DeBUG.show() def mousePressEvent(self, event): """Détecte les clics sur le logo pour activer le mode debug (3 clics consécutifs)""" global DeBUG # Zone du logo (coordonnées x: 330-560, y: 5-75) if 330 <= event.pos().x() <= 560 and 5 <= event.pos().y() <= 75: DeBUG = DeBUG + 1 if DeBUG == 3: # Activation après 3 clics DeBUG = 0 self.ModeDeBUG() else: DeBUG = 0 self.DeBUG.hide() def bd_source(self): """Sélectionne la base de données source (SIG ou REF)""" self.activateWindow() bd_origine = self.comboBox_2.currentText() if bd_origine == 'REF': self.run_ref() # Connexion à la base REF if bd_origine == 'SIG': self.run_sig() # Connexion à la base SIG def run_ref(self): """Initialise la connexion à la base de données REF""" # Vider le tableau des flux sélectionnés while self.tableWidget_2.rowCount() > 0: self.tableWidget_2.removeRow(self.tableWidget_2.rowCount() - 1) global cur, con, dbtype dbtype = refdb # Connexion à la base de données REF con = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + dbtype + " user=" + user + " password=" + mdp) cur = con.cursor(cursor_factory=psycopg2.extras.DictCursor) self.combobox_custom() self.initialisation_flux() # Create the dialog with elements (after translation) and keep reference # Only create GUI ONCE in callback, so that it will only load when the plugin is started if self.first_start is True: self.first_start = False # show the dialog self.show() # Run the dialog event loop result = self.exec() if result: pass def run_sig(self): """Initialise la connexion à la base de données SIG""" # Vider le tableau des flux sélectionnés while self.tableWidget_2.rowCount() > 0: self.tableWidget_2.removeRow(self.tableWidget_2.rowCount() - 1) global cur, con, dbtype dbtype = sigdb # Connexion à la base de données SIG con = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + dbtype + " user=" + user + " password=" + mdp) cur = con.cursor(cursor_factory=psycopg2.extras.DictCursor) self.combobox_custom() self.initialisation_flux() if self.first_start is True: self.first_start = False def suppression_flux(self): self.tableWidget_2.removeRow(self.tableWidget_2.currentRow()) def AddOrDelToUserFav(self): """Ajoute ou supprime une couche des favoris de l'utilisateur""" selected_items = self.tableWidget.selectedItems() favorit_statut = selected_items[4].text() # 0 = non favori, 1 = favori selected_items[4].tableWidget().removeCellWidget(selected_items[4].row(), 4) schema_name = selected_items[2].text() table_name = selected_items[3].text() # Ajout aux favoris if favorit_statut == "0": FAV = "mStarIconDel.png" # Icône étoile pleine selected_items[4].setText("1") # Requête SQL pour ajouter aux favoris SQLAddFav = """INSERT INTO admin_sig.favtable (utilisateur, schema_name, table_name) VALUES ('""" + user + "','" + schema_name + "','" + table_name + """');""" if dbtype == sigdb: cur.execute(SQLAddFav) con.commit() else: conSIG = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + sigdb + " user=" + user + " password=" + mdp) curSIG = conSIG.cursor(cursor_factory=psycopg2.extras.DictCursor) curSIG.execute(SQLAddFav) conSIG.commit() conSIG.close() # Suppression des favoris else: FAV = "mStarIconAdd.png" # Icône étoile vide selected_items[4].setText("0") # Requête SQL pour supprimer des favoris SQLDelFav = """DELETE FROM admin_sig.favtable WHERE utilisateur LIKE '""" + user + """' AND schema_name LIKE '""" + schema_name + """' AND table_name LIKE '""" + table_name + """';""" if dbtype == sigdb: cur.execute(SQLDelFav) con.commit() else: conSIG = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + sigdb + " user=" + user + " password=" + mdp) curSIG = conSIG.cursor(cursor_factory=psycopg2.extras.DictCursor) curSIG.execute(SQLDelFav) conSIG.commit() conSIG.close() iconFav = QIcon() iconFav.addPixmap(QtGui.QPixmap(resources_path('icons', FAV)), QIcon.Mode(0), QIcon.State(1)) self.FavButton = QPushButton(iconFav, "") selected_items[4].tableWidget().setCellWidget(selected_items[4].row(), 4, self.FavButton) self.FavButton.clicked.connect(self.AddOrDelToUserFav) def initialisation_flux(self): """Initialise et remplit le tableau des couches disponibles""" if self.toolButton_2.text() == "1": self.filtre_favorit(None) self.tableWidget.clear() if NoSignals == 0: # Éviter les boucles infinies lors des mises à jour if dbtype == sigdb: if self.comboBox.currentText() == 'toutes les catégories': custom_list = schemaname_list elif self.comboBox.currentText() == 'travaux': custom_list = """(SELECT schemaname,tablename from pg_catalog.pg_tables where schemaname like '""" + str(self.comboBox.currentText()) + """%' order by schemaname,tablename) UNION (SELECT schemaname,matviewname AS tablename FROM pg_catalog.pg_matviews where schemaname like '""" + str(self.comboBox.currentText()) + """%' order by schemaname,tablename) order by schemaname,tablename;""" else: custom_list = """(SELECT schemaname,tablename from pg_catalog.pg_tables where schemaname like '\\_""" + str(self.comboBox.currentText()) + """%' order by schemaname,tablename) UNION (SELECT schemaname,matviewname AS tablename FROM pg_catalog.pg_matviews where schemaname like '\\_""" + str(self.comboBox.currentText()) + """%' order by schemaname,tablename) order by schemaname,tablename;""" else: if self.comboBox.currentText() == 'toutes les catégories': custom_list = schemaname_list_ref else: custom_list = """SELECT schemaname, tablename from pg_catalog.pg_tables WHERE schemaname LIKE '""" + str(self.comboBox.currentText()) + """' AND tablename NOT LIKE 'qgis_projects' order by schemaname, tablename;""" cur.execute(custom_list) list_schema = cur.fetchall() # Vérification de la présence de couches raster dans la base SQLcountRaster = """SELECT schemaname,viewname FROM pg_catalog.pg_views WHERE schemaname LIKE 'public' AND viewname LIKE 'raster_columns';""" cur.execute(SQLcountRaster) RasterIF = len(cur.fetchall()) # Récupération de la liste des couches raster si disponibles if RasterIF == 1: SQLloadRaster = """SELECT concat(r_table_schema,'.',r_table_name) from public.raster_columns; """ cur.execute(SQLloadRaster) list_raster = cur.fetchall() RasterList = [] for rasterFind in list_raster: RasterList.append(rasterFind[0]) else: RasterList = [] # Récupération des projets QGIS stockés dans la base de données SQLprojects = """SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE tablename LIKE 'qgis_projects'""" cur.execute(SQLprojects) list_projects = cur.fetchall() list_projects_qgis = [] if len(list_projects) <= 1: for ProjectName in list_projects: SQLProjectsQgis = """SELECT name, metadata, content FROM """ + '"' + ProjectName[0] + '"."' + ProjectName[1] + '"' cur.execute(SQLProjectsQgis) list_projects_qgis.append(cur.fetchall()) # Récupération des droits d'accès de l'utilisateur sur les tables if self.comboBox.currentText() == 'toutes les catégories': SQLGrands = """SELECT concat(table_schema,'.',table_name) FROM information_schema.role_table_grants WHERE grantee in(SELECT rolname FROM pg_catalog.pg_roles WHERE oid in(SELECT roleid FROM pg_auth_members WHERE member = (SELECT usesysid FROM pg_catalog.pg_user WHERE usename = '""" + user + """'))) and privilege_type = 'SELECT';""" else: if dbtype == sigdb: SQLGrands = """SELECT concat(table_schema,'.',table_name) FROM information_schema.role_table_grants WHERE grantee in(SELECT rolname FROM pg_catalog.pg_roles WHERE oid in(SELECT roleid FROM pg_auth_members WHERE member = (SELECT usesysid FROM pg_catalog.pg_user WHERE usename = '""" + user + """'))) and privilege_type = 'SELECT' AND table_schema LIKE '_""" + str(self.comboBox.currentText()) + """_%';""" elif dbtype == refdb: SQLGrands = """SELECT concat(table_schema,'.',table_name) FROM information_schema.role_table_grants WHERE grantee in(SELECT rolname FROM pg_catalog.pg_roles WHERE oid in(SELECT roleid FROM pg_auth_members WHERE member = (SELECT usesysid FROM pg_catalog.pg_user WHERE usename = '""" + user + """'))) and privilege_type = 'SELECT' AND table_schema LIKE '""" + str(self.comboBox.currentText()) + """%';""" cur.execute(SQLGrands) list_grands = cur.fetchall() GrandUser = [] for grandsFind in list_grands: GrandUser.append(grandsFind[0]) # Récupération de la liste des favoris de l'utilisateur SQLFavTable = "SELECT concat(schema_name, '.', table_name) FROM admin_sig.favtable WHERE utilisateur LIKE '" + user + "';" if dbtype == refdb: conSIG = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + sigdb + " user=" + user + " password=" + mdp) curSIG = conSIG.cursor(cursor_factory=psycopg2.extras.DictCursor) curSIG.execute(SQLFavTable) list_fav = curSIG.fetchall() conSIG.close() print('SIG') else: cur.execute(SQLFavTable) list_fav = cur.fetchall() FavList = [] for favFind in list_fav: FavList.append(favFind[0]) # Remplissage du tableau avec les couches disponibles self.tableWidget.setRowCount(len(list_schema)) self.tableWidget.setColumnCount(5) i = 0 for value in list_schema: if dbtype == sigdb: type_val = str(value[0])[1:3] schema_name = str(value[0])[4:] table_name = str(value[1][len(value[0]) + 1:]) if value[0] == value[1][:len(value[0])]: table_name = str(value[1][len(value[0]) + 1:]) else: table_name = str(value[1]) else: type_val = '' schema_name = str(value[0]) table_name = str(value[1]) if type_val == 'fo': type_val = str(value[0])[1:5] schema_name = str(value[0])[6:] if value[0] == value[1][:len(value[0])]: table_name = str(value[1][len(value[0]) + 1:]) else: table_name = str(value[1]) elif type_val == 'ra': type_val = 'travaux' schema_name = str(value[0]) table_name = str(value[1]) elif type_val != '00' and type_val != '01' and type_val != '07' and type_val != '26' and type_val != '42' and type_val != '69' and type_val != 'ra': type_val = 'agregation' schema_name = str(value[0]) table_name = str(value[1]) FavStatut = 0 if (schema_name + '.' + table_name) not in FavList: FAV = "mStarIconAdd.png" FavStatut = 0 else: FAV = "mStarIconDel.png" FavStatut = 1 iconFav = QIcon() iconFav.addPixmap(QtGui.QPixmap(resources_path('icons', FAV)), QIcon.Mode(0), QIcon.State(1)) self.FavButton = QPushButton(iconFav, "") self.FavButton.clicked.connect(self.AddOrDelToUserFav) if (str(value[0]) + '.' + str(value[1])) in RasterList: SVG = 'mIconRaster.svg' else: SVG = 'mIconVecteur.svg' itemIcon = QTableWidgetItem() icon = QIcon() icon.addPixmap(QtGui.QPixmap(resources_path('icons', SVG)), QIcon.Mode(0), QIcon.State(1)) itemIcon.setIcon(icon) self.tableWidget.setItem(i, 0, itemIcon) item = QTableWidgetItem(type_val) self.tableWidget.setItem(i, 1, item) item = QTableWidgetItem(schema_name) self.tableWidget.setItem(i, 2, item) item = QTableWidgetItem(table_name) self.tableWidget.setItem(i, 3, item) item = QTableWidgetItem(str(FavStatut)) self.tableWidget.setItem(i, 4, item) self.tableWidget.setCellWidget(i, 4, self.FavButton) # Coloration des lignes selon les droits d'accès if (str(value[0]) + '.' + str(value[1])) in GrandUser: pass # L'utilisateur a les droits else: # Coloration en violet si droits insuffisants for j in range(self.tableWidget.columnCount()): self.tableWidget.item(i, j).setBackground(QtGui.QColor(187, 134, 192, 50)) self.tableWidget.item(i, j).setToolTip('Droit insuffisant pour ouvrire la couche !') i = i + 1 if self.comboBox.currentText() == 'toutes les catégories': SQLprojects = """SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE tablename LIKE 'qgis_projects'""" else: SQLprojects = """SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE tablename LIKE 'qgis_projects' AND schemaname LIKE '""" + str(self.comboBox.currentText()) + """';""" cur.execute(SQLprojects) list_projects = cur.fetchall() list_projects_qgis = [] if len(list_projects) >= 1: for ProjectName in list_projects: SQLProjectsQgis = """SELECT name, metadata, content FROM """ + '"' + ProjectName[0] + '"."' + ProjectName[1] + '"' cur.execute(SQLProjectsQgis) list_projects_qgis = cur.fetchall() for Project in list_projects_qgis: FavStatut = 0 if (ProjectName[0] + '.' + Project[0]) not in FavList: FAV = "mStarIconAdd.png" FavStatut = 0 else: FAV = "mStarIconDel.png" FavStatut = 1 iconFav = QIcon() iconFav.addPixmap(QtGui.QPixmap(resources_path('icons', FAV)), QIcon.Mode(0), QIcon.State(1)) self.FavButton = QPushButton(iconFav, "") self.FavButton.clicked.connect(self.AddOrDelToUserFav) if dbtype == refdb: self.FavButton.setEnabled(False) self.tableWidget.setRowCount(i + 1) itemIcon = QTableWidgetItem() icon = QIcon() icon.addPixmap(QtGui.QPixmap(resources_path('icons', 'mIconQgis.svg')), QIcon.Mode(0), QIcon.State(1)) itemIcon.setIcon(icon) self.tableWidget.setItem(i, 0, itemIcon) item = QTableWidgetItem('qgis') self.tableWidget.setItem(i, 1, item) item = QTableWidgetItem(ProjectName[0]) self.tableWidget.setItem(i, 2, item) item = QTableWidgetItem(Project[0]) self.tableWidget.setItem(i, 3, item) item = QTableWidgetItem(str(FavStatut)) self.tableWidget.setItem(i, 4, item) self.tableWidget.setCellWidget(i, 4, self.FavButton) i = i + 1 self.tableWidget.setColumnWidth(0, 20) self.tableWidget.setColumnWidth(1, 70) self.tableWidget.setColumnWidth(2, 300) self.tableWidget.setColumnWidth(3, 300) self.tableWidget.setColumnWidth(4, 20) self.tableWidget.setHorizontalHeaderLabels(["Type", "Code", "Schema", "Table", "Favorit"]) if self.lineEdit.text() != 'Recherche par mots-clés': self.filtre_dynamique(self.lineEdit.text()) def selection_flux(self): """Ajoute une couche sélectionnée à la liste des flux à charger""" selected_row = 0 selected_items = self.tableWidget.selectedItems() new_item_text = selected_items[3].text() if not self.item_already_exists(new_item_text): self.tableWidget_2.insertRow(selected_row) for column in range(self.tableWidget.columnCount()): cloned_item = selected_items[column].clone() self.tableWidget_2.setHorizontalHeaderLabels(["Type", "Code", "Schema", "Table", "Favorit"]) self.tableWidget_2.setColumnCount(5) self.tableWidget_2.setItem(selected_row, column, cloned_item) self.tableWidget_2.setColumnWidth(0, 20) self.tableWidget_2.setColumnWidth(1, 70) self.tableWidget_2.setColumnWidth(2, 300) self.tableWidget_2.setColumnWidth(3, 300) self.tableWidget_2.setColumnWidth(4, 20) self.tableWidget_2.setColumnHidden(4, True) def item_already_exists(self, new_item_text): # Assuming you want to compare items in the first column for uniqueness existing_items = self.tableWidget_2.findItems(new_item_text, QtCore.Qt.MatchFlag(0)) # Check if there are any existing items with the same text in the first column return len(existing_items) > 0 def limite_flux(self): """Vérifie le nombre de flux à charger et affiche un avertissement si > 5""" # Avertissement si plus de 5 couches sélectionnées (risque de performance) if self.tableWidget_2.rowCount() > 5: self.QMBquestion = QMessageBox.question(iface.mainWindow(), u"Attention !", "Le nombre de flux à charger en une seule fois est limité à 5 pour des questions de performances. Souhaitez vous tout de même charger les " + str( self.tableWidget_2.rowCount()) + " flux sélectionnés ? (risque de plantage de QGIS)", QMessageBox.StandardButton(0x00004000) | QMessageBox.StandardButton(0x00010000)) if self.QMBquestion == QMessageBox.StandardButton(0x00004000): self.chargement_flux() if self.QMBquestion == QMessageBox.StandardButton(0x00001000): print("Annulation du chargement des couches") if self.tableWidget_2.rowCount() <= 5: self.chargement_flux() def chargement_flux(self): """Charge les couches sélectionnées dans QGIS""" managerAU = QgsApplication.authManager() managerAU.availableAuthMethodConfigs().keys() def REQUEST(type): switcher = { 'WFS': "GetFeature", 'WMS': "GetMap", 'WMS+Vecteur': "GetMap", 'WMS+Raster': "GetMap", 'WMTS': "GetMap" } return switcher.get(type, "nothing") # Vérification de la présence de l'extension PostGIS Raster SQLloadRaster = """SELECT concat(r_table_schema,'.',r_table_name) from public.raster_columns; """ SQLextension = """SELECT count(extname) FROM pg_catalog.pg_extension WHERE extname LIKE 'postgis_raster';""" cur.execute(SQLextension) count_extension = cur.fetchall()[0][0] if count_extension == 1: cur.execute(SQLloadRaster) list_raster = cur.fetchall() else: list_raster = [] RasterList = [] for rasterFind in list_raster: RasterList.append(rasterFind[0]) # Chargement de chaque couche sélectionnée for row in range(0, self.tableWidget_2.rowCount()): color_rgba_db = 855030089 # Code couleur pour couche dans autre BD color_rgba_droit = 851150528 # Code couleur pour droits insuffisants print(self.tableWidget_2.item(row, 1).background().color().rgba()) if self.tableWidget_2.item(row, 1).background().color().rgba() == color_rgba_droit: self.QMBquestion = QMessageBox.question(iface.mainWindow(), u"Attention !", "Vous ne disposez pas des droit pour la couche «" + str(self.tableWidget_2.item(row, 1).text()) + ' ' + str(self.tableWidget_2.item(row, 2).text()) + "» !", QMessageBox.StandardButton(0x00004000)) elif self.tableWidget_2.item(row, 1).background().color().rgba() != color_rgba_db: # supression de la partie de l'url après le point d'interrogation if dbtype == sigdb: code = self.tableWidget_2.item(row, 1).text() schema = '_' + code + '_' + self.tableWidget_2.item(row, 2).text() if code == 'travaux' or code == 'agregation': schema = self.tableWidget_2.item(row, 2).text() table = self.tableWidget_2.item(row, 3).text() elif code == '00': table = self.tableWidget_2.item(row, 3).text() else: table = self.tableWidget_2.item(row, 3).text() table = schema + '_' + table elif dbtype == refdb: code = self.tableWidget_2.item(row, 1).text() schema = self.tableWidget_2.item(row, 2).text() table = self.tableWidget_2.item(row, 3).text() # Configuration de l'URI de connexion PostGIS uri = QgsDataSourceUri() uri.setConnection(host, port, dbtype, user, mdp) # Chargement selon le type de couche (raster, vecteur ou projet QGIS) if (schema + '.' + table) in RasterList: # Chargement d'une couche raster uri.setDataSource(schema, table, "rast") uri.setKeyColumn('rid') # Clé primaire pour les rasters uri.setSrid('2154') # Lambert 93 layer = QgsRasterLayer(uri.uri(), table, "postgresraster") QgsProject.instance().addMapLayer(layer) elif code == 'qgis': # Chargement d'un projet QGIS stocké dans la base de données schema = self.tableWidget_2.item(row, 2).text() print(schema) table = self.tableWidget_2.item(row, 3).text() uri_project = 'postgresql://' + user + ':' + mdp + '@' + host + ':' + port + '?sslmode=disable&dbname=' + dbtype + "&schema=" + schema + '&project=' + table QgsProject.instance().read(uri_project) else: # Chargement d'une couche vecteur uri.setDataSource(schema, table, "geom") # Colonne géométrie uri.setKeyColumn('gid') # Clé primaire # Détection du type de géométrie geom_type = 'SELECT right(st_geometrytype(geom),-3) as a FROM ' + schema + '.' + table + ' GROUP BY a' cur.execute(geom_type) list_typegeom = cur.fetchall() if len(list_typegeom) > 1: for typegeom in list_typegeom: if typegeom[0] == 'MultiPolygon': uri.setWkbType(QgsWkbTypes.MultiPolygon) elif typegeom[0] == 'MultiLineString': uri.setWkbType(QgsWkbTypes.MultiLineString) elif typegeom[0] == 'Point': uri.setWkbType(QgsWkbTypes.Point) if typegeom[0] == 'Polygon': uri.setWkbType(QgsWkbTypes.Polygon) elif typegeom[0] == 'LineString': uri.setWkbType(QgsWkbTypes.LineString) elif typegeom[0] == 'MultiPoint': uri.setWkbType(QgsWkbTypes.MultiPoint) if (typegeom[0] is not None and typegeom[0] != 'Polygon'): uri.setSrid('2154') layer = QgsVectorLayer(uri.uri(), table, "postgres") # Ajout de la couche au canevas QGIS QgsProject.instance().addMapLayer(layer) else: layer = QgsVectorLayer(uri.uri(), table, "postgres") # Ajout de la couche au canevas QGIS QgsProject.instance().addMapLayer(layer) else: self.QMBquestion = QMessageBox.question(iface.mainWindow(), u"Attention !", "La couche «" + str(self.tableWidget_2.item(row, 1).text()) + ' ' + str(self.tableWidget_2.item(row, 2).text()) + "» ne ce trouve pas dans cette BD !", QMessageBox.StandardButton(0x00004000)) def combobox_custom(self): """Remplit la liste déroulante des catégories selon la base de données sélectionnée""" global NoSignals NoSignals = 1 # Désactive temporairement les signaux pour éviter les boucles if dbtype == sigdb: self.toolButton.setEnabled(1) self.comboBox.clear() self.comboBox.addItem("toutes les catégories") self.comboBox.addItem('00') self.comboBox.addItem('01') self.comboBox.addItem('07') self.comboBox.addItem('26') self.comboBox.addItem('42') self.comboBox.addItem('69') self.comboBox.addItem('agregation') self.comboBox.addItem('travaux') self.comboBox.addItem('qgis') self.comboBox.addItem('form') if dbtype == refdb: self.toolButton.setEnabled(0) custom_list = schemaname_distinct cur.execute(custom_list) list_schema = cur.fetchall() self.comboBox.clear() self.comboBox.addItem("toutes les catégories") for baxval in list_schema: self.comboBox.addItem(baxval[0]) NoSignals = 0 def filtre_favorit(self, filter_fav): """Active ou désactive le filtre des favoris""" if self.toolButton_2.text() == "0": # Activation du filtre self.toolButton_2.setText("1") self.toolButton_2.setDown(True) if self.lineEdit.text() != 'Recherche par mots-clés': self.filtre_dynamique(self.lineEdit.text()) else: for i in range(self.tableWidget.rowCount()): item = self.tableWidget.item(i, 4) match = self.toolButton_2.text() not in item.text().lower() self.tableWidget.setRowHidden(i, match) elif self.toolButton_2.text() == "1": self.toolButton_2.setText("0") self.toolButton_2.setDown(False) if self.lineEdit.text() != 'Recherche par mots-clés': self.filtre_dynamique(self.lineEdit.text()) else: for i in range(self.tableWidget.rowCount()): self.tableWidget.setRowHidden(i, False) def filtre_dynamique(self, filter_text): """Filtre dynamique des couches selon le texte saisi""" # Remplacement des espaces par des underscores pour la recherche if filter_text.find(' ') >= 0: filter_text = filter_text.replace(" ", "_") for i in range(self.tableWidget.rowCount()): for j in range(self.tableWidget.columnCount()): item = self.tableWidget.item(i, j) match = filter_text.lower() not in item.text().lower() if match is False: if self.toolButton_2.text() == "1": item = self.tableWidget.item(i, 4) match = self.toolButton_2.text() not in item.text().lower() self.tableWidget.setRowHidden(i, match) if not match: break def getCanevas(self): """Filtre les couches selon l'emprise du canevas QGIS actuel""" # Récupération de la liste des favoris de l'utilisateur SQLFavTable = "SELECT concat(schema_name, '.', table_name) FROM admin_sig.favtable WHERE utilisateur LIKE '" + user + "';" if dbtype == refdb: conSIG = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + sigdb + " user=" + user + " password=" + mdp) curSIG = conSIG.cursor(cursor_factory=psycopg2.extras.DictCursor) curSIG.execute(SQLFavTable) list_fav = curSIG.fetchall() conSIG.close() else: cur.execute(SQLFavTable) list_fav = cur.fetchall() FavList = [] for favFind in list_fav: FavList.append(favFind[0]) # Récupération de l'emprise du canevas poly = iface.mapCanvas().extent() geom = (str(poly.xMinimum()) + ',' + str(poly.yMinimum()) + ',' + str(poly.xMaximum()) + ',' + str(poly.yMaximum())) SQL_GEOM_CONTOUR = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_contour" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname" SQL_GEOM_HABITAT = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_habitat" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname" SQL_GEOM_EU_HABITAT = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_eu_habitat" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname" SQL_GEOM_TRAVAUX_PREVUS_LIGNE = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_travaux_prevus_ligne" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname" SQL_GEOM_TRAVAUX_PREVUS_POINT = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_travaux_prevus_point" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname" SQL_GEOM_TRAVAUX_PREVUS_POLY = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_travaux_prevus_poly" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname" cur.execute(SQL_GEOM_CONTOUR) TableContour = cur.fetchall() cur.execute(SQL_GEOM_HABITAT) TableHabitat = cur.fetchall() cur.execute(SQL_GEOM_EU_HABITAT) TableEuHabitat = cur.fetchall() cur.execute(SQL_GEOM_TRAVAUX_PREVUS_LIGNE) TableTravauxLigne = cur.fetchall() cur.execute(SQL_GEOM_TRAVAUX_PREVUS_POINT) TableTravauxPoint = cur.fetchall() cur.execute(SQL_GEOM_TRAVAUX_PREVUS_POLY) TableTravauxPoly = cur.fetchall() TableHaveGeom = sorted(TableContour + TableHabitat + TableEuHabitat + TableTravauxLigne + TableTravauxPoint + TableTravauxPoly) row_count = 0 self.tableWidget.setRowCount(0) for e in TableHaveGeom: cur.execute("""SELECT DISTINCT count(*) FROM pg_catalog.pg_tables WHERE schemaname LIKE '""" + e[0] + """' AND tablename LIKE '""" + e[1] + """';""") TableSomme = cur.fetchall()[0][0] if e[0][1:3] != 'fo': schema_name = e[0][4:] DepName = QTableWidgetItem(e[0][1:3]) SchemaName = QTableWidgetItem(schema_name) else: schema_name = e[0][6:] DepName = QTableWidgetItem('form') SchemaName = QTableWidgetItem(schema_name) table_name = e[1][len(e[0]) + 1:] TableName = QTableWidgetItem(table_name) FavStatut = 0 if (schema_name + '.' + table_name) not in FavList: FAV = "mStarIconAdd.png" FavStatut = 0 else: FAV = "mStarIconDel.png" FavStatut = 1 iconFav = QIcon() iconFav.addPixmap(QtGui.QPixmap(resources_path('icons', FAV)), QIcon.Mode(0), QIcon.State(1)) self.FavButton = QPushButton(iconFav, "") self.FavButton.clicked.connect(self.AddOrDelToUserFav) self.tableWidget.insertRow(row_count) itemIcon = QTableWidgetItem() icon = QIcon() icon.addPixmap(QtGui.QPixmap(resources_path('icons', 'mIconVecteur.svg')), QIcon.Mode(0), QIcon.State(1)) itemIcon.setIcon(icon) self.tableWidget.setItem(row_count, 0, itemIcon) self.tableWidget.setItem(row_count, 1, DepName) self.tableWidget.setItem(row_count, 2, SchemaName) self.tableWidget.setItem(row_count, 3, TableName) item = QTableWidgetItem(str(FavStatut)) self.tableWidget.setItem(row_count, 4, item) self.tableWidget.setCellWidget(row_count, 4, self.FavButton) if TableSomme == 0: for j in range(self.tableWidget.columnCount()): self.tableWidget.item(row_count, j).setBackground(QtGui.QColor(246, 185, 73, 50)) self.tableWidget.item(row_count, j).setToolTip('Couche dans une autre BD !') row_count = row_count + 1 if self.lineEdit.text() != 'Recherche par mots-clés': self.filtre_dynamique(self.lineEdit.text()) def SwitchGeom(self, vargeom): new_object = '[' obj = vargeom['coordinates'][0][0] for obj_X in obj: new_object = new_object + '[' + str(obj_X[1]) + ',' + str(obj_X[0]) + '],' new_object = new_object[:-1] + ']' return (new_object)