mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-11-04 00:04:25 -05:00 
			
		
		
		
	Prevent changes to files that weren't changed between releases. This eases review of the changes between releases significantly.
		
			
				
	
	
		
			218 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# -*- coding: utf-8 -*-
 | 
						|
 | 
						|
"""
 | 
						|
***************************************************************************
 | 
						|
    FieldsMapper.py
 | 
						|
    ---------------------
 | 
						|
    Date                 : October 2014
 | 
						|
    Copyright            : (C) 2014 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.                                   *
 | 
						|
*                                                                         *
 | 
						|
***************************************************************************
 | 
						|
"""
 | 
						|
 | 
						|
__author__ = 'Arnaud Morvan'
 | 
						|
__date__ = 'October 2014'
 | 
						|
__copyright__ = '(C) 2014, Arnaud Morvan'
 | 
						|
 | 
						|
from qgis.core import (
 | 
						|
    QgsDistanceArea,
 | 
						|
    QgsExpression,
 | 
						|
    QgsField,
 | 
						|
    QgsFields,
 | 
						|
    QgsProcessing,
 | 
						|
    QgsProcessingException,
 | 
						|
    QgsProcessingParameterDefinition,
 | 
						|
    QgsProcessingParameterType,
 | 
						|
    NULL)
 | 
						|
 | 
						|
from qgis.PyQt.QtCore import QCoreApplication
 | 
						|
 | 
						|
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
 | 
						|
 | 
						|
 | 
						|
