Skip to content

Commit c768edf

Browse files
committed
[processing] Add postgis widget wrappers
1 parent dda6670 commit c768edf

File tree

5 files changed

+265
-31
lines changed

5 files changed

+265
-31
lines changed

python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py

+25-16
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
__revision__ = '$Format:%H$'
2828

2929

30-
from qgis.PyQt.QtCore import QSettings
31-
3230
from processing.core.parameters import ParameterVector
3331
from processing.core.parameters import ParameterString
3432
from processing.core.parameters import ParameterCrs
@@ -87,17 +85,15 @@ def __init__(self):
8785
GdalAlgorithm.__init__(self)
8886
self.processing = False
8987

90-
def dbConnectionNames(self):
91-
settings = QSettings()
92-
settings.beginGroup('/PostgreSQL/connections/')
93-
return settings.childGroups()
94-
9588
def defineCharacteristics(self):
9689
self.name, self.i18n_name = self.trAlgorithm('Import Vector into PostGIS database (available connections)')
9790
self.group, self.i18n_group = self.trAlgorithm('[OGR] Miscellaneous')
98-
self.DB_CONNECTIONS = self.dbConnectionNames()
99-
self.addParameter(ParameterSelection(self.DATABASE,
100-
self.tr('Database (connection name)'), self.DB_CONNECTIONS))
91+
self.addParameter(ParameterString(
92+
self.DATABASE,
93+
self.tr('Database (connection name)'),
94+
metadata={
95+
'widget_wrapper': {
96+
'class': 'processing.gui.wrappers_postgis.ConnectionWidgetWrapper'}}))
10197
self.addParameter(ParameterVector(self.INPUT_LAYER,
10298
self.tr('Input layer')))
10399
self.addParameter(ParameterString(self.SHAPE_ENCODING,
@@ -110,11 +106,24 @@ def defineCharacteristics(self):
110106
self.tr('Reproject to this CRS on output '), '', optional=True))
111107
self.addParameter(ParameterCrs(self.S_SRS,
112108
self.tr('Override source CRS'), '', optional=True))
113-
self.addParameter(ParameterString(self.SCHEMA,
114-
self.tr('Schema name'), 'public', optional=True))
115-
self.addParameter(ParameterString(self.TABLE,
116-
self.tr('Table name, leave blank to use input name'),
117-
'', optional=True))
109+
self.addParameter(ParameterString(
110+
self.SCHEMA,
111+
self.tr('Schema name'),
112+
'public',
113+
optional=True,
114+
metadata={
115+
'widget_wrapper': {
116+
'class': 'processing.gui.wrappers_postgis.SchemaWidgetWrapper',
117+
'connection_param': self.DATABASE}}))
118+
self.addParameter(ParameterString(
119+
self.TABLE,
120+
self.tr('Table name, leave blank to use input name'),
121+
'',
122+
optional=True,
123+
metadata={
124+
'widget_wrapper': {
125+
'class': 'processing.gui.wrappers_postgis.TableWidgetWrapper',
126+
'schema_param': self.SCHEMA}}))
118127
self.addParameter(ParameterString(self.PK,
119128
self.tr('Primary key (new field)'), 'id', optional=True))
120129
self.addParameter(ParameterTableField(self.PRIMARY_KEY,
@@ -168,7 +177,7 @@ def processAlgorithm(self, feedback):
168177
self.processing = False
169178

170179
def getConsoleCommands(self):
171-
connection = self.DB_CONNECTIONS[self.getParameterValue(self.DATABASE)]
180+
connection = self.getParameterValue(self.DATABASE)
172181
uri = uri_from_name(connection)
173182
if self.processing:
174183
# to get credentials input when needed

python/plugins/processing/algs/qgis/ImportIntoPostGIS.py

+25-10
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
from processing.core.parameters import ParameterBoolean
3434
from processing.core.parameters import ParameterVector
3535
from processing.core.parameters import ParameterString
36-
from processing.core.parameters import ParameterSelection
3736
from processing.core.parameters import ParameterTableField
3837
from processing.tools import dataobjects, postgis
3938

@@ -58,14 +57,30 @@ def defineCharacteristics(self):
5857
self.group, self.i18n_group = self.trAlgorithm('Database')
5958
self.addParameter(ParameterVector(self.INPUT,
6059
self.tr('Layer to import')))
61-
62-
self.DB_CONNECTIONS = self.dbConnectionNames()
63-
self.addParameter(ParameterSelection(self.DATABASE,
64-
self.tr('Database (connection name)'), self.DB_CONNECTIONS))
65-
self.addParameter(ParameterString(self.SCHEMA,
66-
self.tr('Schema (schema name)'), 'public'))
67-
self.addParameter(ParameterString(self.TABLENAME,
68-
self.tr('Table to import to (leave blank to use layer name)'), optional=True))
60+
self.addParameter(ParameterString(
61+
self.DATABASE,
62+
self.tr('Database (connection name)'),
63+
metadata={
64+
'widget_wrapper': {
65+
'class': 'processing.gui.wrappers_postgis.ConnectionWidgetWrapper'}}))
66+
self.addParameter(ParameterString(
67+
self.SCHEMA,
68+
self.tr('Schema (schema name)'),
69+
'public',
70+
optional=True,
71+
metadata={
72+
'widget_wrapper': {
73+
'class': 'processing.gui.wrappers_postgis.SchemaWidgetWrapper',
74+
'connection_param': self.DATABASE}}))
75+
self.addParameter(ParameterString(
76+
self.TABLENAME,
77+
self.tr('Table to import to (leave blank to use layer name)'),
78+
'',
79+
optional=True,
80+
metadata={
81+
'widget_wrapper': {
82+
'class': 'processing.gui.wrappers_postgis.TableWidgetWrapper',
83+
'schema_param': self.SCHEMA}}))
6984
self.addParameter(ParameterTableField(self.PRIMARY_KEY,
7085
self.tr('Primary key field'), self.INPUT, optional=True))
7186
self.addParameter(ParameterString(self.GEOMETRY_COLUMN,
@@ -85,7 +100,7 @@ def defineCharacteristics(self):
85100
self.tr('Create single-part geometries instead of multi-part'), False))
86101

87102
def processAlgorithm(self, feedback):
88-
connection = self.DB_CONNECTIONS[self.getParameterValue(self.DATABASE)]
103+
connection = self.getParameterValue(self.DATABASE)
89104
db = postgis.GeoDB.from_name(connection)
90105

91106
schema = self.getParameterValue(self.SCHEMA)

python/plugins/processing/algs/qgis/PostGISExecuteSQL.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626

2727
__revision__ = '$Format:%H$'
2828

29-
from qgis.PyQt.QtCore import QSettings
30-
3129
from processing.core.GeoAlgorithm import GeoAlgorithm
3230
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
3331
from processing.core.parameters import ParameterString
@@ -42,7 +40,12 @@ class PostGISExecuteSQL(GeoAlgorithm):
4240
def defineCharacteristics(self):
4341
self.name, self.i18n_name = self.trAlgorithm('PostGIS execute SQL')
4442
self.group, self.i18n_group = self.trAlgorithm('Database')
45-
self.addParameter(ParameterString(self.DATABASE, self.tr('Database')))
43+
self.addParameter(ParameterString(
44+
self.DATABASE,
45+
self.tr('Database'),
46+
metadata={
47+
'widget_wrapper': {
48+
'class': 'processing.gui.wrappers_postgis.ConnectionWidgetWrapper'}}))
4649
self.addParameter(ParameterString(self.SQL, self.tr('SQL query'), '', True))
4750

4851
def processAlgorithm(self, feedback):

python/plugins/processing/gui/wrappers.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,9 @@ def getFileName(self, initial_value=''):
193193
return filename, selected_filter
194194

195195

196-
class ExpressionEnabledWidgetWrapper(WidgetWrapper):
196+
class ExpressionWidgetWrapperMixin():
197197

198-
def createWidget(self, basewidget):
198+
def wrapWithExpressionButton(self, basewidget):
199199
expr_button = QToolButton()
200200
expr_button.clicked.connect(self.showExpressionsBuilder)
201201
expr_button.setText('...')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
***************************************************************************
5+
postgis.py - Postgis widget wrappers
6+
---------------------
7+
Date : December 2016
8+
Copyright : (C) 2016 by Arnaud Morvan
9+
Email : arnaud dot morvan at camptocamp dot com
10+
***************************************************************************
11+
* *
12+
* This program is free software; you can redistribute it and/or modify *
13+
* it under the terms of the GNU General Public License as published by *
14+
* the Free Software Foundation; either version 2 of the License, or *
15+
* (at your option) any later version. *
16+
* *
17+
***************************************************************************
18+
"""
19+
20+
21+
from qgis.PyQt.QtCore import QSettings
22+
from qgis.PyQt.QtWidgets import QComboBox
23+
24+
from processing.core.parameters import (
25+
ParameterString,
26+
ParameterNumber,
27+
ParameterFile,
28+
ParameterTableField,
29+
ParameterExpression
30+
)
31+
from processing.core.outputs import OutputString
32+
from processing.gui.wrappers import (
33+
WidgetWrapper,
34+
ExpressionWidgetWrapperMixin,
35+
DIALOG_MODELER,
36+
)
37+
from processing.tools.postgis import GeoDB
38+
39+
40+
class ConnectionWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
41+
"""
42+
WidgetWrapper for ParameterString that create and manage a combobox widget
43+
with existing postgis connections.
44+
"""
45+
46+
def createWidget(self):
47+
self._combo = QComboBox()
48+
for group in self.items():
49+
self._combo.addItem(*group)
50+
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
51+
return self.wrapWithExpressionButton(self._combo)
52+
53+
def items(self):
54+
settings = QSettings()
55+
settings.beginGroup('/PostgreSQL/connections/')
56+
items = [(group, group) for group in settings.childGroups()]
57+
58+
if self.dialogType == DIALOG_MODELER:
59+
strings = self.dialog.getAvailableValuesOfType(
60+
[ParameterString, ParameterNumber, ParameterFile,
61+
ParameterTableField, ParameterExpression], OutputString)
62+
items = items + [(self.dialog.resolveValueDescription(s), s) for s in strings]
63+
64+
return items
65+
66+
def setValue(self, value):
67+
self.setComboValue(value, self._combo)
68+
69+
def value(self):
70+
return self.comboValue(combobox=self._combo)
71+
72+
73+
class SchemaWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
74+
"""
75+
WidgetWrapper for ParameterString that create and manage a combobox widget
76+
with existing schemas from a parent connection parameter.
77+
"""
78+
79+
def createWidget(self, connection_param=None):
80+
self._connection_param = connection_param
81+
self._connection = None
82+
self._database = None
83+
84+
self._combo = QComboBox()
85+
self._combo.setEditable(True)
86+
self.refreshItems()
87+
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
88+
self._combo.lineEdit().editingFinished.connect(lambda: self.widgetValueHasChanged.emit(self))
89+
90+
return self.wrapWithExpressionButton(self._combo)
91+
92+
def postInitialize(self, wrappers):
93+
for wrapper in wrappers:
94+
if wrapper.param.name == self._connection_param:
95+
self.connection_wrapper = wrapper
96+
self.setConnection(wrapper.value())
97+
wrapper.widgetValueHasChanged.connect(self.connectionChanged)
98+
break
99+
100+
def connectionChanged(self, wrapper):
101+
connection = wrapper.value()
102+
if connection == self._connection:
103+
return
104+
self.setConnection(connection)
105+
106+
def setConnection(self, connection):
107+
self._connection = connection
108+
if isinstance(connection, str):
109+
self._database = GeoDB.from_name(connection)
110+
else:
111+
self._database = None
112+
self.refreshItems()
113+
self.widgetValueHasChanged.emit(self)
114+
115+
def refreshItems(self):
116+
value = self.comboValue(combobox=self._combo)
117+
118+
self._combo.clear()
119+
120+
if self._database is not None:
121+
for schema in self._database.list_schemas():
122+
self._combo.addItem(schema[1], schema[1])
123+
124+
if self.dialogType == DIALOG_MODELER:
125+
strings = self.dialog.getAvailableValuesOfType(
126+
[ParameterString, ParameterNumber, ParameterFile,
127+
ParameterTableField, ParameterExpression], OutputString)
128+
for text, data in [(self.dialog.resolveValueDescription(s), s) for s in strings]:
129+
self._combo.addItem(text, data)
130+
131+
self.setComboValue(value, self._combo)
132+
133+
def setValue(self, value):
134+
self.setComboValue(value, self._combo)
135+
self.widgetValueHasChanged.emit(self)
136+
137+
def value(self):
138+
return self.comboValue(combobox=self._combo)
139+
140+
def database(self):
141+
return self._database
142+
143+
144+
class TableWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
145+
"""
146+
WidgetWrapper for ParameterString that create and manage a combobox widget
147+
with existing tables from a parent schema parameter.
148+
"""
149+
150+
def createWidget(self, schema_param=None):
151+
self._schema_param = schema_param
152+
self._database = None
153+
self._schema = None
154+
155+
self._combo = QComboBox()
156+
self._combo.setEditable(True)
157+
self.refreshItems()
158+
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
159+
self._combo.lineEdit().editingFinished.connect(lambda: self.widgetValueHasChanged.emit(self))
160+
161+
return self.wrapWithExpressionButton(self._combo)
162+
163+
def postInitialize(self, wrappers):
164+
for wrapper in wrappers:
165+
if wrapper.param.name == self._schema_param:
166+
self.schema_wrapper = wrapper
167+
self.setSchema(wrapper.database(), wrapper.value())
168+
wrapper.widgetValueHasChanged.connect(self.schemaChanged)
169+
break
170+
171+
def schemaChanged(self, wrapper):
172+
database = wrapper.database()
173+
schema = wrapper.value()
174+
if database == self._database and schema == self._schema:
175+
return
176+
self.setSchema(database, schema)
177+
178+
def setSchema(self, database, schema):
179+
self._database = database
180+
self._schema = schema
181+
self.refreshItems()
182+
self.widgetValueHasChanged.emit(self)
183+
184+
def refreshItems(self):
185+
value = self.comboValue(combobox=self._combo)
186+
187+
self._combo.clear()
188+
189+
if (self._database is not None and isinstance(self._schema, str)):
190+
for table in self._database.list_geotables(self._schema):
191+
self._combo.addItem(table[0], table[0])
192+
193+
if self.dialogType == DIALOG_MODELER:
194+
strings = self.dialog.getAvailableValuesOfType(
195+
[ParameterString, ParameterNumber, ParameterFile,
196+
ParameterTableField, ParameterExpression], OutputString)
197+
for text, data in [(self.dialog.resolveValueDescription(s), s) for s in strings]:
198+
self._combo.addItem(text, data)
199+
200+
self.setComboValue(value, self._combo)
201+
202+
def setValue(self, value):
203+
self.setComboValue(value, self._combo)
204+
self.widgetValueHasChanged.emit(self)
205+
206+
def value(self):
207+
return self.comboValue(combobox=self._combo)

0 commit comments

Comments
 (0)