forked from CEN-RA/Plugin_QGIS
361 lines
16 KiB
Python
361 lines
16 KiB
Python
# -*- 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
|