# -*- coding: utf-8 -*- from __future__ import absolute_import # Import the PyQt and QGIS libraries from builtins import next from builtins import str from builtins import object import qgis from qgis.PyQt import QtCore from qgis.PyQt.QtCore import QSettings from qgis.PyQt import QtWidgets from qgis.PyQt.QtWidgets import QAction, QMenu, QDialog from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import * from qgis.PyQt.QtGui import * from qgis.PyQt import QtGui from qgis.core import * from qgis.core import QgsDataSourceUri from qgis.PyQt.QtWidgets import ( QDialog, QAction, QDockWidget, QFileDialog, QInputDialog, QMenu, QToolButton, QTableWidget, QTableWidgetItem, QMessageBox, QVBoxLayout, ) from .tools.SQLRequet import * from .tools.resources import ( load_ui, resources_path, send_issues, ) try: from .tools.PythonSQL import login_base except: print('Pas de fichier PythonSQL') from .issues import CenRa_Issues from ast import literal_eval from qgis.utils import iface import os.path import webbrowser, os import psycopg2 import psycopg2.extras import base64 global DeBUG DeBUG = 0 try: account = login_base('account') user = account[0] mdp = account[1] host = account[2] port = account[3] dbname = account[4] sigdb = account[5] refdb = account[6] except: print('') EDITOR_CLASS = load_ui('CenRa_Flux_base.ui') html = '''
''' targetCrs = QgsCoordinateReferenceSystem('EPSG:4326') layerCrs = QgsCoordinateReferenceSystem('EPSG:2154') TranformCRS = QgsCoordinateTransform(layerCrs, targetCrs,QgsProject.instance()) class Flux_Editor(QDialog, EDITOR_CLASS): def __init__(self, parent=None): _ = 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 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'))) #self.tableWidget.setSelectionBehavior(QTableWidget.selectRow) self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger(0)) self.toolButton.setIcon(QtGui.QIcon(resources_path('ui','find.png'))) self.comboBox_2.addItem("SIG") self.comboBox_2.addItem('REF') self.comboBox.currentIndexChanged.connect(self.initialisation_flux) self.commandLinkButton.clicked.connect(self.selection_flux) self.tableWidget.itemDoubleClicked.connect(self.selection_flux) self.pushButton_2.clicked.connect(self.limite_flux) self.commandLinkButton_2.clicked.connect(self.suppression_flux) self.tableWidget_2.itemDoubleClicked.connect(self.suppression_flux) self.comboBox_2.currentIndexChanged.connect(self.bd_source) self.checkBox.hide() self.checkBox.stateChanged.connect(self.modeCarte) self.toolButton.clicked.connect(self.getCanevas) layout = QVBoxLayout() self.lineEdit.textChanged.connect(self.filtre_dynamique) self.viewer.textChanged.connect(self.NewTitle) layout.addWidget(self.lineEdit) self.viewer.hide() self.DeBUG.addItem('') self.DeBUG.addItem('01') self.DeBUG.addItem('0726') self.DeBUG.addItem('4269') self.DeBUG.hide() #self.lineEdit.mousePressEvent = self._mousePressEvent #metadonnees_plugin = open(self.plugin_path + '/metadata.txt') #infos_metadonnees = metadonnees_plugin.readlines() def raise_(self): """Run method that performs all the real work""" self.bd_source() def ModeDeBUG(self): self.DeBUG.show() def mousePressEvent(self, event): global DeBUG if 330 <= event.pos().x() <= 560 and 5 <= event.pos().y() <= 75: DeBUG = DeBUG+1 if DeBUG == 3: DeBUG = 0 self.ModeDeBUG() else: DeBUG = 0 self.DeBUG.hide() def NewTitle(self): if self.viewer.title() != '': Tsplit = ((self.viewer.title()).split('.')) print(Tsplit[0],Tsplit[1]) self.openPostGIS(Tsplit[0],Tsplit[1]) def modeCarte(self): if self.checkBox.isChecked(): self.viewer.show() cur.execute("SELECT ST_AsGeoJSON(st_centroid(ST_Transform(geom,4326))) FROM _agregation_ra._agreg_contour") varcenter = literal_eval(cur.fetchall()[0][0]) varcenter = [varcenter['coordinates'][1],varcenter['coordinates'][0]] cur.execute("SELECT ST_AsGeoJSON(ST_Transform(st_collect(geom),4326)),tschema,tname FROM _agregation_ra._agreg_contour WHERE geom IS NOT NULL GROUP BY tschema,tname;" ) varSite = cur.fetchall() cur.execute("SELECT ST_AsGeoJSON(ST_Transform(st_collect(geom),4326)),tschema,tname FROM _agregation_ra._agreg_travaux_prevus_poly WHERE geom IS NOT NULL GROUP BY tschema,tname;") varTravaux = cur.fetchall() cur.execute("SELECT ST_AsGeoJSON(ST_Transform(geom,4326)),milieu_libelle ,lb_eu_01,tschema,tname FROM _agregation_ra._agreg_eu_habitat WHERE geom IS NOT NULL;") varHabitat = cur.fetchall() vargeomS = literal_eval(varSite[0][0]) vargeomT = literal_eval(varTravaux[0][0]) vargeomH = literal_eval(varHabitat[0][0]) #new_objectS = self.SwitchGeom(vargeomS) #new_objectT = self.SwitchGeom(vargeomT) #new_objectH = self.SwitchGeom(vargeomH) script = 'var map = L.map("map").setView('+str(varcenter)+', 13);' id = 0 varSiteJSON = '''var ParcelleJSON = { "type": "FeatureCollection", "features":[''' for varP in varSite: id = id+1 varSiteJSON = varSiteJSON+'{"properties": {"code": "'+str(varP[1])+'.'+str(varP[2])+'" },'+str(varP[0][1:])+',' varSiteJSON = varSiteJSON[:-1]+''']}; var Sites = L.geoJSON(ParcelleJSON,{ style: function(feature) { switch (feature.geometry.properties.code) { case 'Ensemble de sites': return {fillColor: "#9a7863",color:"white",weight: 1,fillOpacity: 0.7}; case 'Sous-site conservatoire': return {fillColor: "#e69800",color:"white",weight: 1,fillOpacity: 0.7}; case 'Site non géré': return {fillColor: "#73004c",color:"white",weight: 1,fillOpacity: 0.7}; case 'Animation territoriale': return {fillColor: "#ffebaf",color:"white",weight: 1,fillOpacity: 0.7}; case 'Site conservatoire': return {fillColor: "#f9ff08",color:"white",weight: 1,fillOpacity: 0.7}; default: return {fillColor: "#c8c8c8",color:"white",weight: 1,fillOpacity: 0.7}; } }, onEachFeature: function (feature,layer) { layer.on('click', function(e) { map.fitBounds(layer.getBounds()); document.title = feature.properties.code.toString(); }); layer.on('mouseover', function(e) { layer.setStyle({ weight: 5, color: '#fe0000', dashArray: '', }); }); //layer.on('mousemove', function(e) { //layer.openPopup(e.latlng); //}); layer.on('mouseout', function(e) { layer.setStyle({ color:"white", weight: 1, }); }); layer.bindTooltip(feature.properties.code.toString(), { sticky: true, permanent: false, direction: 'right', className: 'label_parc' }); } }).addTo(map);''' id = 0 varTravauxJSON = '''var TravauxJSON = { "type": "FeatureCollection", "features":[''' for varT in varTravaux: id = id+1 varTravauxJSON = varTravauxJSON+'{"properties": {"code": "'+str(varT[1])+'.'+str(varT[2])+'" },'+str(varT[0][1:])+',' varTravauxJSON = varTravauxJSON[:-1]+''']}; var Travaux = L.geoJSON(TravauxJSON,{ onEachFeature: function (feature,layer) { layer.on('click', function(e) { map.fitBounds(layer.getBounds()); document.title = feature.properties.code.toString(); }); layer.on('mouseover', function(e) { layer.setStyle({ weight: 5, color: '#fe0000', dashArray: '', }); }); //layer.on('mousemove', function(e) { //layer.openPopup(e.latlng); //}); layer.on('mouseout', function(e) { layer.setStyle({ color:"white", weight: 1, }); }); layer.bindTooltip(feature.properties.code.toString(), { sticky: true, permanent: false, direction: 'right', className: 'label_parc' }); } }).addTo(map);''' script = script+varSiteJSON+varTravauxJSON self.viewer.setHtml(html+script+font) else: self.viewer.hide() def bd_source(self): self.activateWindow() bd_origine=self.comboBox_2.currentText() if bd_origine == 'REF': self.run_ref() if bd_origine == 'SIG': self.run_sig() def run_ref(self): """Run method that performs all the real work""" while self.tableWidget_2.rowCount() > 0: self.tableWidget_2.removeRow(self.tableWidget_2.rowCount()-1) # print(self.tableWidget_2.rowCount()) global cur,con,dbtype dbtype=refdb con = psycopg2.connect("host=" + host + " port=" + port + " dbname="+dbtype+" user=" + user + " password=" + mdp) cur = con.cursor(cursor_factory = psycopg2.extras.DictCursor) self.initialisation_flux() self.combobox_custom() # 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 == True: self.first_start = False # show the dialog self.show() # Run the dialog event loop result = self.exec() # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass def run_sig(self): """Run method that performs all the real work""" while self.tableWidget_2.rowCount() > 0: self.tableWidget_2.removeRow(self.tableWidget_2.rowCount()-1) global cur,con,dbtype dbtype=sigdb con = psycopg2.connect("host=" + host + " port=" + port + " dbname="+dbtype+" user=" + user + " password=" + mdp) cur = con.cursor(cursor_factory = psycopg2.extras.DictCursor) self.initialisation_flux() self.combobox_custom() # 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 == True: self.first_start = False # show the dialog self.show() # Run the dialog event loop result = self.exec() # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass def suppression_flux(self): self.tableWidget_2.removeRow(self.tableWidget_2.currentRow()) def open_url(self, item): url = item.data(Qt.UserRole) def initialisation_flux(self): if dbtype == sigdb: # self.toolButton.setEnabled(1) 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()) +"""' order by schemaname,tablename;""" cur.execute(custom_list) list_schema = cur.fetchall() self.tableWidget.setRowCount(len(list_schema)) self.tableWidget.setColumnCount(3) 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]) item = QTableWidgetItem(type_val) self.tableWidget.setItem(i,0,item) item = QTableWidgetItem(schema_name) self.tableWidget.setItem(i,1,item) item = QTableWidgetItem(table_name) self.tableWidget.setItem(i,2,item) i=i+1 self.tableWidget.setColumnWidth(0, 20) self.tableWidget.setColumnWidth(1, 300) self.tableWidget.setColumnWidth(2, 300) self.tableWidget.setHorizontalHeaderLabels(["Code","Schema","Table"]) def selection_flux(self): selected_row = 0 selected_items = self.tableWidget.selectedItems() # Assuming you want to compare items in the first column for uniqueness new_item_text = selected_items[2].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(["Code","Schema", "Table"]) self.tableWidget_2.setColumnCount(3) self.tableWidget_2.setItem(selected_row, column, cloned_item) self.tableWidget_2.setColumnWidth(0, 50) self.tableWidget_2.setColumnWidth(1, 300) self.tableWidget_2.setColumnWidth(2, 300) 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): 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.Yes | QMessageBox.No) if self.QMBquestion == QMessageBox.Yes: self.chargement_flux() if self.QMBquestion == QMessageBox.No: print("Annulation du chargement des couches") if self.tableWidget_2.rowCount() <= 5: self.chargement_flux() def openPostGIS(self,schema,table): uri = QgsDataSourceUri() uri.setConnection(host ,port ,sigdb ,user ,mdp) uri.setDataSource(schema, table, "geom") uri.setKeyColumn('gid') uri.setSrid('2154') layer = QgsVectorLayer(uri.uri(), table, "postgres") # Ajout de la couche au canevas QGIS QgsProject.instance().addMapLayer(layer) def chargement_flux(self): managerAU = QgsApplication.authManager() k = managerAU.availableAuthMethodConfigs().keys() def REQUEST(type): switcher = { 'WFS': "GetFeature", 'WMS': "GetMap", 'WMS+Vecteur': "GetMap", 'WMS+Raster': "GetMap", 'WMTS': "GetMap" } return switcher.get(type, "nothing") def displayOnWindows(type, uri, name): p = [] for row in range(0, self.tableWidget_2.rowCount()): color_rgba = 855030089 if self.tableWidget_2.item(row, 0).background().color().rgba() != 855030089: ## supression de la partie de l'url après le point d'interrogation if dbtype == sigdb: code = self.tableWidget_2.item(row,0).text() schema = '_'+code+'_'+self.tableWidget_2.item(row,1).text() if code == 'travaux' or code == 'agregation': schema = self.tableWidget_2.item(row,1).text() table = self.tableWidget_2.item(row,2).text() else: table = self.tableWidget_2.item(row,2).text() table = schema+'_'+table if dbtype == refdb: # code = self.tableWidget_2.item(row,0).text() schema = self.tableWidget_2.item(row,1).text() table = self.tableWidget_2.item(row,2).text()#.split("?", 1)[0] uri = QgsDataSourceUri() uri.setConnection(host ,port ,dbtype ,user ,mdp) # nom du schéma à remplacer: "hydrographie" à supprimer et mettre "couches_collaboratives" lorsqu'on aura regroupé les couches à modifier dans un même schéma uri.setDataSource(schema, table, "geom") uri.setKeyColumn('gid') # Chargement de la couche PostGIS 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] != 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.Yes) def combobox_custom(self): 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('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]) def filtre_dynamique(self, filter_text): 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() self.tableWidget.setRowHidden(i, match) if not match: break def getCanevas(self): 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': DepName = QTableWidgetItem(e[0][1:3]) SchemaName = QTableWidgetItem(e[0][4:]) else: DepName = QTableWidgetItem('form') SchemaName = QTableWidgetItem(e[0][6:]) TableName = QTableWidgetItem(e[1][len(e[0])+1:]) self.tableWidget.insertRow(row_count) self.tableWidget.setItem(row_count,0,DepName) self.tableWidget.setItem(row_count,1,SchemaName) self.tableWidget.setItem(row_count,2,TableName) 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) def popup(self): self.dialog = Popup() # +++ - self self.dialog.text_edit.show()