Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[processing] Add postgis widget wrappers
  • Loading branch information
arnaud-morvan committed Feb 10, 2017
1 parent dda6670 commit c768edf
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 31 deletions.
41 changes: 25 additions & 16 deletions python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py
Expand Up @@ -27,8 +27,6 @@
__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
Expand Down Expand Up @@ -87,17 +85,15 @@ def __init__(self):
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,
Expand All @@ -110,11 +106,24 @@ def defineCharacteristics(self):
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,
Expand Down Expand Up @@ -168,7 +177,7 @@ def processAlgorithm(self, feedback):
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
Expand Down
35 changes: 25 additions & 10 deletions python/plugins/processing/algs/qgis/ImportIntoPostGIS.py
Expand Up @@ -33,7 +33,6 @@
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

Expand All @@ -58,14 +57,30 @@ def defineCharacteristics(self):
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,
Expand All @@ -85,7 +100,7 @@ def defineCharacteristics(self):
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)
Expand Down
9 changes: 6 additions & 3 deletions python/plugins/processing/algs/qgis/PostGISExecuteSQL.py
Expand Up @@ -26,8 +26,6 @@

__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
Expand All @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/gui/wrappers.py
Expand Up @@ -193,9 +193,9 @@ def getFileName(self, initial_value=''):
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('...')
Expand Down
207 changes: 207 additions & 0 deletions python/plugins/processing/gui/wrappers_postgis.py
@@ -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)

0 comments on commit c768edf

Please sign in to comment.