class FieldsMapper(QgisFeatureBasedAlgorithm):
 | 
						|
 | 
						|
    INPUT_LAYER = 'INPUT_LAYER'
 | 
						|
    FIELDS_MAPPING = 'FIELDS_MAPPING'
 | 
						|
    OUTPUT_LAYER = 'OUTPUT_LAYER'
 | 
						|
 | 
						|
    def group(self):
 | 
						|
        return self.tr('Vector table')
 | 
						|
 | 
						|
    def groupId(self):
 | 
						|
        return 'vectortable'
 | 
						|
 | 
						|
    def tags(self):
 | 
						|
        return self.tr('attributes,table').split(',')
 | 
						|
 | 
						|
    def initParameters(self, config=None):
 | 
						|
        fields_mapping = FieldsMapper.ParameterFieldsMapping(self.FIELDS_MAPPING,
 | 
						|
                                                             description=self.tr('Fields mapping'))
 | 
						|
        fields_mapping.setMetadata({
 | 
						|
            'widget_wrapper': 'processing.algs.qgis.ui.FieldsMappingPanel.FieldsMappingWidgetWrapper'
 | 
						|
        })
 | 
						|
        self.addParameter(fields_mapping)
 | 
						|
 | 
						|
    def name(self):
 | 
						|
        return 'refactorfields'
 | 
						|
 | 
						|
    def displayName(self):
 | 
						|
        return self.tr('Refactor fields')
 | 
						|
 | 
						|
    def outputName(self):
 | 
						|
        return self.tr('Refactored')
 | 
						|
 | 
						|
    def inputLayerTypes(self):
 | 
						|
        return [QgsProcessing.TypeVector]
 | 
						|
 | 
						|
    def parameterAsFieldsMapping(self, parameters, name, context):
 | 
						|
        return parameters[name]
 | 
						|
 | 
						|
    def supportInPlaceEdit(self, layer):
 | 
						|
        return False
 | 
						|
 | 
						|
    def prepareAlgorithm(self, parameters, context, feedback):
 | 
						|
        source = self.parameterAsSource(parameters, 'INPUT', context)
 | 
						|
        if source is None:
 | 
						|
            raise QgsProcessingException(self.invalidSourceError(parameters, 'INPUT'))
 | 
						|
 | 
						|
        mapping = self.parameterAsFieldsMapping(parameters, self.FIELDS_MAPPING, context)
 | 
						|
 | 
						|
        self.fields = QgsFields()
 | 
						|
        self.expressions = []
 | 
						|
 | 
						|
        da = QgsDistanceArea()
 | 
						|
        da.setSourceCrs(source.sourceCrs(), context.transformContext())
 | 
						|
        da.setEllipsoid(context.project().ellipsoid())
 | 
						|
 | 
						|
        # create an expression context using thread safe processing context
 | 
						|
        self.expr_context = self.createExpressionContext(parameters, context, source)
 | 
						|
 | 
						|
        for field_def in mapping:
 | 
						|
            self.fields.append(QgsField(name=field_def['name'],
 | 
						|
                                        type=field_def['type'],
 | 
						|
                                        typeName="",
 | 
						|
                                        len=field_def.get('length', 0),
 | 
						|
                                        prec=field_def.get('precision', 0)))
 | 
						|
            if field_def['expression']:
 | 
						|
                expression = QgsExpression(field_def['expression'])
 | 
						|
                expression.setGeomCalculator(da)
 | 
						|
                expression.setDistanceUnits(context.project().distanceUnits())
 | 
						|
                expression.setAreaUnits(context.project().areaUnits())
 | 
						|
                if expression.hasParserError():
 | 
						|
                    feedback.reportError(
 | 
						|
                        self.tr(u'Parser error in expression "{}": {}')
 | 
						|
                        .format(expression.expression(),
 | 
						|
                                expression.parserErrorString()))
 | 
						|
                    return False
 | 
						|
                self.expressions.append(expression)
 | 
						|
            else:
 | 
						|
                self.expressions.append(None)
 | 
						|
        return True
 | 
						|
 | 
						|
    def outputFields(self, inputFields):
 | 
						|
        return self.fields
 | 
						|
 | 
						|
    def processAlgorithm(self, parameters, context, feeback):
 | 
						|
        for expression in self.expressions:
 | 
						|
            if expression is not None:
 | 
						|
                expression.prepare(self.expr_context)
 | 
						|
        self._row_number = 0
 | 
						|
        return super().processAlgorithm(parameters, context, feeback)
 | 
						|
 | 
						|
    def processFeature(self, feature, context, feedback):
 | 
						|
        attributes = []
 | 
						|
        for expression in self.expressions:
 | 
						|
            if expression is not None:
 | 
						|
                self.expr_context.setFeature(feature)
 | 
						|
                self.expr_context.lastScope().setVariable("row_number", self._row_number)
 | 
						|
                value = expression.evaluate(self.expr_context)
 | 
						|
                if expression.hasEvalError():
 | 
						|
                    raise QgsProcessingException(
 | 
						|
                        self.tr(u'Evaluation error in expression "{}": {}')
 | 
						|
                            .format(expression.expression(),
 | 
						|
                                    expression.evalErrorString()))
 | 
						|
                attributes.append(value)
 | 
						|
            else:
 | 
						|
                attributes.append(NULL)
 | 
						|
        feature.setAttributes(attributes)
 | 
						|
        self._row_number += 1
 | 
						|
        return [feature]
 | 
						|
 | 
						|
    class ParameterFieldsMappingType(QgsProcessingParameterType):
 | 
						|
 | 
						|
        def __init__(self):
 | 
						|
            super().__init__()
 | 
						|
 | 
						|
        def create(self, name):
 | 
						|
            return FieldsMapper.ParameterFieldsMapping(name)
 | 
						|
 | 
						|
        def metadata(self):
 | 
						|
            return {'widget_wrapper': 'processing.algs.qgis.ui.FieldsMappingPanel.FieldsMappingWidgetWrapper'}
 | 
						|
 | 
						|
        def name(self):
 | 
						|
            return QCoreApplication.translate('Processing', 'Fields Mapper')
 | 
						|
 | 
						|
        def id(self):
 | 
						|
            return 'fields_mapping'
 | 
						|
 | 
						|
        def pythonImportString(self):
 | 
						|
            return 'from processing.algs.qgis.FieldsMapper import FieldsMapper'
 | 
						|
 | 
						|
        def className(self):
 | 
						|
            return 'FieldsMapper.ParameterFieldsMapping'
 | 
						|
 | 
						|
        def description(self):
 | 
						|
            return QCoreApplication.translate('Processing', 'A mapping of field names to field type definitions and expressions. Used for the refactor fields algorithm.')
 | 
						|
 | 
						|
    class ParameterFieldsMapping(QgsProcessingParameterDefinition):
 | 
						|
 | 
						|
        def __init__(self, name, description='', parentLayerParameterName='INPUT'):
 | 
						|
            super().__init__(name, description)
 | 
						|
            self._parentLayerParameter = parentLayerParameterName
 | 
						|
 | 
						|
        def clone(self):
 | 
						|
            copy = FieldsMapper.ParameterFieldsMapping(self.name(), self.description(), self._parentLayerParameter)
 | 
						|
            return copy
 | 
						|
 | 
						|
        def type(self):
 | 
						|
            return self.typeName()
 | 
						|
 | 
						|
        @staticmethod
 | 
						|
        def typeName():
 | 
						|
            return 'fields_mapping'
 | 
						|
 | 
						|
        def checkValueIsAcceptable(self, value, context=None):
 | 
						|
            if not isinstance(value, list):
 | 
						|
                return False
 | 
						|
            for field_def in value:
 | 
						|
                if not isinstance(field_def, dict):
 | 
						|
                    return False
 | 
						|
                if 'name' not in field_def.keys():
 | 
						|
                    return False
 | 
						|
                if 'type' not in field_def.keys():
 | 
						|
                    return False
 | 
						|
                if 'expression' not in field_def.keys():
 | 
						|
                    return False
 | 
						|
            return True
 | 
						|
 | 
						|
        def valueAsPythonString(self, value, context):
 | 
						|
            return str(value)
 | 
						|
 | 
						|
        def asScriptCode(self):
 | 
						|
            raise NotImplementedError()
 | 
						|
 | 
						|
        @classmethod
 | 
						|
        def fromScriptCode(cls, name, description, isOptional, definition):
 | 
						|
            raise NotImplementedError()
 | 
						|
 | 
						|
        def parentLayerParameter(self):
 | 
						|
            return self._parentLayerParameter
 |