From 72010321d8850be27655d482d3fa1e06fdae809f Mon Sep 17 00:00:00 2001 From: Tom LAVEILLE Date: Thu, 1 Aug 2024 14:36:55 +0200 Subject: [PATCH] =?UTF-8?q?T=C3=A9l=C3=A9verser=20les=20fichiers=20vers=20?= =?UTF-8?q?"/"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cenra.png | Bin 0 -> 4977 bytes copie.py | 360 ++++++++++++++++++++++++++++++++++++++++++++ copie.py.bak | 360 ++++++++++++++++++++++++++++++++++++++++++++ copie_dialog.py | 42 ++++++ copie_dialog.py.bak | 41 +++++ 5 files changed, 803 insertions(+) create mode 100644 cenra.png create mode 100644 copie.py create mode 100644 copie.py.bak create mode 100644 copie_dialog.py create mode 100644 copie_dialog.py.bak diff --git a/cenra.png b/cenra.png new file mode 100644 index 0000000000000000000000000000000000000000..d53a910fea37e4930c40122d285e6ea9fdc75ba7 GIT binary patch literal 4977 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 literal 0 HcmV?d00001 diff --git a/copie.py b/copie.py new file mode 100644 index 00000000..d2d26c83 --- /dev/null +++ b/copie.py @@ -0,0 +1,360 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + Copie + A QGIS plugin + Permet la copie d'une table dans une base PostGis + ------------------- + begin : 2015-04-13 + git sha : $Format:%H$ + copyright : (C) 2015 by Guillaume COSTES - CEN Rhône-Alpes + email : guillaume.costes@espaces-naturels.fr + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 __future__ import absolute_import +#from PyQt4.QtCore import * +#from PyQt4.QtGui import * +from qgis.PyQt.QtCore import QSettings +from qgis.PyQt.QtWidgets import QAction, QMenu, QDialog, QMessageBox +from qgis.PyQt.QtGui import QIcon +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from qgis.core import QgsDataSourceUri +from builtins import str +from builtins import object +from qgis.core import * +from qgis.gui import * +# Initialize Qt resources from file resources.py +from . import resources_rc +# Import the code for the dialog +from .copie_dialog import CopieDialog +import os.path +from .PythonSQL import * +import psycopg2 +import psycopg2.extras +import base64 +#import socket +import os +#import sys + +class Copie(object): + """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 + locale = QSettings().value('locale/userLocale')[0:2] + locale_path = os.path.join( + self.plugin_dir, + 'i18n', + 'Copie_{}.qm'.format(locale)) + + if os.path.exists(locale_path): + self.translator = QTranslator() + self.translator.load(locale_path) + + if qVersion() > '4.3.3': + QCoreApplication.installTranslator(self.translator) + + # Create the dialog (after translation) and keep reference + self.dlg = CopieDialog() + + # Declare instance attributes + self.actions = [] + self.menu = self.tr(u'&Copie') + # TODO: We are going to let the user set this up in a future iteration + self.toolbar = self.iface.addToolBar(u'Copie') + self.toolbar.setObjectName(u'Copie') + + # 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('Copie', message) + + + def add_action( + self, + icon_path, + text, + callback, + 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: + self.toolbar.addAction(action) + + if add_to_menu: + self.iface.addPluginToMenu( + self.menu, + action) + + self.actions.append(action) + + return action + + def initGui(self): + """Create the menu entries and toolbar icons inside the QGIS GUI.""" + + icon_path = ':/plugins/Copie/table_copie.png' + self.add_action( + icon_path, + text=self.tr(u'Copie'), + callback=self.run, + parent=self.iface.mainWindow()) + + + def unload(self): + """Removes the plugin menu item and icon from QGIS GUI.""" + for action in self.actions: + self.iface.removePluginMenu( + self.tr(u'&Copie'), + action) + self.iface.removeToolBarIcon(action) + # remove the toolbar + del self.toolbar + + + def run(self): + """Run method that performs all the real work""" + layer = self.iface.activeLayer() + + if layer == None : + #self.iface.messageBar().pushMessage(u"Vous devez sélectionner une table !", level=QgsMessageBar.WARNING, duration=5) + self.iface.messageBar().pushMessage("Ooops", u"Vous devez sélectionner une table !", level=Qgis.Warning, duration=5) + + else : + # Récupération des sources de la couche active + list_sources = layer.source().split(" ") + # dbname + source_db = [s for s in list_sources if "dbname" in s][0].split("'")[1] + # schema + source_schema = [s for s in list_sources if "table" in s][0].split('"')[1] + # tablename + source_tablename = [s for s in list_sources if "table" in s][0].split('"')[3] + + if source_db != sigdb: + #self.iface.messageBar().pushMessage(u"Un référentiel ne peut être copié, utilisez les filtres !", level=QgsMessageBar.CRITICAL, duration=10) + self.iface.messageBar().pushMessage("Ooops", u"Vous ne pouvez copier des couches que dans sigXX", level=Qgis.Critical, duration=5) + + else : + + 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) + first_conn.close() + + # Creation de la liste des schemas de la base de donnees + SQL = """WITH list_schema AS ( + SELECT catalog_name, schema_name + FROM information_schema.schemata + WHERE schema_name <> 'information_schema' + AND schema_name !~ E'^pg_' + ORDER BY schema_name + ) + + SELECT string_agg(schema_name,',') + FROM list_schema + GROUP BY catalog_name""" + + cur.execute(SQL) + + list_brut = str(next(cur)) + + list = list_brut [2:-3] + listItems = list.split(",") + + con.close() + + self.dlg.schema.clear() + self.dlg.schema.addItems(listItems) + self.dlg.schema.setCurrentIndex(-1) # Pour ne pas commencer la liste au premier schema + + + self.dlg.table_source.setText(source_schema + "." + source_tablename) # Affiche le nom de la table source + # show the dialog + self.dlg.show() + # Run the dialog event loop + result = self.dlg.exec_() + # See if OK was pressed + if result: + #******************************debut script********************************* + + + 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) + first_conn.close() + # Récupération de la couche active + layer = self.iface.activeLayer() + + # Récupération des sources de la couche active + list_sources = layer.source().split(" ") + # dbname + source_db = [s for s in list_sources if "dbname" in s][0].split("'")[1] + # schema + source_schema = [s for s in list_sources if "table" in s][0].split('"')[1] + # tablename + source_tablename = [s for s in list_sources if "table" in s][0].split('"')[3] + + if self.dlg.schema.currentIndex() == -1 : + QMessageBox.warning(None, "Oups :", "Veuillez choisir un dossier de destination.") + return + + schema = self.dlg.schema.currentText() + + if self.dlg.table_destination.text() == '' : + QMessageBox.warning(None, "Oups :", "Veuillez choisir un nom de destination.") + return + + if self.dlg.annee.text() == 'aaaa' or self.dlg.annee.text() == '': + tablename = schema + "_" + self.dlg.table_destination.text().lower() + else : + tablename = schema + "_" + self.dlg.table_destination.text().lower() + "_" + self.dlg.annee.text() + + tablename_qgis = tablename[1:] # Permet d'enlever le "_", ajouter a la premiere etape, dans qgis + + if self.dlg.table_vide.isChecked() == 1 : + SQL_table = "CREATE TABLE " + schema + "." + tablename + " AS SELECT * FROM " + source_schema + "." + source_tablename + " LIMIT 0;" + else : + SQL_table = "CREATE TABLE " + schema + "." + tablename + " AS SELECT * FROM " + source_schema + "." + source_tablename + + + SQL_pkey = "ALTER TABLE " + schema + "." + tablename + " ADD CONSTRAINT " + tablename + "_pkey" + " PRIMARY KEY (gid)" + SQL_sequence_01 = "CREATE SEQUENCE " + schema + "." + tablename + "_gid_seq" + " INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;" + SQL_sequence_02 = "ALTER TABLE " + schema + "." + tablename + " ALTER COLUMN gid SET DEFAULT nextval(\'" + schema + "." + tablename + "_gid_seq\'::regclass);" + SQL_sequence_03 = "SELECT setval(\'" + schema + "." + tablename + "_gid_seq\'::regclass, (SELECT max(gid) AS max_gid FROM " + schema + "." + tablename + "));" + SQL_sequence_04 = "ALTER SEQUENCE " + schema + "." + tablename + "_gid_seq" + " OWNED BY " + schema + "." + tablename + ".gid;" + + SQL_trigger_area_m2 = "CREATE TRIGGER area_m2" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.area_m2();" + SQL_trigger_area_ha = "CREATE TRIGGER area_ha" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.area_ha();" + SQL_trigger_length_m = "CREATE TRIGGER length_m" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.length_m();" + SQL_trigger_length_km = "CREATE TRIGGER length_km" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.length_km();" + SQL_trigger_coordonnees = "CREATE TRIGGER coordonnees" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.coordonnees();" + + cur.execute(SQL_table) + cur.execute(SQL_pkey) + cur.execute(SQL_sequence_01) + cur.execute(SQL_sequence_02) + cur.execute(SQL_sequence_03) + cur.execute(SQL_sequence_04) + + if layer.wkbType() == QgsWkbTypes.PointGeometry : + cur.execute(SQL_trigger_coordonnees) + + if layer.wkbType() == QgsWkbTypes.LineGeometry : + cur.execute(SQL_trigger_length_m) + cur.execute(SQL_trigger_length_km) + + if layer.wkbType() == QgsWkbTypes.PolygonGeometry : + cur.execute(SQL_trigger_area_m2) + cur.execute(SQL_trigger_area_ha) + + con.commit() + + ### Affichage de la table + uri = QgsDataSourceUri() + # set host name, port, database name, username and password + uri.setConnection(host ,port ,dbname ,user ,mdp) + # set database schema, table name, geometry column and optionaly subset (WHERE clause) + uri.setDataSource(schema, tablename, geom) + + layer = self.iface.addVectorLayer(uri.uri(), tablename_qgis, "postgres") + + con.commit() + con.close() + + #self.iface.messageBar().pushMessage("Table \"" + source_schema + "." + source_tablename + u"\" copiée dans \"" + schema + "." + tablename + "\"." , level=QgsMessageBar.INFO, duration=10) + self.iface.messageBar().pushMessage("Bravo!", "Table \"" + source_schema + "." + source_tablename + u"\" copiée dans \"" + schema + "." + tablename + "\".", level=Qgis.Success, duration=5) + pass diff --git a/copie.py.bak b/copie.py.bak new file mode 100644 index 00000000..057d5db1 --- /dev/null +++ b/copie.py.bak @@ -0,0 +1,360 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + Copie + A QGIS plugin + Permet la copie d'une table dans une base PostGis + ------------------- + begin : 2015-04-13 + git sha : $Format:%H$ + copyright : (C) 2015 by Guillaume COSTES - CEN Rhône-Alpes + email : guillaume.costes@espaces-naturels.fr + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 PyQt4.QtCore import * +#from PyQt4.QtGui import * +from qgis.core import * +from qgis.gui import * +# Initialize Qt resources from file resources.py +import resources_rc +# Import the code for the dialog +from copie_dialog import CopieDialog +import os.path + + +class Copie: + """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 + locale = QSettings().value('locale/userLocale')[0:2] + locale_path = os.path.join( + self.plugin_dir, + 'i18n', + 'Copie_{}.qm'.format(locale)) + + if os.path.exists(locale_path): + self.translator = QTranslator() + self.translator.load(locale_path) + + if qVersion() > '4.3.3': + QCoreApplication.installTranslator(self.translator) + + # Create the dialog (after translation) and keep reference + self.dlg = CopieDialog() + + # Declare instance attributes + self.actions = [] + self.menu = self.tr(u'&Copie') + # TODO: We are going to let the user set this up in a future iteration + self.toolbar = self.iface.addToolBar(u'Copie') + self.toolbar.setObjectName(u'Copie') + + # 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('Copie', message) + + + def add_action( + self, + icon_path, + text, + callback, + 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: + self.toolbar.addAction(action) + + if add_to_menu: + self.iface.addPluginToMenu( + self.menu, + action) + + self.actions.append(action) + + return action + + def initGui(self): + """Create the menu entries and toolbar icons inside the QGIS GUI.""" + + icon_path = ':/plugins/Copie/table_copie.png' + self.add_action( + icon_path, + text=self.tr(u'Copie'), + callback=self.run, + parent=self.iface.mainWindow()) + + + def unload(self): + """Removes the plugin menu item and icon from QGIS GUI.""" + for action in self.actions: + self.iface.removePluginMenu( + self.tr(u'&Copie'), + action) + self.iface.removeToolBarIcon(action) + # remove the toolbar + del self.toolbar + + + def run(self): + """Run method that performs all the real work""" + layer = self.iface.activeLayer() + + if layer == None : + self.iface.messageBar().pushMessage(u"Vous devez sélectionner une table !", level=QgsMessageBar.WARNING, duration=5) + + else : + # Récupération des sources de la couche active + list_sources = layer.source().split(" ") + # dbname + source_db = [s for s in list_sources if "dbname" in s][0].split("'")[1] + # schema + source_schema = [s for s in list_sources if "table" in s][0].split('"')[1] + # tablename + source_tablename = [s for s in list_sources if "table" in s][0].split('"')[3] + + if source_db != 'sig4269': + self.iface.messageBar().pushMessage(u"Un référentiel ne peut être copié, utilisez les filtres !", level=QgsMessageBar.CRITICAL, duration=10) + + else : + import psycopg2 + + config = "//100.100.100.100/bd_sig/z_QGIS/config.txt" # Chemin du fichier config + # Fonction de lecture des lignes du fichier config + def readline(n): + with open(config, "r") as f: + for lineno, line in enumerate(f): + if lineno == n: + return line.strip() # Permet d'enlever les retours chariots + + host = readline(10) + port = readline(12) + dbname = readline(14) + user = readline(16) + password = readline(18) + + con = psycopg2.connect("dbname="+ dbname + " user=" + user + " host=" + host + " password=" + password) + cur = con.cursor() + # Creation de la liste des schemas de la base de donnees + SQL = """WITH list_schema AS ( + SELECT catalog_name, schema_name + FROM information_schema.schemata + WHERE schema_name <> 'information_schema' + AND schema_name !~ E'^pg_' + ORDER BY schema_name + ) + + SELECT string_agg(schema_name,',') + FROM list_schema + GROUP BY catalog_name""" + + cur.execute(SQL) + + list_brut = str(cur.next()) + + list = list_brut [3:-3] + listItems = list.split(",") + + con.close() + + self.dlg.schema.clear() + self.dlg.schema.addItems(listItems) + self.dlg.schema.setCurrentIndex(-1) # Pour ne pas commencer la liste au premier schema + + + self.dlg.table_source.setText(source_schema + "." + source_tablename) # Affiche le nom de la table source + # show the dialog + self.dlg.show() + # Run the dialog event loop + result = self.dlg.exec_() + # See if OK was pressed + if result: + #******************************debut script********************************* + ### config.txt + config = "//100.100.100.100/bd_sig/z_QGIS/config.txt" # Chemin du fichier config + + # Fonction de lecture des lignes du fichier config + def readline(n): + with open(config, "r") as f: + for lineno, line in enumerate(f): + if lineno == n: + return line.strip() # Permet d'enlever les retours chariots + + # Recuperation des donnees + host = readline(10) + port = readline(12) + dbname = readline(14) + user = readline(16) + password = readline(18) + + con = psycopg2.connect("dbname="+ dbname + " user=" + user + " host=" + host + " password=" + password) + cur = con.cursor() + + # Récupération de la couche active + layer = self.iface.activeLayer() + + # Récupération des sources de la couche active + list_sources = layer.source().split(" ") + # dbname + source_db = [s for s in list_sources if "dbname" in s][0].split("'")[1] + # schema + source_schema = [s for s in list_sources if "table" in s][0].split('"')[1] + # tablename + source_tablename = [s for s in list_sources if "table" in s][0].split('"')[3] + + if self.dlg.schema.currentIndex() == -1 : + QMessageBox.warning(None, "Oups :", "Veuillez choisir un dossier de destination.") + return + + schema = self.dlg.schema.currentText() + + if self.dlg.table_destination.text() == '' : + QMessageBox.warning(None, "Oups :", "Veuillez choisir un nom de destination.") + return + + if self.dlg.annee.text() == 'aaaa' or self.dlg.annee.text() == '': + tablename = schema + "_" + self.dlg.table_destination.text().lower() + else : + tablename = schema + "_" + self.dlg.table_destination.text().lower() + "_" + self.dlg.annee.text() + + tablename_qgis = tablename[1:] # Permet d'enlever le "_", ajouter a la premiere etape, dans qgis + + geom = readline(6) + + if self.dlg.table_vide.isChecked() == 1 : + SQL_table = "CREATE TABLE " + schema + "." + tablename + " AS SELECT * FROM " + source_schema + "." + source_tablename + " LIMIT 0;" + else : + SQL_table = "CREATE TABLE " + schema + "." + tablename + " AS SELECT * FROM " + source_schema + "." + source_tablename + + + SQL_pkey = "ALTER TABLE " + schema + "." + tablename + " ADD CONSTRAINT " + tablename + "_pkey" + " PRIMARY KEY (gid)" + SQL_sequence_01 = "CREATE SEQUENCE " + schema + "." + tablename + "_gid_seq" + " INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;" + SQL_sequence_02 = "ALTER TABLE " + schema + "." + tablename + " ALTER COLUMN gid SET DEFAULT nextval(\'" + schema + "." + tablename + "_gid_seq\'::regclass);" + SQL_sequence_03 = "SELECT setval(\'" + schema + "." + tablename + "_gid_seq\'::regclass, (SELECT max(gid) AS max_gid FROM " + schema + "." + tablename + "));" + SQL_sequence_04 = "ALTER SEQUENCE " + schema + "." + tablename + "_gid_seq" + " OWNED BY " + schema + "." + tablename + ".gid;" + + SQL_trigger_area_m2 = "CREATE TRIGGER area_m2" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.area_m2();" + SQL_trigger_area_ha = "CREATE TRIGGER area_ha" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.area_ha();" + SQL_trigger_length_m = "CREATE TRIGGER length_m" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.length_m();" + SQL_trigger_length_km = "CREATE TRIGGER length_km" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.length_km();" + SQL_trigger_coordonnees = "CREATE TRIGGER coordonnees" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.coordonnees();" + + cur.execute(SQL_table) + cur.execute(SQL_pkey) + cur.execute(SQL_sequence_01) + cur.execute(SQL_sequence_02) + cur.execute(SQL_sequence_03) + cur.execute(SQL_sequence_04) + + if layer.wkbType() == QGis.WKBPoint : + cur.execute(SQL_trigger_coordonnees) + + if layer.wkbType() == QGis.WKBMultiLineString : + cur.execute(SQL_trigger_length_m) + cur.execute(SQL_trigger_length_km) + + if layer.wkbType() == QGis.WKBMultiPolygon : + cur.execute(SQL_trigger_area_m2) + cur.execute(SQL_trigger_area_ha) + + con.commit() + + ### Affichage de la table + uri = QgsDataSourceURI() + # set host name, port, database name, username and password + uri.setConnection(host ,port ,dbname ,user ,password) + # set database schema, table name, geometry column and optionaly subset (WHERE clause) + uri.setDataSource(schema, tablename, geom) + + layer = self.iface.addVectorLayer(uri.uri(), tablename_qgis, "postgres") + + con.commit() + con.close() + + self.iface.messageBar().pushMessage("Table \"" + source_schema + "." + source_tablename + u"\" copiée dans \"" + schema + "." + tablename + "\"." , level=QgsMessageBar.INFO, duration=10) + pass diff --git a/copie_dialog.py b/copie_dialog.py new file mode 100644 index 00000000..95c2d782 --- /dev/null +++ b/copie_dialog.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + CopieDialog + A QGIS plugin + Permet la copie d'une table dans une base PostGis + ------------------- + begin : 2015-04-13 + git sha : $Format:%H$ + copyright : (C) 2015 by Guillaume COSTES - CEN Rhône-Alpes + email : guillaume.costes@espaces-naturels.fr + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +""" + +import os + +from qgis.PyQt import QtCore, QtGui, QtGui, uic +from qgis.PyQt.QtWidgets import QAction, QMenu, QDialog + +FORM_CLASS, _ = uic.loadUiType(os.path.join( + os.path.dirname(__file__), 'copie_dialog_base.ui')) + + +class CopieDialog(QDialog, FORM_CLASS): + def __init__(self, parent=None): + """Constructor.""" + super(CopieDialog, self).__init__(parent) + # Set up the user interface from Designer. + # After setupUI you can access any designer object by doing + # self., and you can use autoconnect slots - see + # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html + # #widgets-and-dialogs-with-auto-connect + self.setupUi(self) diff --git a/copie_dialog.py.bak b/copie_dialog.py.bak new file mode 100644 index 00000000..a951555c --- /dev/null +++ b/copie_dialog.py.bak @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + CopieDialog + A QGIS plugin + Permet la copie d'une table dans une base PostGis + ------------------- + begin : 2015-04-13 + git sha : $Format:%H$ + copyright : (C) 2015 by Guillaume COSTES - CEN Rhône-Alpes + email : guillaume.costes@espaces-naturels.fr + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +""" + +import os + +from PyQt4 import QtGui, uic + +FORM_CLASS, _ = uic.loadUiType(os.path.join( + os.path.dirname(__file__), 'copie_dialog_base.ui')) + + +class CopieDialog(QtGui.QDialog, FORM_CLASS): + def __init__(self, parent=None): + """Constructor.""" + super(CopieDialog, self).__init__(parent) + # Set up the user interface from Designer. + # After setupUI you can access any designer object by doing + # self., and you can use autoconnect slots - see + # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html + # #widgets-and-dialogs-with-auto-connect + self.setupUi(self)