Skip to content
Permalink
Browse files

Merge pull request #3044 from arnaud-morvan/processing_output_vectort…

…able

Processing - Output tables with no geometry through OutputVector
  • Loading branch information
volaya committed May 18, 2016
2 parents a9c1996 + 7847f97 commit fc0853542914763a3ca10b2c371221e922c313fd
@@ -30,7 +30,7 @@
from qgis.utils import iface
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterTable
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector

@@ -52,13 +52,15 @@ def __init__(self):
def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Refactor fields')
self.group, self.i18n_group = self.trAlgorithm('Vector table tools')
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer'),
[ParameterVector.VECTOR_TYPE_ANY], False))
self.addParameter(ParameterTable(self.INPUT_LAYER,
self.tr('Input layer'),
False))
self.addParameter(ParameterFieldsMapping(self.FIELDS_MAPPING,
self.tr('Fields mapping'), self.INPUT_LAYER))
self.tr('Fields mapping'),
self.INPUT_LAYER))
self.addOutput(OutputVector(self.OUTPUT_LAYER,
self.tr('Refactored')))
self.tr('Refactored'),
base_input=self.INPUT_LAYER))

def processAlgorithm(self, progress):
layer = self.getParameterValue(self.INPUT_LAYER)
@@ -120,7 +122,9 @@ def processAlgorithm(self, progress):
for current, inFeat in enumerate(features):
rownum = current + 1

outFeat.setGeometry(inFeat.geometry())
geometry = inFeat.geometry()
if geometry is not None:
outFeat.setGeometry(geometry)

attrs = []
for i in xrange(0, len(mapping)):
@@ -56,7 +56,8 @@ def getWidgetFromParameter(self, param):
else:
items = []
self.dependentItems[param.parent] = items
items.append(param.name)
items.append(param)

parent = self.alg.getParameterFromName(param.parent)
if isinstance(parent, ParameterVector):
layers = dataobjects.getVectorLayers(parent.shapetype)
@@ -76,16 +77,17 @@ def updateDependentFields(self):
layer = sender.itemData(sender.currentIndex())
children = self.dependentItems[sender.name]
for child in children:
widget = self.valueItems[child]
widget = self.valueItems[child.name]
if isinstance(widget, FieldsMappingPanel):
widget.setLayer(layer)
ParametersPanel.updateDependentFields(self)

def somethingDependsOnThisParameter(self, parent):
for param in self.alg.parameters:
if isinstance(param, ParameterFieldsMapping):
if param.parent == parent.name:
return True
return False
return ParametersPanel.somethingDependsOnThisParameter(self, parent)


class FieldsMapperParametersDialog(AlgorithmDialog):
@@ -463,7 +463,7 @@ def on_model_rowsInserted(self, parent, start, end):
self.model.index(end, self.model.columnCount() - 1))

def updateLayerCombo(self):
layers = dataobjects.getVectorLayers()
layers = dataobjects.getTables()
layers.sort(key=lambda lay: lay.name())
for layer in layers:
self.layerCombo.addItem(layer.name(), layer)
@@ -354,7 +354,7 @@ def checkOutputFileExtensions(self):
out.value = out.value + '.' + exts[0]
else:
ext = out.value[idx + 1:]
if ext not in exts:
if ext not in exts + ['dbf']:
out.value = out.value + '.' + exts[0]

def resolveTemporaryOutputs(self):
@@ -250,15 +250,34 @@ class OutputVector(Output):
encoding = None
compatible = None

def getFileFilter(self, alg):
def __init__(self, name='', description='', hidden=False, base_input=None):
Output.__init__(self, name, description, hidden)
self.base_input = base_input
self.base_layer = None

def hasGeometry(self):
if self.base_layer is None:
return True
return dataobjects.canUseVectorLayer(self.base_layer, [-1])

def getSupportedOutputVectorLayerExtensions(self):
exts = dataobjects.getSupportedOutputVectorLayerExtensions()
if not self.hasGeometry():
exts = ['dbf'] + [ext for ext in exts if ext in VectorWriter.nogeometry_extensions]
return exts

