[processing] Add postgis widget wrappers

This commit is contained in:
arnaud.morvan@camptocamp.com 2017-02-09 16:07:24 +01:00
parent dda667023a
commit c768edf9d1
5 changed files with 265 additions and 31 deletions

View File

@ -27,8 +27,6 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$'
from qgis.PyQt.QtCore import QSettings
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterString
from processing.core.parameters import ParameterCrs
@ -87,17 +85,15 @@ class Ogr2OgrToPostGisList(GdalAlgorithm):
GdalAlgorithm.__init__(self)
self.processing = False
def dbConnectionNames(self):
settings = QSettings()
settings.beginGroup('/PostgreSQL/connections/')
return settings.childGroups()
def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Import Vector into PostGIS database (available connections)')
self.group, self.i18n_group = self.trAlgorithm('[OGR] Miscellaneous')
self.DB_CONNECTIONS = self.dbConnectionNames()
self.addParameter(ParameterSelection(self.DATABASE,
self.tr('Database (connection name)'), self.DB_CONNECTIONS))
self.addParameter(ParameterString(
self.DATABASE,
self.tr('Database (connection name)'),
metadata={
'widget_wrapper': {
'class': 'processing.gui.wrappers_postgis.ConnectionWidgetWrapper'}}))
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer')))
self.addParameter(ParameterString(self.SHAPE_ENCODING,
@ -110,11 +106,24 @@ class Ogr2OgrToPostGisList(GdalAlgorithm):
self.tr('Reproject to this CRS on output '), '', optional=True))
self.addParameter(ParameterCrs(self.S_SRS,
self.tr('Override source CRS'), '', optional=True))
self.addParameter(ParameterString(self.SCHEMA,
self.tr('Schema name'), 'public', optional=True))
self.addParameter(ParameterString(self.TABLE,
self.tr('Table name, leave blank to use input name'),
'', optional=True))
self.addParameter(ParameterString(
self.SCHEMA,
self.tr('Schema name'),
'public',
optional=True,
metadata={
'widget_wrapper': {
'class': 'processing.gui.wrappers_postgis.SchemaWidgetWrapper',
'connection_param': self.DATABASE}}))
self.addParameter(ParameterString(
self.TABLE,
self.tr('Table name, leave blank to use input name'),
'',
optional=True,
metadata={
'widget_wrapper': {
'class': 'processing.gui.wrappers_postgis.TableWidgetWrapper',
'schema_param': self.SCHEMA}}))
self.addParameter(ParameterString(self.PK,
self.tr('Primary key (new field)'), 'id', optional=True))
self.addParameter(ParameterTableField(self.PRIMARY_KEY,
@ -168,7 +177,7 @@ class Ogr2OgrToPostGisList(GdalAlgorithm):
self.processing = False
def getConsoleCommands(self):
connection = self.DB_CONNECTIONS[self.getParameterValue(self.DATABASE)]
connection = self.getParameterValue(self.DATABASE)
uri = uri_from_name(connection)
if self.processing:
# to get credentials input when needed

View File

@ -33,7 +33,6 @@ from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecution
from processing.core.parameters import ParameterBoolean
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterString
from processing.core.parameters import ParameterSelection
from processing.core.parameters import ParameterTableField
from processing.tools import dataobjects, postgis
@ -58,14 +57,30 @@ class ImportIntoPostGIS(GeoAlgorithm):
self.group, self.i18n_group = self.trAlgorithm('Database')
self.addParameter(ParameterVector(self.INPUT,
self.tr('Layer to import')))
self.DB_CONNECTIONS = self.dbConnectionNames()
self.addParameter(ParameterSelection(self.DATABASE,
self.tr('Database (connection name)'), self.DB_CONNECTIONS))
self.addParameter(ParameterString(self.SCHEMA,
self.tr('Schema (schema name)'), 'public'))
self.addParameter(ParameterString(self.TABLENAME,
self.tr('Table to import to (leave blank to use layer name)'), optional=True))
self.addParameter(ParameterString(
self.DATABASE,
self.tr('Database (connection name)'),
metadata={
'widget_wrapper': {
'class': 'processing.gui.wrappers_postgis.ConnectionWidgetWrapper'}}))
self.addParameter(ParameterString(
self.SCHEMA,
self.tr('Schema (schema name)'),
'public',
optional=True,
metadata={
'widget_wrapper': {
'class': 'processing.gui.wrappers_postgis.SchemaWidgetWrapper',
'connection_param': self.DATABASE}}))
self.addParameter(ParameterString(
self.TABLENAME,
self.tr('Table to import to (leave blank to use layer name)'),
'',
optional=True,
metadata={
'widget_wrapper': {
'class': 'processing.gui.wrappers_postgis.TableWidgetWrapper',
'schema_param': self.SCHEMA}}))
self.addParameter(ParameterTableField(self.PRIMARY_KEY,
self.tr('Primary key field'), self.INPUT, optional=True))
self.addParameter(ParameterString(self.GEOMETRY_COLUMN,
@ -85,7 +100,7 @@ class ImportIntoPostGIS(GeoAlgorithm):
self.tr('Create single-part geometries instead of multi-part'), False))
def processAlgorithm(self, feedback):
connection = self.DB_CONNECTIONS[self.getParameterValue(self.DATABASE)]
connection = self.getParameterValue(self.DATABASE)
db = postgis.GeoDB.from_name(connection)
schema = self.getParameterValue(self.SCHEMA)

View File

@ -26,8 +26,6 @@ __copyright__ = '(C) 2012, Victor Olaya, Carterix Geomatics'
__revision__ = '$Format:%H$'
from qgis.PyQt.QtCore import QSettings
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterString
@ -42,7 +40,12 @@ class PostGISExecuteSQL(GeoAlgorithm):
def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('PostGIS execute SQL')
self.group, self.i18n_group = self.trAlgorithm('Database')
self.addParameter(ParameterString(self.DATABASE, self.tr('Database')))
self.addParameter(ParameterString(
self.DATABASE,
self.tr('Database'),
metadata={
'widget_wrapper': {
'class': 'processing.gui.wrappers_postgis.ConnectionWidgetWrapper'}}))
self.addParameter(ParameterString(self.SQL, self.tr('SQL query'), '', True))
def processAlgorithm(self, feedback):

View File

@ -193,9 +193,9 @@ class WidgetWrapper(QObject):
return filename, selected_filter
class ExpressionEnabledWidgetWrapper(WidgetWrapper):
class ExpressionWidgetWrapperMixin():
def createWidget(self, basewidget):
def wrapWithExpressionButton(self, basewidget):
expr_button = QToolButton()
expr_button.clicked.connect(self.showExpressionsBuilder)
expr_button.setText('...')

View File

@ -0,0 +1,207 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
postgis.py - Postgis widget wrappers
---------------------
Date : December 2016
Copyright : (C) 2016 by Arnaud Morvan
Email : arnaud dot morvan at camptocamp dot com
***************************************************************************
* *
* 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
from qgis.PyQt.QtWidgets import QComboBox
from processing.core.parameters import (
ParameterString,
ParameterNumber,
ParameterFile,
ParameterTableField,
ParameterExpression
)
from processing.core.outputs import OutputString
from processing.gui.wrappers import (
WidgetWrapper,
ExpressionWidgetWrapperMixin,
DIALOG_MODELER,
)
from processing.tools.postgis import GeoDB
class ConnectionWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
"""
WidgetWrapper for ParameterString that create and manage a combobox widget
with existing postgis connections.
"""
def createWidget(self):
self._combo = QComboBox()
for group in self.items():
self._combo.addItem(*group)
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return self.wrapWithExpressionButton(self._combo)
def items(self):
settings = QSettings()
settings.beginGroup('/PostgreSQL/connections/')
items = [(group, group) for group in settings.childGroups()]
if self.dialogType == DIALOG_MODELER:
strings = self.dialog.getAvailableValuesOfType(
[ParameterString, ParameterNumber, ParameterFile,
ParameterTableField, ParameterExpression], OutputString)
items = items + [(self.dialog.resolveValueDescription(s), s) for s in strings]
return items
def setValue(self, value):
self.setComboValue(value, self._combo)
def value(self):
return self.comboValue(combobox=self._combo)
class SchemaWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
"""
WidgetWrapper for ParameterString that create and manage a combobox widget
with existing schemas from a parent connection parameter.
"""
def createWidget(self, connection_param=None):
self._connection_param = connection_param
self._connection = None
self._database = None
self._combo = QComboBox()
self._combo.setEditable(True)
self.refreshItems()
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
self._combo.lineEdit().editingFinished.connect(lambda: self.widgetValueHasChanged.emit(self))
return self.wrapWithExpressionButton(self._combo)
def postInitialize(self, wrappers):
for wrapper in wrappers:
if wrapper.param.name == self._connection_param:
self.connection_wrapper = wrapper
self.setConnection(wrapper.value())
wrapper.widgetValueHasChanged.connect(self.connectionChanged)
break
def connectionChanged(self, wrapper):
connection = wrapper.value()
if connection == self._connection:
return
self.setConnection(connection)
def setConnection(self, connection):
self._connection = connection
if isinstance(connection, str):
self._database = GeoDB.from_name(connection)
else:
self._database = None
self.refreshItems()
self.widgetValueHasChanged.emit(self)
def refreshItems(self):
value = self.comboValue(combobox=self._combo)
self._combo.clear()
if self._database is not None:
for schema in self._database.list_schemas():
self._combo.addItem(schema[1], schema[1])
if self.dialogType == DIALOG_MODELER:
strings = self.dialog.getAvailableValuesOfType(
[ParameterString, ParameterNumber, ParameterFile,
ParameterTableField, ParameterExpression], OutputString)
for text, data in [(self.dialog.resolveValueDescription(s), s) for s in strings]:
self._combo.addItem(text, data)
self.setComboValue(value, self._combo)
def setValue(self, value):
self.setComboValue(value, self._combo)
self.widgetValueHasChanged.emit(self)
def value(self):
return self.comboValue(combobox=self._combo)
def database(self):
return self._database
class TableWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
"""
WidgetWrapper for ParameterString that create and manage a combobox widget
with existing tables from a parent schema parameter.
"""
def createWidget(self, schema_param=None):
self._schema_param = schema_param
self._database = None
self._schema = None
self._combo = QComboBox()
self._combo.setEditable(True)
self.refreshItems()
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
self._combo.lineEdit().editingFinished.connect(lambda: self.widgetValueHasChanged.emit(self))
return self.wrapWithExpressionButton(self._combo)
def postInitialize(self, wrappers):
for wrapper in wrappers:
if wrapper.param.name == self._schema_param:
self.schema_wrapper = wrapper
self.setSchema(wrapper.database(), wrapper.value())
wrapper.widgetValueHasChanged.connect(self.schemaChanged)
break
def schemaChanged(self, wrapper):
database = wrapper.database()
schema = wrapper.value()
if database == self._database and schema == self._schema:
return
self.setSchema(database, schema)
def setSchema(self, database, schema):
self._database = database
self._schema = schema
self.refreshItems()
self.widgetValueHasChanged.emit(self)
def refreshItems(self):
value = self.comboValue(combobox=self._combo)
self._combo.clear()
if (self._database is not None and isinstance(self._schema, str)):
for table in self._database.list_geotables(self._schema):
self._combo.addItem(table[0], table[0])
if self.dialogType == DIALOG_MODELER:
strings = self.dialog.getAvailableValuesOfType(
[ParameterString, ParameterNumber, ParameterFile,
ParameterTableField, ParameterExpression], OutputString)
for text, data in [(self.dialog.resolveValueDescription(s), s) for s in strings]:
self._combo.addItem(text, data)
self.setComboValue(value, self._combo)
def setValue(self, value):
self.setComboValue(value, self._combo)
self.widgetValueHasChanged.emit(self)
def value(self):
return self.comboValue(combobox=self._combo)