# -*- 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 import os 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: if os.path.exists('N:'): 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 = schemaname_list[:-2] + """ WHERE schemaname LIKE '""" + str(self.comboBox.currentText()) + """%'; """ else: custom_list = schemaname_list[:-2] + """ WHERE schemaname LIKE '_""" + str(self.comboBox.currentText()) + """%'; """ else: if self.comboBox.currentText() == 'toutes les catégories': custom_list = schemaname_list_ref else: custom_list = schemaname_list_ref[:-2] + """ WHERE schemaname LIKE '""" + str(self.comboBox.currentText()) + """%' AND tablename NOT LIKE 'qgis_projects'; """ 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 SQLGrands = """ WITH t as (SELECT n.nspname AS table_schema, c.relname AS table_name, r.rolname AS grantee, CASE WHEN acl_text LIKE '%r%' THEN 'SELECT' WHEN acl_text LIKE '%w%' THEN 'UPDATE' WHEN acl_text LIKE '%a%' THEN 'INSERT' WHEN acl_text LIKE '%d%' THEN 'DELETE' WHEN acl_text LIKE '%x%' THEN 'REFERENCES' ELSE 'OTHER' END AS privilege_type FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace LEFT JOIN LATERAL unnest(c.relacl) AS acl_item(acl) ON TRUE LEFT JOIN LATERAL ( SELECT acl::text AS acl_text, split_part(acl::text, '=', 1) AS grantee_name ) priv ON TRUE LEFT JOIN pg_roles r ON r.rolname = priv.grantee_name WHERE c.relkind IN ('r', 'v','m')) """ if self.comboBox.currentText() == 'toutes les catégories': SQLGrands = SQLGrands + """SELECT concat(table_schema,'.',table_name) FROM t 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 = SQLGrands + """SELECT concat(table_schema,'.',table_name) FROM t 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 = SQLGrands + """SELECT concat(table_schema,'.',table_name) FROM t 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: MetadataXML = value[2] 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]) if type_val == "00": table_name = 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: # L'utilisateur a les droits for j in range(self.tableWidget.columnCount()): self.tableWidget.item(i, j).setToolTip(MetadataXML) 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 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() 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)