Skip to content

Commit 7318c73

Browse files
committed
Convert values to target field format
For the field calculator and virtual fields. Fix #11000 Fix #10995 Fix #10993
1 parent 11e3044 commit 7318c73

File tree

5 files changed

+95
-2
lines changed

5 files changed

+95
-2
lines changed

python/core/qgsfield.sip

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,65 @@ public:
110110

111111
/**Formats string for display*/
112112
QString displayString( const QVariant& v ) const;
113+
114+
115+
/**
116+
* Converts the provided variant to a compatible format
117+
*
118+
* @param v The value to convert
119+
*
120+
* @return True if the conversion was successful
121+
*/
122+
QVariant convertCompatible( QVariant& v ) const;
123+
%MethodCode
124+
PyObject *sipParseErr = NULL;
125+
126+
{
127+
QVariant * a0;
128+
int a0State = 0;
129+
const QgsField *sipCpp;
130+
131+
if (sipParseArgs(&sipParseErr, sipArgs, "BJ1", &sipSelf, sipType_QgsField, &sipCpp, sipType_QVariant,&a0, &a0State))
132+
{
133+
bool sipRes;
134+
135+
Py_BEGIN_ALLOW_THREADS
136+
try
137+
{
138+
QgsDebugMsg( a0->toString() );
139+
sipRes = sipCpp->convertCompatible(*a0);
140+
QgsDebugMsg( a0->toString() );
141+
}
142+
catch (...)
143+
{
144+
Py_BLOCK_THREADS
145+
146+
sipReleaseType(a0,sipType_QVariant,a0State);
147+
sipRaiseUnknownException();
148+
return NULL;
149+
}
150+
151+
Py_END_ALLOW_THREADS
152+
153+
PyObject* res = sipConvertFromType( a0, sipType_QVariant, NULL );
154+
sipReleaseType(a0,sipType_QVariant,a0State);
155+
156+
if ( !sipRes )
157+
{
158+
PyErr_SetString(PyExc_ValueError,
159+
QString( "Value %1 (%2) could not be converted to field type %3." ).arg( a0->toString() ).arg ( a0->typeName() ).arg( sipCpp->type() ).toUtf8().constData() );
160+
sipError = sipErrorFail;
161+
}
162+
163+
return res;
164+
}
165+
}
166+
167+
/* Raise an exception if the arguments couldn't be parsed. */
168+
sipNoMethod(sipParseErr, sipName_QgsField, sipName_convertCompatible, doc_QgsField_convertCompatible);
169+
170+
return NULL;
171+
%End
113172
}; // class QgsField
114173

115174

src/app/qgsfieldcalculator.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ void QgsFieldCalculator::accept()
127127
return;
128128
}
129129

130+
const QgsField& field = mVectorLayer->pendingFields()[mAttributeId];
131+
130132
QApplication::setOverrideCursor( Qt::WaitCursor );
131133

132134
mVectorLayer->beginEditCommand( "Field calculator" );
@@ -198,7 +200,7 @@ void QgsFieldCalculator::accept()
198200
bool newField = !mUpdateExistingGroupBox->isChecked();
199201
QVariant emptyAttribute;
200202
if ( newField )
201-
emptyAttribute = QVariant( mVectorLayer->pendingFields()[mAttributeId].type() );
203+
emptyAttribute = QVariant( field.type() );
202204

203205
QgsFeatureIterator fit = mVectorLayer->getFeatures( QgsFeatureRequest().setFlags( useGeometry ? QgsFeatureRequest::NoFlags : QgsFeatureRequest::NoGeometry ) );
204206
while ( fit.nextFeature( feature ) )
@@ -210,9 +212,9 @@ void QgsFieldCalculator::accept()
210212
continue;
211213
}
212214
}
213-
214215
exp.setCurrentRowNumber( rownum );
215216
QVariant value = exp.evaluate( &feature );
217+
field.convertCompatible( value );
216218
if ( exp.hasEvalError() )
217219
{
218220
calculationSuccess = false;

src/core/qgsfield.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "qgsfield.h"
1818

1919
#include <QSettings>
20+
#include <QtCore/qmath.h>
2021

2122
#if 0
2223
QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
@@ -128,6 +129,27 @@ QString QgsField::displayString( const QVariant& v ) const
128129
return v.toString();
129130
}
130131

132+
bool QgsField::convertCompatible( QVariant& v ) const
133+
{
134+
if ( v.isNull() )
135+
{
136+
v.convert( mType );
137+
return true;
138+
}
139+
140+
if ( !v.convert( mType ) )
141+
{
142+
return false;
143+
}
144+
145+
if ( mType == QVariant::Double && mPrecision > 0 )
146+
{
147+
v = qRound64( v.toDouble() * qPow( 10, mPrecision ) ) / qPow( 10, mPrecision );
148+
return true;
149+
}
150+
151+
return true;
152+
}
131153

132154
////////////////////////////////////////////////////////////////////////////
133155

src/core/qgsfield.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,15 @@ class CORE_EXPORT QgsField
129129
/** Formats string for display*/
130130
QString displayString( const QVariant& v ) const;
131131

132+
/**
133+
* Converts the provided variant to a compatible format
134+
*
135+
* @param v The value to convert
136+
*
137+
* @return True if the conversion was successful
138+
*/
139+
bool convertCompatible( QVariant& v ) const;
140+
132141
private:
133142

134143
//! Name

src/core/qgsvectorlayerfeatureiterator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ void QgsVectorLayerFeatureIterator::addVirtualAttributes( QgsFeature& f )
559559
{
560560
QgsExpression* exp = it.value();
561561
QVariant val = exp->evaluate( f );
562+
mSource->mFields.at( it.key() ).convertCompatible( val );;
562563
f.setAttribute( it.key(), val );
563564
}
564565
}

0 commit comments

Comments
 (0)