def getFileFilter(self, alg):
exts = self.getSupportedOutputVectorLayerExtensions()
for i in range(len(exts)):
exts[i] = self.tr('%s files (*.%s)', 'OutputVector') % (exts[i].upper(), exts[i].lower())
return ';;'.join(exts)

def getDefaultFileExtension(self, alg):
supported = alg.provider.getSupportedOutputVectorLayerExtensions()
default = ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT)
supported = self.getSupportedOutputVectorLayerExtensions()
if self.hasGeometry():
default = ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT)
else:
default = 'dbf'
ext = default if default in supported else supported[0]
return ext

@@ -271,9 +290,8 @@ def getCompatibleFileName(self, alg):
temporary file with a supported file format, to be used to
generate the output result.
"""

ext = self.value[self.value.rfind('.') + 1:]
if ext in alg.provider.getSupportedOutputVectorLayerExtensions():
if ext in self.getSupportedOutputVectorLayerExtensions():
return self.value
else:
if self.compatible is None:
@@ -307,4 +325,5 @@ def getVectorWriter(self, fields, geomType, crs, options=None):
w = VectorWriter(self.value, self.encoding, fields, geomType,
crs, options)
self.layer = w.layer
self.value = w.destination
return w
@@ -142,7 +142,9 @@ def saveToPostGIS(self):
password = settings.value(mySettings + '/password')
uri = QgsDataSourceURI()
uri.setConnection(host, str(port), dbname, user, password)
uri.setDataSource(dlg.schema, dlg.table, "the_geom")
uri.setDataSource(dlg.schema, dlg.table,
"the_geom" if self.output.hasGeometry() else None)

connInfo = uri.connectionInfo()
(success, user, passwd) = QgsCredentials.instance().get(connInfo, None, None)
if success:
@@ -182,7 +184,8 @@ def saveToSpatialite(self):

uri = QgsDataSourceURI()
uri.setDatabase(fileName)
uri.setDataSource('', self.output.name.lower(), 'the_geom')
uri.setDataSource('', self.output.name.lower(),
'the_geom' if self.output.hasGeometry() else None)
self.leText.setText("spatialite:" + uri.uri())

def saveToMemory(self):
@@ -259,6 +259,22 @@ def initWidgets(self):
self.checkBoxes[output.name] = check
self.valueItems[output.name] = widget

if isinstance(output, OutputVector):
if output.base_input in self.dependentItems:
items = self.dependentItems[output.base_input]
else:
items = []
self.dependentItems[output.base_input] = items
items.append(output)

base_input = self.alg.getParameterFromName(output.base_input)
if isinstance(base_input, ParameterVector):
layers = dataobjects.getVectorLayers(base_input.shapetype)
else:
layers = dataobjects.getTables()
if len(layers) > 0:
output.base_layer = layers[0]

def buttonToggled(self, value):
if value:
sender = self.sender()
@@ -343,7 +359,7 @@ def getWidgetFromParameter(self, param):
else:
items = []
self.dependentItems[param.parent] = items
items.append(param.name)
items.append(param)
parent = self.alg.getParameterFromName(param.parent)
if isinstance(parent, ParameterVector):
layers = dataobjects.getVectorLayers(parent.shapetype)
@@ -434,12 +450,15 @@ def updateDependentFields(self):
return
children = self.dependentItems[sender.name]
for child in children:
widget = self.valueItems[child]
widget.clear()
if self.alg.getParameterFromName(child).optional:
widget.addItem(self.tr('[not set]'))
widget.addItems(self.getFields(layer,
self.alg.getParameterFromName(child).datatype))
if isinstance(child, ParameterTableField):
widget = self.valueItems[child.name]
widget.clear()
if self.alg.getParameterFromName(child).optional:
widget.addItem(self.tr('[not set]'))
widget.addItems(self.getFields(layer,
self.alg.getParameterFromName(child).datatype))
if isinstance(child, OutputVector):
child.base_layer = layer

def getFields(self, layer, datatype):
fieldTypes = []
@@ -460,4 +479,8 @@ def somethingDependsOnThisParameter(self, parent):
if isinstance(param, ParameterTableField):
if param.parent == parent.name:
return True
for output in self.alg.outputs:
if isinstance(output, OutputVector):
if output.base_layer == parent.name:
return True
return False
@@ -47,6 +47,7 @@


GEOM_TYPE_MAP = {
QGis.WKBNoGeometry: 'none',
QGis.WKBPoint: 'Point',
QGis.WKBLineString: 'LineString',
QGis.WKBPolygon: 'Polygon',
@@ -535,6 +536,13 @@ class VectorWriter:
POSTGIS_LAYER_PREFIX = 'postgis:'
SPATIALITE_LAYER_PREFIX = 'spatialite:'

nogeometry_extensions = [
u'csv',
u'dbf',
u'ods',
u'xlsx',
]

def __init__(self, destination, encoding, fields, geometryType,
crs, options=None):
self.destination = destination
@@ -592,9 +600,10 @@ def _runSQL(sql):
for f in fields)

_runSQL("CREATE TABLE %s.%s (%s)" % (uri.schema(), uri.table().lower(), fieldsdesc))
_runSQL("SELECT AddGeometryColumn('{schema}', '{table}', 'the_geom', {srid}, '{typmod}', 2)".format(
table=uri.table().lower(), schema=uri.schema(), srid=crs.authid().split(":")[-1],
typmod=GEOM_TYPE_MAP[geometryType].upper()))
if geometryType != QGis.WKBNoGeometry:
_runSQL("SELECT AddGeometryColumn('{schema}', '{table}', 'the_geom', {srid}, '{typmod}', 2)".format(
table=uri.table().lower(), schema=uri.schema(), srid=crs.authid().split(":")[-1],
typmod=GEOM_TYPE_MAP[geometryType].upper()))

self.layer = QgsVectorLayer(uri.uri(), uri.table(), "postgres")
self.writer = self.layer.dataProvider()
@@ -622,9 +631,10 @@ def _runSQL(sql):

_runSQL("DROP TABLE IF EXISTS %s" % uri.table().lower())
_runSQL("CREATE TABLE %s (%s)" % (uri.table().lower(), fieldsdesc))
_runSQL("SELECT AddGeometryColumn('{table}', 'the_geom', {srid}, '{typmod}', 2)".format(
table=uri.table().lower(), srid=crs.authid().split(":")[-1],
typmod=GEOM_TYPE_MAP[geometryType].upper()))
if geometryType != QGis.WKBNoGeometry:
_runSQL("SELECT AddGeometryColumn('{table}', 'the_geom', {srid}, '{typmod}', 2)".format(
table=uri.table().lower(), srid=crs.authid().split(":")[-1],
typmod=GEOM_TYPE_MAP[geometryType].upper()))

self.layer = QgsVectorLayer(uri.uri(), uri.table(), "spatialite")
self.writer = self.layer.dataProvider()
@@ -636,12 +646,22 @@ def _runSQL(sql):
extension = extension[extension.find('*.') + 2:]
extension = extension[:extension.find(' ')]
OGRCodes[extension] = value
OGRCodes['dbf'] = "DBF file"

extension = self.destination[self.destination.rfind('.') + 1:]

if extension not in OGRCodes:
extension = 'shp'
self.destination = self.destination + '.shp'

if geometryType == QGis.WKBNoGeometry:
if extension == 'shp':
extension = 'dbf'
self.destination = self.destination[:self.destination.rfind('.')] + '.dbf'
if extension not in self.nogeometry_extensions:
raise GeoAlgorithmExecutionException(
"Unsupported format for tables with no geometry")

qgsfields = QgsFields()
for field in fields:
qgsfields.append(_toQgsField(field))

0 comments on commit fc08535

Please sign in to comment.
You can’t perform that action at this time.