forked from CEN-RA/Plugin_QGIS
938 lines
43 KiB
Python
938 lines
43 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
/***************************************************************************
|
|
FluxCEN
|
|
A QGIS plugin
|
|
Centralisation des flux WFS/WMS utilisés au CEN NA
|
|
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
|
|
-------------------
|
|
begin : 2022-03-23
|
|
git sha : $Format:%H$
|
|
copyright : (C) 2022 by Romain MONTILLET
|
|
email : r.montillet@cen-na.org
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
"""
|
|
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication, Qt, QUrl
|
|
from qgis.PyQt.QtGui import *
|
|
from qgis.PyQt.QtWidgets import *
|
|
from PyQt5 import *
|
|
|
|
# Initialize Qt resources from file resources.py
|
|
from .resources import *
|
|
# Import the code for the dialog
|
|
from .FluxCEN_dialog import FluxCENDialog
|
|
import os.path, os, shutil
|
|
from qgis.core import *
|
|
from qgis.gui import *
|
|
from qgis.utils import *
|
|
from .forms.about_form import FluxAboutDialog
|
|
import qgis
|
|
import processing
|
|
import psycopg2
|
|
import psycopg2.extras
|
|
from PyQt5.QtXml import QDomDocument
|
|
import csv
|
|
import os
|
|
import io
|
|
import re
|
|
import random
|
|
# Deal with SSL
|
|
import ssl
|
|
import urllib
|
|
from urllib import request, parse
|
|
import socket
|
|
import json
|
|
import requests
|
|
import base64
|
|
|
|
ssl._create_default_https_context = ssl._create_unverified_context
|
|
from PyQt5 import QtGui
|
|
from .tools.resources import maj_verif
|
|
from .tools.PythonSQL import *
|
|
first_conn = psycopg2.connect("host=" + host + " port=" + port + " dbname="+dbname+" user=first_cnx password=" + password)
|
|
first_cur = first_conn.cursor(cursor_factory = psycopg2.extras.DictCursor)
|
|
first_cur.execute("SELECT mdp_w, login_w FROM pg_catalog.pg_user t1, admin_sig.vm_users_sig t2 WHERE t2.oid = t1.usesysid AND (login_w = '" + os_user + "' OR login_w = '" + os_user + "')")
|
|
res_ident = first_cur.fetchone()
|
|
mdp = base64.b64decode(str(res_ident[0])).decode('utf-8')
|
|
user = res_ident[1]
|
|
#con = psycopg2.connect("host=" + host + " port=" + port + " dbname="+dbname+" user=" + user + " password=" + mdp)
|
|
#cur = con.cursor(cursor_factory = psycopg2.extras.DictCursor)
|
|
#from .HubToTea import gitea
|
|
#gitea()
|
|
first_conn.close()
|
|
|
|
|
|
'''
|
|
# Vérifier la connexion à internet
|
|
try:
|
|
# Vérifier si l'utilisateur est connecté à internet en ouvrant une connexion avec un site web
|
|
host = socket.gethostbyname("www.google.com")
|
|
s = socket.create_connection((host, 80), 2)
|
|
s.close()
|
|
except socket.error:
|
|
# Afficher un message si l'utilisateur n'est pas connecté à internet
|
|
QMessageBox.warning(None, 'Avertissement',
|
|
'Vous n\'êtes actuellement pas connecté à internet. Veuillez vous connecter pour pouvoir utiliser FluxCEN !')
|
|
'''
|
|
|
|
class Flux:
|
|
def __init__(self, t, c, nc, l, u, p):
|
|
self.type = t
|
|
self.category = c
|
|
self.nom_commercial = nc
|
|
self.layer = l
|
|
self.url = u
|
|
self.parameters = p
|
|
maj_verif('CenRa_FLUX')
|
|
|
|
|
|
class Popup(QWidget):
|
|
def __init__(self, parent=None):
|
|
super(Popup, self).__init__(parent)
|
|
|
|
self.plugin_dir = os.path.dirname(__file__)
|
|
|
|
self.text_edit = QTextBrowser()
|
|
fp = urllib.request.urlopen("https://raw.githubusercontent.com/CEN-Nouvelle-Aquitaine/fluxcen/main/info_changelog.html")
|
|
mybytes = fp.read()
|
|
html_changelog = mybytes.decode("utf8")
|
|
fp.close()
|
|
|
|
self.text_edit.setHtml(html_changelog)
|
|
self.text_edit.setFont(QtGui.QFont("Calibri",weight=QtGui.QFont.Bold))
|
|
self.text_edit.anchorClicked.connect(QtGui.QDesktopServices.openUrl)
|
|
self.text_edit.setOpenLinks(False)
|
|
|
|
self.text_edit.setWindowTitle("Nouveautés")
|
|
self.text_edit.setMinimumSize(600,450)
|
|
|
|
class FluxCEN:
|
|
"""QGIS Plugin Implementation."""
|
|
|
|
def __init__(self, iface):
|
|
"""Constructor.
|
|
|
|
:param iface: An interface instance that will be passed to this class
|
|
which provides the hook by which you can manipulate the QGIS
|
|
application at run time.
|
|
:type iface: QgsInterface
|
|
"""
|
|
# Save reference to the QGIS interface
|
|
self.iface = iface
|
|
# initialize plugin directory
|
|
self.plugin_dir = os.path.dirname(__file__)
|
|
# initialize locale
|
|
#print(QSettings().value('locale/userLocale'))
|
|
locale = QSettings().value('locale/userLocale')[0:2]
|
|
locale_path = os.path.join(
|
|
self.plugin_dir,
|
|
'i18n',
|
|
'FluxCEN_{}.qm'.format(locale))
|
|
version = qgis.utils.pluginMetadata('CenRa_FLUX','version')
|
|
# Display About window on first use
|
|
s = QSettings()
|
|
versionUse = s.value("flux/version", 1, type=str)
|
|
if str(versionUse) != str(version) :
|
|
s.setValue("flux/version", str(version))
|
|
self.open_about_dialog()
|
|
|
|
if os.path.exists(locale_path):
|
|
self.translator = QTranslator()
|
|
self.translator.load(locale_path)
|
|
QCoreApplication.installTranslator(self.translator)
|
|
|
|
# Declare instance attributes
|
|
self.actions = []
|
|
self.menu = self.tr(u'&FluxCEN')
|
|
self.dlg = FluxCENDialog()
|
|
self.plugin_path = os.path.dirname(__file__)
|
|
|
|
# Check if plugin was started the first time in current QGIS session
|
|
# Must be set in initGui() to survive plugin reloads
|
|
self.first_start = None
|
|
|
|
self.dlg.tableWidget.setSelectionBehavior(QTableWidget.SelectRows)
|
|
self.dlg.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
|
|
|
self.dlg.comboBox_2.addItem("SIG")
|
|
self.dlg.comboBox_2.addItem('REF')
|
|
# self.dlg.comboBox.addItem('07')
|
|
# self.dlg.comboBox.addItem('26')
|
|
# self.dlg.comboBox.addItem('42')
|
|
# self.dlg.comboBox.addItem('69')
|
|
# self.dlg.comboBox.addItem('form')
|
|
|
|
self.dlg.comboBox.currentIndexChanged.connect(self.initialisation_flux)
|
|
self.dlg.commandLinkButton.clicked.connect(self.selection_flux)
|
|
self.dlg.tableWidget.itemDoubleClicked.connect(self.selection_flux)
|
|
self.dlg.pushButton_2.clicked.connect(self.limite_flux)
|
|
self.dlg.commandLinkButton_2.clicked.connect(self.suppression_flux)
|
|
self.dlg.tableWidget_2.itemDoubleClicked.connect(self.suppression_flux)
|
|
self.dlg.comboBox_2.currentIndexChanged.connect(self.bd_source)
|
|
#self.dlg.commandLinkButton_3.clicked.connect(self.option_OSM)
|
|
#self.dlg.commandLinkButton_4.clicked.connect(self.option_google_maps)
|
|
|
|
#self.dlg.commandLinkButton_5.clicked.connect(self.popup)
|
|
# iface.mapCanvas().extentsChanged.connect(self.test5)
|
|
|
|
# url_open = urllib.request.urlopen("https://raw.githubusercontent.com/CEN-Rhone-Alpes/Plugin_QGIS/main/flux.csv")
|
|
# colonnes_flux = csv.DictReader(io.TextIOWrapper(url_open, encoding='utf8'), delimiter=';')
|
|
|
|
#mots_cles = [row["categorie"] for row in colonnes_flux if row["categorie"]]
|
|
#categories = list(set(mots_cles))
|
|
#categories.sort()
|
|
|
|
#self.dlg.comboBox.addItems(categories)
|
|
layout = QVBoxLayout()
|
|
self.dlg.lineEdit.textChanged.connect(self.filtre_dynamique)
|
|
layout.addWidget(self.dlg.lineEdit)
|
|
self.dlg.lineEdit.mousePressEvent = self._mousePressEvent
|
|
|
|
metadonnees_plugin = open(self.plugin_path + '/metadata.txt')
|
|
infos_metadonnees = metadonnees_plugin.readlines()
|
|
|
|
# derniere_version = urllib.request.urlopen("https://sig.dsi-cen.org/qgis/downloads/last_version_fluxcen.txt")
|
|
# num_last_version = derniere_version.readlines()[0].decode("utf-8")
|
|
|
|
# Connect the itemClicked signal to the open_url function
|
|
#self.dlg.tableWidget.itemClicked.connect(self.open_url)
|
|
|
|
# version_utilisateur = infos_metadonnees[8].splitlines()
|
|
|
|
# if infos_metadonnees[8].splitlines() == num_last_version.splitlines():
|
|
# iface.messageBar().pushMessage("Plugin à jour", "Votre version de FluxCEN %s est à jour !" %version_utilisateur, level=Qgis.Success, duration=5)
|
|
# else:
|
|
# iface.messageBar().pushMessage("Information :", "Une nouvelle version de FluxCEN est disponible, veuillez mettre à jour le plugin !", level=Qgis.Info, duration=120)
|
|
|
|
def open_about_dialog(self):
|
|
dialog = FluxAboutDialog(self.iface)
|
|
dialog.exec_()
|
|
|
|
def _mousePressEvent(self, event):
|
|
self.dlg.lineEdit.setText("")
|
|
self.dlg.lineEdit.mousePressEvent = None
|
|
|
|
# noinspection PyMethodMayBeStatic
|
|
def tr(self, message):
|
|
"""Get the translation for a string using Qt translation API.
|
|
|
|
We implement this ourselves since we do not inherit QObject.
|
|
|
|
:param message: String for translation.
|
|
:type message: str, QString
|
|
|
|
:returns: Translated version of message.
|
|
:rtype: QString
|
|
"""
|
|
# noinspection PyTypeChecker,PyArgumentList,PyCallByClass
|
|
return QCoreApplication.translate('FluxCEN', message)
|
|
|
|
|
|
def add_action(
|
|
self,
|
|
icon_path,
|
|
text,
|
|
callback,
|
|
dbtype=None,
|
|
enabled_flag=True,
|
|
add_to_menu=True,
|
|
add_to_toolbar=True,
|
|
status_tip=None,
|
|
whats_this=None,
|
|
parent=None):
|
|
"""Add a toolbar icon to the toolbar.
|
|
|
|
:param icon_path: Path to the icon for this action. Can be a resource
|
|
path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
|
|
:type icon_path: str
|
|
|
|
:param text: Text that should be shown in menu items for this action.
|
|
:type text: str
|
|
|
|
:param callback: Function to be called when the action is triggered.
|
|
:type callback: function
|
|
|
|
:param enabled_flag: A flag indicating if the action should be enabled
|
|
by default. Defaults to True.
|
|
:type enabled_flag: bool
|
|
|
|
:param add_to_menu: Flag indicating whether the action should also
|
|
be added to the menu. Defaults to True.
|
|
:type add_to_menu: bool
|
|
|
|
:param add_to_toolbar: Flag indicating whether the action should also
|
|
be added to the toolbar. Defaults to True.
|
|
:type add_to_toolbar: bool
|
|
|
|
:param status_tip: Optional text to show in a popup when mouse pointer
|
|
hovers over the action.
|
|
:type status_tip: str
|
|
|
|
:param parent: Parent widget for the new action. Defaults None.
|
|
:type parent: QWidget
|
|
:param whats_this: Optional text to show in the status bar when the
|
|
mouse pointer hovers over the action.
|
|
|
|
:returns: The action that was created. Note that the action is also
|
|
added to self.actions list.
|
|
:rtype: QAction
|
|
"""
|
|
|
|
icon = QIcon(icon_path)
|
|
action = QAction(icon, text, parent)
|
|
action.triggered.connect(callback)
|
|
action.setEnabled(enabled_flag)
|
|
|
|
if status_tip is not None:
|
|
action.setStatusTip(status_tip)
|
|
|
|
if whats_this is not None:
|
|
action.setWhatsThis(whats_this)
|
|
|
|
if add_to_toolbar:
|
|
# Adds plugin icon to Plugins toolbar
|
|
#self.iface.addToolBarIcon(action)
|
|
self.toolBar.addAction(action)
|
|
|
|
if add_to_menu:
|
|
self.iface.addPluginToMenu(
|
|
self.menu,
|
|
action)
|
|
|
|
self.actions.append(action)
|
|
|
|
return action
|
|
|
|
def initGui(self):
|
|
self.toolBar = self.iface.addToolBar("FluxCEN")
|
|
self.toolBar.setObjectName("FluxCEN")
|
|
"""Create the menu entries and toolbar icons inside the QGIS GUI."""
|
|
icon_path = ':/plugins/CenRa_FLUX/reficon.png'
|
|
self.add_action(
|
|
icon_path,
|
|
text=self.tr(u'SigCEN'),
|
|
callback=self.bd_source,
|
|
dbtype='"+dbname+"',
|
|
parent=self.iface.mainWindow())
|
|
'''
|
|
icon_path_2 = ':/plugins/CenRa_FLUX/reficon.png'
|
|
self.add_action(
|
|
icon_path_2,
|
|
text=self.tr(u'RefCEN'),
|
|
callback=self.run_ref,
|
|
dbtype='ref_geo4269',
|
|
parent=self.iface.mainWindow())
|
|
'''
|
|
|
|
# will be set False in run()
|
|
self.first_start = False
|
|
|
|
def unload(self):
|
|
"""Removes the plugin menu item and icon from QGIS GUI."""
|
|
for action in self.actions:
|
|
self.iface.removePluginMenu(
|
|
self.tr(u'&SigCEN'),
|
|
action)
|
|
self.iface.removeToolBarIcon(action)
|
|
for action in self.actions:
|
|
self.iface.removePluginMenu(
|
|
self.tr(u'&RefCEN'),
|
|
action)
|
|
self.iface.removeToolBarIcon(action)
|
|
|
|
def bd_source(self):
|
|
self.dlg.activateWindow()
|
|
bd_origine=self.dlg.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.dlg.tableWidget_2.rowCount() > 0:
|
|
self.dlg.tableWidget_2.removeRow(self.dlg.tableWidget_2.rowCount()-1)
|
|
# print(self.dlg.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.dlg.show()
|
|
# Run the dialog event loop
|
|
result = self.dlg.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.dlg.tableWidget_2.rowCount() > 0:
|
|
self.dlg.tableWidget_2.removeRow(self.dlg.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.dlg.show()
|
|
# Run the dialog event loop
|
|
result = self.dlg.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.dlg.tableWidget_2.removeRow(self.dlg.tableWidget_2.currentRow())
|
|
'''
|
|
def option_OSM(self):
|
|
tms = 'type=xyz&url=https://tile.openstreetmap.org/{z}/{x}/{y}.png&zmax=19&zmin=0'
|
|
layer = QgsRasterLayer(tms, 'OSM', 'wms')
|
|
|
|
if not QgsProject.instance().mapLayersByName("OSM"):
|
|
QgsProject.instance().addMapLayer(layer)
|
|
else:
|
|
QMessageBox.question(iface.mainWindow(), u"Fond OSM déjà chargé !", "Le fond de carte OSM est déjà chargé", QMessageBox.Ok)
|
|
|
|
OSM_layer = QgsProject.instance().mapLayersByName("OSM")[0]
|
|
|
|
root = QgsProject.instance().layerTreeRoot()
|
|
|
|
# Move Layer
|
|
OSM_layer = root.findLayer(OSM_layer.id())
|
|
myClone = OSM_layer.clone()
|
|
parent = OSM_layer.parent()
|
|
parent.insertChildNode(-1, myClone)
|
|
parent.removeChildNode(OSM_layer)
|
|
|
|
|
|
def option_google_maps(self):
|
|
tms = 'type=xyz&zmin=0&zmax=20&url=https://mt1.google.com/vt/lyrs%3Ds%26x%3D{x}%26y%3D{y}%26z%3D{z}'
|
|
layer = QgsRasterLayer(tms, 'Google Satelitte', 'wms')
|
|
|
|
if not QgsProject.instance().mapLayersByName("Google Satelitte"):
|
|
QgsProject.instance().addMapLayer(layer)
|
|
else:
|
|
QMessageBox.question(iface.mainWindow(), u"Fond Google Sat' déjà chargé !", "Le fond de carte Google Satelitte est déjà chargé", QMessageBox.Ok)
|
|
|
|
google_layer = QgsProject.instance().mapLayersByName("Google Satelitte")[0]
|
|
|
|
root = QgsProject.instance().layerTreeRoot()
|
|
|
|
# Move Layer
|
|
google_layer = root.findLayer(google_layer.id())
|
|
myClone = google_layer.clone()
|
|
parent = google_layer.parent()
|
|
parent.insertChildNode(-1, myClone)
|
|
parent.removeChildNode(google_layer)
|
|
'''
|
|
|
|
def open_url(self, item):
|
|
url = item.data(Qt.UserRole)
|
|
#if url:
|
|
# Open the URL, you might use QDesktopServices.openUrl for this in a standalone PyQt application
|
|
# QDesktopServices.openUrl(QUrl(url))
|
|
|
|
def initialisation_flux(self):
|
|
'''
|
|
def csv_import(url):
|
|
url_open = urllib.request.urlopen(url)
|
|
csvfile = csv.reader(io.TextIOWrapper(url_open, encoding='utf8'), delimiter=';')
|
|
#on ne lit pas la première ligne correspondant aux noms des colonnes avec next()
|
|
next(csvfile)
|
|
return csvfile;
|
|
|
|
data = []
|
|
data2 = []
|
|
model = QStandardItemModel()
|
|
|
|
raw = csv_import(
|
|
"https://raw.githubusercontent.com/CEN-Rhone-Alpes/Plugin_QGIS/main/flux.csv")
|
|
for row in raw:
|
|
data.append(row)
|
|
data2.append(row)
|
|
data = [k for k in data if self.dlg.comboBox.currentText() in k]
|
|
data.sort()
|
|
data2.sort()
|
|
items = [
|
|
QStandardItem(field)
|
|
for field in row]
|
|
|
|
model.appendRow(items)
|
|
|
|
row=0
|
|
data=['a1','a2','a3']
|
|
data2=[['b1','c1','d1'],['b2','c2','d2'],['b3','c3','d3']]
|
|
if self.dlg.comboBox.currentText() == 'toutes les catégories':
|
|
# print(str(data2[0]))
|
|
# del data2[0]
|
|
# print(str(data2[0]))
|
|
nb_row = len(data2)
|
|
nb_col = len(data2[0])
|
|
print(data2[row][2])
|
|
self.dlg.tableWidget.setRowCount(nb_row)
|
|
self.dlg.tableWidget.setColumnCount(nb_col)
|
|
for row in range(nb_row):
|
|
for col in range(nb_col):
|
|
item = QTableWidgetItem(str(data2[row][col]))
|
|
# Access the value from the 6th column for the current row (style here)
|
|
value_from_2nd_column = str(data2[row][2])
|
|
# Set tooltip for each row
|
|
tooltip = f"Nom du flux: {value_from_2nd_column}"
|
|
item.setToolTip(tooltip)
|
|
|
|
# Check if the current column is the "Résumé des métadonnées" column
|
|
if col == 7:
|
|
# Set icon for the "Résumé des métadonnées" column
|
|
icon_path = self.plugin_path + '/info_metadata.png' # Replace 'path_to_your_icon.png' with the actual path to your icon
|
|
icon = QIcon(icon_path)
|
|
item.setIcon(icon)
|
|
# Store the URL in the item's data for later retrieval
|
|
url_from_6th_column = str(data2[row][7]) # Assuming the URL is in the next column
|
|
item.setData(Qt.UserRole, url_from_6th_column)'''
|
|
if dbtype == sigdb:
|
|
if self.dlg.comboBox.currentText() == 'toutes les catégories':
|
|
custom_list=schemaname_list
|
|
elif self.dlg.comboBox.currentText() == 'travaux':
|
|
custom_list="""(SELECT schemaname,tablename from pg_catalog.pg_tables
|
|
where schemaname like '"""+ str(self.dlg.comboBox.currentText()) +"""%' order by schemaname,tablename) UNION (SELECT schemaname,matviewname AS tablename FROM pg_catalog.pg_matviews where schemaname like '"""+ str(self.dlg.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.dlg.comboBox.currentText()) +"""%' order by schemaname,tablename) UNION (SELECT schemaname,matviewname AS tablename FROM pg_catalog.pg_matviews where schemaname like '\_"""+ str(self.dlg.comboBox.currentText()) +"""%' order by schemaname,tablename) order by schemaname,tablename;"""
|
|
else:
|
|
if self.dlg.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.dlg.comboBox.currentText()) +"""' order by schemaname,tablename;"""
|
|
cur.execute(custom_list)
|
|
list_schema = cur.fetchall()
|
|
|
|
self.dlg.tableWidget.setRowCount(len(list_schema))
|
|
self.dlg.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])
|
|
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:]
|
|
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.dlg.tableWidget.setItem(i,0,item)
|
|
item = QTableWidgetItem(schema_name)
|
|
self.dlg.tableWidget.setItem(i,1,item)
|
|
item = QTableWidgetItem(table_name)
|
|
self.dlg.tableWidget.setItem(i,2,item)
|
|
i=i+1
|
|
self.dlg.tableWidget.setColumnWidth(0, 20)
|
|
self.dlg.tableWidget.setColumnWidth(1, 300)
|
|
self.dlg.tableWidget.setColumnWidth(2, 300)
|
|
self.dlg.tableWidget.setHorizontalHeaderLabels(["Code","Schema","Table"])
|
|
'''
|
|
else:
|
|
nb_row = len(data)
|
|
nb_col = len(data[0])
|
|
self.dlg.tableWidget.setRowCount(nb_row)
|
|
self.dlg.tableWidget.setColumnCount(nb_col)
|
|
for row in range(nb_row):
|
|
for col in range(nb_col):
|
|
item = QTableWidgetItem(str(data[row][col]))
|
|
# Access the value from the 6th column for the current row (style here)
|
|
value_from_2nd_column = str(data[row][1])
|
|
# Set tooltip for each row
|
|
tooltip = f"Nom du flux: {value_from_2nd_column}"
|
|
item.setToolTip(tooltip)
|
|
|
|
# Check if the current column is the "Résumé des métadonnées" column
|
|
if col == 7:
|
|
# Set icon for the "Résumé des métadonnées" column
|
|
icon_path = self.plugin_path + '/metadata.png' # Replace 'path_to_your_icon.png' with the actual path to your icon
|
|
icon = QIcon(icon_path)
|
|
item.setIcon(icon)
|
|
# Store the URL in the item's data for later retrieval
|
|
url_from_6th_column = str(data2[row][7]) # Assuming the URL is in the next column
|
|
item.setData(Qt.UserRole, url_from_6th_column)
|
|
|
|
self.dlg.tableWidget.setItem(row, col, item)
|
|
|
|
self.dlg.tableWidget.setHorizontalHeaderLabels(["Service", "Catégorie", "Flux", "Nom technique", "Url d'accès", "Source", "Style", "Infos"])
|
|
|
|
self.dlg.tableWidget.setColumnWidth(0, 76)
|
|
self.dlg.tableWidget.setColumnWidth(1, 0)
|
|
self.dlg.tableWidget.setColumnWidth(2, 610)
|
|
self.dlg.tableWidget.setColumnWidth(3, 0)
|
|
self.dlg.tableWidget.setColumnWidth(4, 0)
|
|
self.dlg.tableWidget.setColumnWidth(5, 88)
|
|
self.dlg.tableWidget.setColumnWidth(6, 0)
|
|
self.dlg.tableWidget.setColumnWidth(7, 30)
|
|
|
|
self.dlg.tableWidget.selectRow(0)
|
|
'''
|
|
def selection_flux(self):
|
|
selected_row = 0
|
|
selected_items = self.dlg.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.dlg.tableWidget_2.insertRow(selected_row)
|
|
|
|
for column in range(self.dlg.tableWidget.columnCount()):
|
|
cloned_item = selected_items[column].clone()
|
|
self.dlg.tableWidget_2.setHorizontalHeaderLabels(["Code","Schema", "Table"])
|
|
self.dlg.tableWidget_2.setColumnCount(3)
|
|
self.dlg.tableWidget_2.setItem(selected_row, column, cloned_item)
|
|
|
|
self.dlg.tableWidget_2.setColumnWidth(0, 50)
|
|
self.dlg.tableWidget_2.setColumnWidth(1, 300)
|
|
self.dlg.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.dlg.tableWidget_2.findItems(new_item_text, QtCore.Qt.MatchExactly)
|
|
|
|
# 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.dlg.tableWidget_2.rowCount() > 3:
|
|
self.QMBquestion = QMessageBox.question(iface.mainWindow(), u"Attention !",
|
|
"Le nombre de flux à charger en une seule fois est limité à 3 pour des questions de performances. Souhaitez vous tout de même charger les " + str(
|
|
self.dlg.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.dlg.tableWidget_2.rowCount() <= 3:
|
|
self.chargement_flux()
|
|
|
|
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):
|
|
'''
|
|
if type == 'WFS':
|
|
vlayer = QgsVectorLayer(uri, name, "WFS")
|
|
# vlayer.setScaleBasedVisibility(True)
|
|
QgsProject.instance().addMapLayer(vlayer)
|
|
|
|
layers = QgsProject.instance().mapLayers() # dictionary
|
|
|
|
# rowCount() This property holds the number of rows in the table
|
|
for row in range(self.dlg.tableWidget_2.rowCount()):
|
|
# item(row, 0) Returns the item for the given row and column if one has been set; otherwise returns nullptr.
|
|
_item = self.dlg.tableWidget_2.item(row, 2).text()
|
|
_legend = self.dlg.tableWidget_2.item(row, 6).text()
|
|
# print(_item)
|
|
# print(_legend)
|
|
|
|
for layer in layers.values():
|
|
if layer.name() == _item:
|
|
if len(_legend) > 1:
|
|
styles_url = 'https://raw.githubusercontent.com/CEN-Nouvelle-Aquitaine/fluxcen/main/styles_couches/' + _legend + '.qml'
|
|
|
|
fp = urllib.request.urlopen(styles_url)
|
|
mybytes = fp.read()
|
|
|
|
document = QDomDocument()
|
|
document.setContent(mybytes)
|
|
|
|
res = layer.importNamedStyle(document)
|
|
layer.triggerRepaint()
|
|
|
|
else:
|
|
print("Pas de style à charger pour cette couche")
|
|
|
|
elif type == 'WMS' or type == 'WMS Raster' or type == 'WMS Vecteur' or type == 'WMTS':
|
|
rlayer = QgsRasterLayer(uri, name, "WMS")
|
|
QgsProject.instance().addMapLayer(rlayer)
|
|
else:
|
|
print("Unknown datatype !")
|
|
'''
|
|
p = []
|
|
|
|
for row in range(0, self.dlg.tableWidget_2.rowCount()):
|
|
## supression de la partie de l'url après le point d'interrogation
|
|
if dbtype == sigdb:
|
|
code = self.dlg.tableWidget_2.item(row,0).text()
|
|
schema = '_'+code+'_'+self.dlg.tableWidget_2.item(row,1).text()
|
|
if code == 'travaux' or code == 'agregation':
|
|
schema = self.dlg.tableWidget_2.item(row,1).text()
|
|
table = self.dlg.tableWidget_2.item(row,2).text()#.split("?", 1)[0]
|
|
if dbtype == refdb:
|
|
# code = self.dlg.tableWidget_2.item(row,0).text()
|
|
schema = self.dlg.tableWidget_2.item(row,1).text()
|
|
table = self.dlg.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()
|
|
print(len(list_typegeom))
|
|
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)
|
|
'''
|
|
try:
|
|
service = re.search('SERVICE=(.+?)&VERSION', self.dlg.tableWidget_2.item(row,4).text()).group(1)
|
|
except:
|
|
service = '1.0.0'
|
|
try:
|
|
version = re.search('VERSION=(.+?)&REQUEST', self.dlg.tableWidget_2.item(row,4).text()).group(1)
|
|
except:
|
|
version = '1.0.0'
|
|
|
|
if self.dlg.tableWidget_2.item(row,0).text() == 'WMS' or self.dlg.tableWidget_2.item(row,0).text() == 'WMS Vecteur' or self.dlg.tableWidget_2.item(row,0).text() == 'WMS Raster':
|
|
a = Flux(
|
|
self.dlg.tableWidget_2.item(row,0).text(),
|
|
self.dlg.tableWidget_2.item(row,1).text(),
|
|
self.dlg.tableWidget_2.item(row,2).text(),
|
|
self.dlg.tableWidget_2.item(row,3).text(),
|
|
"url="+url,
|
|
{
|
|
'service': self.dlg.tableWidget_2.item(row,0).text(),
|
|
'version': version,
|
|
'crs': "EPSG:2154",
|
|
'format' : "image/png",
|
|
'layers': self.dlg.tableWidget_2.item(row,3).text()+"&styles"
|
|
}
|
|
)
|
|
|
|
p.append(a)
|
|
|
|
uri = p[row].url + '&' + urllib.parse.unquote(urllib.parse.urlencode(p[row].parameters))
|
|
# print(uri)
|
|
if not QgsProject.instance().mapLayersByName(p[row].nom_commercial):
|
|
displayOnWindows(p[row].type, uri, p[row].nom_commercial)
|
|
else:
|
|
print("Couche "+p[row].nom_commercial+" déjà chargée")
|
|
|
|
|
|
elif self.dlg.tableWidget_2.item(row,0).text() == 'WFS':
|
|
|
|
a = Flux(
|
|
self.dlg.tableWidget_2.item(row, 0).text(),
|
|
self.dlg.tableWidget_2.item(row, 1).text(),
|
|
self.dlg.tableWidget_2.item(row, 2).text(),
|
|
self.dlg.tableWidget_2.item(row, 3).text(),
|
|
url,
|
|
{
|
|
'VERSION': version,
|
|
'TYPENAME': self.dlg.tableWidget_2.item(row, 3).text(),
|
|
'request': "GetFeature",
|
|
|
|
}
|
|
)
|
|
|
|
p.append(a)
|
|
|
|
uri = p[row].url + '?' + urllib.parse.unquote(urllib.parse.urlencode(p[row].parameters))
|
|
|
|
try:
|
|
response = requests.get(uri)
|
|
|
|
if response.status_code == 401:
|
|
print("Statut de réponse: 401")
|
|
|
|
if len(list(k)) == 0:
|
|
QMessageBox.question(iface.mainWindow(), u"Attention", "Veuillez ajouter une entrée de configuration d'authentification dans QGIS pour accéder aux flux CEN-NA sécurisés par un mot de passe (Flux 'FoncierCEN')", QMessageBox.Ok)
|
|
else:
|
|
# Add 'authcfg' to the parameters dictionary
|
|
p[row].parameters['authcfg'] = list(k)[0]
|
|
|
|
# Update the URI with the modified parameters
|
|
uri = p[row].url + '?' + urllib.parse.unquote(urllib.parse.urlencode(p[row].parameters))
|
|
|
|
# Make the request again with the updated URI
|
|
response = requests.get(uri)
|
|
elif response.status_code == 200:
|
|
print("Statut de réponse: 200.")
|
|
else:
|
|
print(f"Statut de réponse: {response.status_code}")
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"problème de requete: {e}")
|
|
|
|
|
|
if not QgsProject.instance().mapLayersByName(p[row].nom_commercial):
|
|
displayOnWindows(p[row].type, uri, p[row].nom_commercial)
|
|
else:
|
|
print("Couche "+p[row].nom_commercial+" déjà chargée")
|
|
|
|
|
|
elif self.dlg.tableWidget_2.item(row, 0).text() == 'PostGIS':
|
|
|
|
# Connexion à la base de données PostGIS
|
|
uri = QgsDataSourceUri()
|
|
uri.setConnection("sandbox.cen-nouvelle-aquitaine.dev", "5432", "piezo", "", "")
|
|
# 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("collaboratif", self.dlg.tableWidget_2.item(row, 3).text(), "geom")
|
|
# Chargement de la couche PostGIS
|
|
layer = QgsVectorLayer(uri.uri(), self.dlg.tableWidget_2.item(row, 2).text(), "postgres")
|
|
|
|
# Ajout de la couche au canevas QGIS
|
|
QgsProject.instance().addMapLayer(layer)
|
|
|
|
else:
|
|
print("Les flux WMTS et autres ne sont pas encore gérés par le plugin")
|
|
'''
|
|
def combobox_custom(self):
|
|
if dbtype == sigdb:
|
|
self.dlg.comboBox.clear()
|
|
self.dlg.comboBox.addItem("toutes les catégories")
|
|
self.dlg.comboBox.addItem('00')
|
|
self.dlg.comboBox.addItem('01')
|
|
self.dlg.comboBox.addItem('07')
|
|
self.dlg.comboBox.addItem('26')
|
|
self.dlg.comboBox.addItem('42')
|
|
self.dlg.comboBox.addItem('69')
|
|
self.dlg.comboBox.addItem('agregation')
|
|
self.dlg.comboBox.addItem('travaux')
|
|
self.dlg.comboBox.addItem('form')
|
|
if dbtype == refdb:
|
|
custom_list=schemaname_distinct
|
|
cur.execute(custom_list)
|
|
list_schema = cur.fetchall()
|
|
self.dlg.comboBox.clear()
|
|
self.dlg.comboBox.addItem("toutes les catégories")
|
|
for baxval in list_schema:
|
|
self.dlg.comboBox.addItem(baxval[0])
|
|
def filtre_dynamique(self, filter_text):
|
|
|
|
for i in range(self.dlg.tableWidget.rowCount()):
|
|
for j in range(self.dlg.tableWidget.columnCount()):
|
|
item = self.dlg.tableWidget.item(i, j)
|
|
match = filter_text.lower() not in item.text().lower()
|
|
self.dlg.tableWidget.setRowHidden(i, match)
|
|
if not match:
|
|
break
|
|
|
|
|
|
|
|
def popup(self):
|
|
|
|
self.dialog = Popup() # +++ - self
|
|
self.dialog.text_edit.show()
|
|
|
|
# from owslib.wfs import WebFeatureService
|
|
# import csv
|
|
|
|
# wfs = WebFeatureService(url='https://opendata.cen-nouvelle-aquitaine.org/geoserver/agriculture/wfs')
|
|
# agriculture = list(wfs.contents)
|
|
# with open('C:/Users/Romain/Desktop/test.csv', "a+", encoding="ISO-8859-1", newline='') as f:
|
|
# writer = csv.writer(f)
|
|
# for row in agriculture:
|
|
# writer.writerow(row.split())
|
|
#
|
|
# from owslib.wms import WebMapService
|
|
# wms = WebMapService('https://opendata.cen-nouvelle-aquitaine.org/geoserver/fond_carto/wms')
|
|
# fonds_carto = list(wms.contents)
|
|
# with open('C:/Users/Romain/Desktop/test.csv', "a+", encoding="ISO-8859-1", newline='') as f:
|
|
# writer = csv.writer(f)
|
|
# for row in fonds_carto:
|
|
# writer.writerow(row.split())
|
|
#
|
|
# import csv
|
|
#
|
|
# fluxWMS = ['AGG_TMM', '16-014_Brandes_de_Soyaux_2020-05', '17IMERIS_Bois-Charles_Vallée-du-Larry_2022_01', '17IMERIS_Grand-Champ_2022-01', '19PTOR_MNS_filtre_futurs_travaux_2021-10_L93', '19PTOR_MNS_filtre_travaux_realises_2021-10_L93', '19PTOR_ortho_2021-10_L93', '23CELI_marais_du_chancelier_2022_03_24', '23CLAM_Rocher_de_Clamouzat_2020-11', '23DIAB_lande_du_pont_du_diable_nord_2021-10_L93', '23DIAB_lande_du_pont_du_diable_sud_2021-10_L93', '23LAND_RNN_etang_des_landes_2020-08_L93', '33_Lagune-108-2021-08', '79BLVI_Blanchère-de-Viennay_2021-10', '79VGAT_Vallée-du-Gâteau_Pressigny_2020-02', '79VGAT_Vallée-du-Gâteau_Pressigny_2021-10', '86-001_TMM_CA-CD_2020-07', '86-500_Clain-sud_Etang-du-Pin', '86_AT_Chalandray_2021-10', '87CREN_siege_saint_gence_2021-09', '87GRLA_grandes_landes_2021-09-24', '87SANA_sanadie_2021-09-24', 'a_16_030_Prairies_de_Vouharte_2019_09', 'a_17_474_Estauaire_de_la_Gironde_Les_Pr_s_de_la_Rouille_2019_08', 'a_17_474_Estauaire_de_la_Gironde_Moulin_Rompu_2019_08', 'a_17_474_Estuaire_de_la_Gironde_Zone_Humide_de_la_Motte_Ronde_2021_04', 'a_17_IMERIS_Carriere_du_Planton_2021_08_12', 'a_17_LGV_Ragouillis_2021_08_12', 'a_33_Lagune_058_2021_08', 'a_33_Lagune_070_2021_08', 'a_33_Lagune_094_2021_08', 'a_33_Lagune_162_2021_08', 'a_33_Lagune_165_2021_08', 'a_33_Lagunes_207_208_209_2021_08', 'a_79_001_Clussais_la_Pommeraie_2020_11', 'a_79_008_Landes_de_L_Hopiteau_2019_09', 'a_79_020_Bessines_1_avant_travaux_2019_10', 'a_79_020_Bessines_2_pendant_travaux_2019_11', 'a_79_020_Bessines_3_apres_travaux_2020_12', 'a_79_044_Carriere_des_Landes_2020_09', 'a_79_AT_Vernoux_en_Gatine_2020_09', 'a_79_Sources_de_la_Sevre_Niortaise_Pierre_levee_2020_09', 'a_86_001_TMM_AA_2020_06', 'a_86_001_TMM_AB_2020_06', 'a_86_001_TMM_AC_2020_06', 'a_86_001_TMM_AD_2020_06', 'a_86_001_TMM_AE_2020_06', 'a_86_001_TMM_AF_2020_06', 'a_86_001_TMM_AG_2020_07', 'a_86_001_TMM_BA_2020_06', 'a_86_001_TMM_BB_2020_06', 'a_86_001_TMM_BC_2020_06', 'a_86_001_TMM_BD_2020_06', 'a_86_001_TMM_BE_2020_07', 'a_86_001_TMM_BF_2021_06', 'a_86_001_TMM_CB_2020_07', 'a_86_001_TMM_CC_2020_07', 'a_86_001_TMM_CC_2021_06', 'a_86_001_TMM_CD_2021_06', 'a_86_001_TMM_CE_2020_07', 'a_86_001_TMM_CF_2020_09', 'a_86_001_TMM_DA_2020_07', 'a_86_001_TMM_DB_2020_09', 'a_86_001_TMM_DC_2021_06', 'a_86_001_TMM_EA_2020_06', 'a_86_001_TMM_EB_2020_06', 'a_86_001_TMM_EC_2020_06', 'a_86_001_TMM_FA_2020_06', 'a_86_001_TMM_FB_2020_07', 'a_86_001_TMM_FC_2020_07', 'a_86_001_TMM_FC_2021_06', 'a_86_001_TMM_HA_2020_09', 'a_86_001_TMM_IA_2020_06', 'a_86_001_TMM_IB_2020_06', 'a_86_001_TMM_IC_2020_06', 'a_86_001_TMM_JA_2020_07', 'a_86_001_TMM_JB_2020_07', 'a_86_001_TMM_JC_2020_07', 'a_86_001_TMM_JE_2020_07', 'a_86_001_TMM_KA_2020_07', 'a_86_001_TMM_KB_2020_07', 'a_86_003_Falunieres_de_Moulin_Pochas_2019_09', 'a_86_006_Landes_et_pelouses_de_Lussac_Sillars_2019_08', 'a_86_011_Landes_de_Sainte_Marie_2019_09', 'a_86_025_Marais_des_Ragouillis_2020_11', 'a_86_025_Marais_des_Ragouillis_2021_02', 'a_86_026_Etangs_Baro_2019_09', 'a_86_029_Vallee_de_la_Longere_2019_09', 'a_86_037_Tourbiere_des_Regeasses_2021_06', 'a_86_038_Vallees_de_la_Vienne_et_du_Clain_Persac_2019_09', 'a_86_038_Vallees_de_la_Vienne_et_du_Clain_Persac_2020_12', 'a_86_052_Fontaine_le_Comte_nord_2020_11', 'a_86_052_Fontaine_le_Comte_sud_2020_11', 'a_86_054_Vallee_de_la_Vonne_2020_11', 'a_86_058_Carriere_de_Puy_Herve_2021_02_09', 'a_86_058_Carriere_de_Puy_Herve_2021_02_25', 'a_86_060_Bocage_de_la_Geoffronniere_2020_11', 'a_86_Le_Cormier_2021_05']
|
|
#
|
|
# with open('C:/Users/Romain/Desktop/test.csv', "a+", encoding="ISO-8859-1", newline='') as f:
|
|
# writer = csv.writer(f)
|
|
# for row in fluxWMS:
|
|
# writer.writerow(row.split())
|
|
|
|
#### Récupération des métadonnées des couches quand disponibles:
|
|
|
|
# from owslib.wms import WebMapService
|
|
# wms = WebMapService('http://geoservices.brgm.fr/geologie?service=WMS+Raster', version='1.1.1')
|
|
# print(list(wms.contents))
|
|
#
|
|
# print(wms['IDPR'].abstract) |