Skip to content

Commit

Permalink
[v0.4.0] New option to calculate the expression on existing features …
Browse files Browse the repository at this point in the history
…right before creating an AutoField.
  • Loading branch information
gacarrillor committed Sep 9, 2016
1 parent 65c0ace commit 73eda01
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 12 deletions.
16 changes: 12 additions & 4 deletions AutoFieldManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from PyQt4.QtGui import QApplication

from EventManager import EventManager
from FieldCalculator import FieldCalculator

class AutoFieldManager( QObject ):
""" Class in charge of the AutoFields administration.
Expand All @@ -52,9 +53,11 @@ def __init__( self, messageManager, iface, settingsPrefix="/AutoFields", organiz
self.eventManager.attributesDeletedCheckIfAutoFields.connect( self.checkAndDisableAutoFieldsForLayer )

self.eventManager.setAFM( self )

self.fieldCalculator = FieldCalculator( self.msg, iface )


def createAutoField( self, layer, fieldName, expression, layer2="", field2="" ):
def createAutoField( self, layer, fieldName, expression, layer2="", field2="", calculateOnExisting=True ):
""" Add AutoField properties to both QSettings and dictAutoFields """
if not layer or not type(layer) is QgsVectorLayer:
self.msg.show(
Expand Down Expand Up @@ -115,7 +118,7 @@ def createAutoField( self, layer, fieldName, expression, layer2="", field2="" ):
self.msg.show( QApplication.translate( "AutoFieldManager",
"[Error] 'expression' variable has not a valid value." ),
'warning' )
return False
return False

autoFieldId = self.buildAutoFieldId( layer, fieldName )

Expand All @@ -127,6 +130,11 @@ def createAutoField( self, layer, fieldName, expression, layer2="", field2="" ):
'warning' )
return False


if calculateOnExisting:
self.fieldCalculator.calculate( layer, fieldName, expression )


# Create AutoField in dictionary
if not self.dictAutoFields:
order = 1
Expand All @@ -150,12 +158,12 @@ def createAutoField( self, layer, fieldName, expression, layer2="", field2="" ):
return autoFieldId


def overwriteAutoField( self, layer, fieldName, expression, layer2="", field2="" ):
def overwriteAutoField( self, layer, fieldName, expression, layer2="", field2="", calculateOnExisting=True ):
""" Logic to overwrite an existing AutoField in both QSettings and dictAutoFields """
autoFieldId = self.buildAutoFieldId( layer, fieldName )
if autoFieldId in self.dictAutoFields:
self.removeAutoField( autoFieldId )
return self.createAutoField( layer, fieldName, expression, layer2, field2 )
return self.createAutoField( layer, fieldName, expression, layer2, field2, calculateOnExisting )

return False

Expand Down
18 changes: 15 additions & 3 deletions AutoFieldsDockWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ def __init__( self, parent, iface, autoFieldManager, messageManager, language='e
self.autoFieldManager.settingsPrefix + "/showOnlyEnabledAutoFields",
True, type=bool )
self.chkOnlyEnabledAutoFields.setChecked( check )
check = settings.value(
self.autoFieldManager.settingsPrefix + "/calculateOnExistingFeatures",
True, type=bool )
self.chkCalculateOnExisting.setChecked( check )
self.btnRemoveAutoFields.setEnabled( False )
self.tblAutoFields.sortItems(0, Qt.AscendingOrder)
self.populateAutoFieldsTable()
Expand All @@ -106,6 +110,7 @@ def __init__( self, parent, iface, autoFieldManager, messageManager, language='e
self.autoFieldManager.autoFieldDisabled.connect( self.populateAutoFieldsTable )
self.tblAutoFields.itemSelectionChanged.connect( self.updateRemoveAutoFieldButton )
self.chkOnlyEnabledAutoFields.toggled.connect( self.saveShowOnlyEnabledPreference )
self.chkCalculateOnExisting.toggled.connect( self.saveCalculateOnExistingPreference )
self.btnRemoveAutoFields.clicked.connect( self.removeAutoFieldFromTable )

# About Tab
Expand Down Expand Up @@ -405,6 +410,7 @@ def doSaveAutoField( self, layer, fieldName, expression ):
""" Repetitive logic to save or overwrite an AutoField """
# Check if the field is an AutoField and ask if we should overwrite it
res = True
bCalculateOnExisting = self.chkCalculateOnExisting.isChecked()
if self.autoFieldManager.isFieldAnAutoField( layer, fieldName ):
reply = QMessageBox.question( self.iface.mainWindow(),
QApplication.translate( "AutoFieldsDockWidgetPy", "Confirmation" ),
Expand All @@ -416,10 +422,10 @@ def doSaveAutoField( self, layer, fieldName, expression ):
QMessageBox.Yes | QMessageBox.No, QMessageBox.No )

if reply == QMessageBox.Yes:
res = self.autoFieldManager.overwriteAutoField( layer, fieldName, expression )
res = self.autoFieldManager.overwriteAutoField( layer, fieldName, expression, calculateOnExisting=bCalculateOnExisting )

else:
res = self.autoFieldManager.createAutoField( layer, fieldName, expression )
res = self.autoFieldManager.createAutoField( layer, fieldName, expression, calculateOnExisting=bCalculateOnExisting )

if not res:
# res will only be False if create/overwriteAutoField return False
Expand Down Expand Up @@ -592,7 +598,13 @@ def saveShowOnlyEnabledPreference( self, status ):
settings = QSettings()
settings.setValue( self.autoFieldManager.settingsPrefix + "/showOnlyEnabledAutoFields" , status )
self.populateAutoFieldsTable()



def saveCalculateOnExistingPreference( self, status ):
""" Saves the preference in QSettings """
settings = QSettings()
settings.setValue( self.autoFieldManager.settingsPrefix + "/calculateOnExistingFeatures" , status )


def openDocumentation( self ):
""" Open a browser to show documentation page """
Expand Down
94 changes: 94 additions & 0 deletions FieldCalculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# -*- coding:utf-8 -*-
"""
/***************************************************************************
AutoFields
A QGIS plugin
Automatic attribute updates when creating or modifying vector features
-------------------
begin : 2016-09-08
copyright : (C) 2016 by Germán Carrillo (GeoTux)
email : [email protected]
Adapted from : https://github.com/qgis/QGIS/blob/322da8b2cf522bc0d6e5d1ba03f4f0597cdf09d2/python/plugins/processing/algs/qgis/FieldsCalculator.py
***************************************************************************/
/***************************************************************************
* *
* 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.core import ( QgsExpression, QgsExpressionContext,
QgsExpressionContextUtils, QgsDistanceArea, QgsProject, QGis, GEO_NONE )
from PyQt4.QtGui import QApplication

class FieldCalculator():
""" Class to perform field calculations on existing features.
Not the core of the plugin, but a helpful option.
Adapted from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py
"""

def __init__( self, messageManager, iface ):
self.msg = messageManager
self.iface = iface


def calculate( self, layer, fieldName, expression ):
if ( layer.featureCount() == 0 ):
self.msg.show( "[Info] * No existing features on layer " + layer.name() + " to calculate expression.", 'info', True )
return

expression = QgsExpression( expression )
if expression.hasParserError():
self.msg.show( QApplication.translate( "AutoFields-FieldCalculator", "[Error] (Parsing) " ) + \
expression.parserErrorString(), 'critical' )
return

context = QgsExpressionContext()
context.appendScope( QgsExpressionContextUtils.globalScope() )
context.appendScope( QgsExpressionContextUtils.projectScope() )
context.appendScope( QgsExpressionContextUtils.layerScope( layer ) )
context.setFields( layer.fields() )

if expression.needsGeometry():
if self.iface:
# This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py
da = QgsDistanceArea()
da.setSourceCrs( layer.crs().srsid() )
da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() )
da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] )
expression.setGeomCalculator( da )
if QGis.QGIS_VERSION_INT >= 21400: # Methods added in QGIS 2.14
expression.setDistanceUnits( QgsProject.instance().distanceUnits() )
expression.setAreaUnits( QgsProject.instance().areaUnits() )

expression.prepare( context )

fieldIndex = layer.fieldNameIndex( fieldName )
if fieldIndex == -1:
return
field = layer.fields()[fieldIndex]

dictResults = {}
for feature in layer.getFeatures():
context.setFeature( feature )
result = expression.evaluate( context )
if expression.hasEvalError():
self.msg.show( QApplication.translate( "AutoFields-FieldCalculator", "[Error] (Evaluating) " ) + \
expression.evalErrorString(), 'critical' )
return

dictResults[feature.id()] = { fieldIndex: field.convertCompatible( result ) }


layer.dataProvider().changeAttributeValues( dictResults )

self.msg.show( "[Info] * An expression was calculated on existing features of layer " + layer.name() + ", field " + fieldName + ".", 'info', True )





49 changes: 47 additions & 2 deletions Ui_AutoFields_dock.ui
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<y>-383</y>
<width>288</width>
<height>726</height>
<height>775</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
Expand Down Expand Up @@ -591,6 +591,51 @@
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_10">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="chkCalculateOnExisting">
<property name="toolTip">
<string>If there are features in this layer already, enabling this option calculates the expression on them</string>
</property>
<property name="text">
<string>Calculate expression on existing features</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_12">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
Expand Down
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def description():
return "Automatic vector field updates when modifying or creating features"

def version():
return "Version 0.3.0"
return "Version 0.4.0"

def qgisMinimumVersion():
return "2.12"
Expand Down
2 changes: 2 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Changes:
[0.4.0] (20160909)
- New option to calculate the expression on existing features.
[0.3.0] (20160817)
- Official release!
- AutoFieldManager: normalize sources from 'Add PostgreSQL layer' and
Expand Down
3 changes: 2 additions & 1 deletion i18n/AutoFields.pro
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FORMS = ../Ui_AutoFields_dock.ui \

SOURCES = ../EventManager.py \
../AutoFieldManager.py \
../AutoFieldsDockWidget.py
../AutoFieldsDockWidget.py \
../FieldCalculator.py

TRANSLATIONS = AutoFields_es.ts
19 changes: 19 additions & 0 deletions i18n/AutoFields_es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ Necesitarías exportar los datos a otro formato para agregar AutoFields.</transl
<translation>, por lo cual no pudo ser removido.</translation>
</message>
</context>
<context>
<name>AutoFields-FieldCalculator</name>
<message>
<source>[Error] (Parsing) </source>
<translation>[Error] (Parseando) </translation>
</message>
<message>
<source>[Error] (Evaluating) </source>
<translation>[Error] (Evaluando) </translation>
</message>
</context>
<context>
<name>AutoFieldsDockWidget</name>
<message>
Expand Down Expand Up @@ -334,6 +345,14 @@ Marcela Suárez&lt;br/&gt;
<source>Save AutoFields</source>
<translation>Guardar AutoFields</translation>
</message>
<message>
<source>If there are features in this layer already, enabling this option calculates the expression on them</source>
<translation>Si ya existen registros en esta capa, habilita esta opción para calcular la expresión sobre ellos.</translation>
</message>
<message>
<source>Calculate expression on existing features</source>
<translation>Calcular expresión en registros existentes</translation>
</message>
</context>
<context>
<name>AutoFieldsDockWidgetPy</name>
Expand Down
4 changes: 3 additions & 1 deletion metadata.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
[general]
name=AutoFields
description=Automatic attribute updates when creating or modifying vector features
version=0.3.0
version=0.4.0
qgisMinimumVersion=2.12
category=Vector
author=Germán Carrillo (GeoTux)
[email protected]
changelog=
[0.4.0] (20160909)
- New option to calculate the expression on existing features.
[0.3.0] (20160817)
- Official release!
- AutoFieldManager: normalize sources from 'Add PostgreSQL layer' and
Expand Down

0 comments on commit 73eda01

Please sign in to comment.