Skip to content

Commit c5546b0

Browse files
committed
Allow conversion of QgsPropertyTransfomers to expressions (when possible)
1 parent ac55f39 commit c5546b0

File tree

5 files changed

+143
-8
lines changed

5 files changed

+143
-8
lines changed

python/core/qgspropertytransformer.sip

+7
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class QgsPropertyTransformer
4545
void setMaxValue( double max );
4646

4747
virtual QVariant transform( const QgsExpressionContext& context, const QVariant& value ) const = 0;
48+
virtual QString toExpression( const QString& baseExpression ) const = 0;
4849

4950
};
5051

@@ -77,6 +78,7 @@ class QgsSizeScaleTransformer : QgsPropertyTransformer
7778
virtual bool writeXml( QDomElement& transformerElem, QDomDocument& doc ) const;
7879
virtual bool readXml( const QDomElement& transformerElem, const QDomDocument& doc );
7980
virtual QVariant transform( const QgsExpressionContext& context, const QVariant& value ) const;
81+
virtual QString toExpression( const QString& baseExpression ) const;
8082

8183
double size( double value ) const;
8284

@@ -125,6 +127,7 @@ class QgsColorRampTransformer : QgsPropertyTransformer
125127
virtual bool writeXml( QDomElement& transformerElem, QDomDocument& doc ) const;
126128
virtual bool readXml( const QDomElement& transformerElem, const QDomDocument& doc );
127129
virtual QVariant transform( const QgsExpressionContext& context, const QVariant& value ) const;
130+
virtual QString toExpression( const QString& baseExpression ) const;
128131

129132
QColor color( double value ) const;
130133

@@ -136,5 +139,9 @@ class QgsColorRampTransformer : QgsPropertyTransformer
136139

137140
void setNullColor( const QColor& color );
138141

142+
QString rampName() const;
143+
144+
void setRampName( const QString& name );
145+
139146
};
140147

src/core/qgsproperty.cpp

+10-5
Original file line numberDiff line numberDiff line change
@@ -293,21 +293,26 @@ QString QgsProperty::expressionString() const
293293

294294
QString QgsProperty::asExpression() const
295295
{
296+
QString exp;
296297
switch ( d->type )
297298
{
298299
case StaticProperty:
299-
return QgsExpression::quotedValue( d->staticValue );
300+
exp = QgsExpression::quotedValue( d->staticValue );
301+
break;
300302

301303
case FieldBasedProperty:
302-
return QgsExpression::quotedColumnRef( d->fieldName );
304+
exp = QgsExpression::quotedColumnRef( d->fieldName );
305+
break;
303306

304307
case ExpressionBasedProperty:
305-
return d->expressionString;
308+
exp = d->expressionString;
309+
break;
306310

307311
case InvalidProperty:
308-
return QString();
312+
exp = QString();
313+
break;
309314
}
310-
return QString();
315+
return d->transformer ? d->transformer->toExpression( exp ) : exp;
311316
}
312317

313318
bool QgsProperty::prepare( const QgsExpressionContext& context ) const

src/core/qgspropertytransformer.cpp

+45-3
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,29 @@ QVariant QgsSizeScaleTransformer::transform( const QgsExpressionContext& context
172172
}
173173
}
174174

175+
QString QgsSizeScaleTransformer::toExpression( const QString& baseExpression ) const
176+
{
177+
QString minValueString = QString::number( mMinValue );
178+
QString maxValueString = QString::number( mMaxValue );
179+
QString minSizeString = QString::number( mMinSize );
180+
QString maxSizeString = QString::number( mMaxSize );
181+
QString nullSizeString = QString::number( mNullSize );
182+
QString exponentString = QString::number( mExponent );
183+
184+
switch ( mType )
185+
{
186+
case Linear:
187+
return QStringLiteral( "coalesce(scale_linear(%1, %2, %3, %4, %5), %6)" ).arg( baseExpression, minValueString, maxValueString, minSizeString, maxSizeString, nullSizeString );
188+
189+
case Area:
190+
case Flannery:
191+
case Exponential:
192+
return QStringLiteral( "coalesce(scale_exp(%1, %2, %3, %4, %5, %6), %7)" ).arg( baseExpression, minValueString, maxValueString, minSizeString, maxSizeString, exponentString, nullSizeString );
193+
194+
}
195+
return QString();
196+
}
197+
175198

176199
//
177200
// QgsColorRampTransformer
@@ -191,6 +214,7 @@ QgsColorRampTransformer::QgsColorRampTransformer( const QgsColorRampTransformer
191214
: QgsPropertyTransformer( other )
192215
, mGradientRamp( other.mGradientRamp ? other.mGradientRamp->clone() : nullptr )
193216
, mNullColor( other.mNullColor )
217+
, mRampName( other.mRampName )
194218
{
195219

196220
}
@@ -201,14 +225,17 @@ QgsColorRampTransformer &QgsColorRampTransformer::operator=( const QgsColorRampT
201225
mMaxValue = other.mMaxValue;
202226
mGradientRamp.reset( other.mGradientRamp ? other.mGradientRamp->clone() : nullptr );
203227
mNullColor = other.mNullColor;
228+
mRampName = other.mRampName;
204229
return *this;
205230
}
206231

207232
QgsColorRampTransformer* QgsColorRampTransformer::clone()
208233
{
209-
return new QgsColorRampTransformer( mMinValue, mMaxValue,
210-
mGradientRamp ? mGradientRamp->clone() : nullptr,
211-
mNullColor );
234+
QgsColorRampTransformer* c = new QgsColorRampTransformer( mMinValue, mMaxValue,
235+
mGradientRamp ? mGradientRamp->clone() : nullptr,
236+
mNullColor );
237+
c->setRampName( mRampName );
238+
return c;
212239
}
213240

214241
bool QgsColorRampTransformer::writeXml( QDomElement &transformerElem, QDomDocument &doc ) const
@@ -222,6 +249,7 @@ bool QgsColorRampTransformer::writeXml( QDomElement &transformerElem, QDomDocume
222249
transformerElem.appendChild( colorRampElem );
223250
}
224251
transformerElem.setAttribute( "nullColor", QgsSymbolLayerUtils::encodeColor( mNullColor ) );
252+
transformerElem.setAttribute( "rampName", mRampName );
225253

226254
return true;
227255
}
@@ -239,6 +267,7 @@ bool QgsColorRampTransformer::readXml( const QDomElement &transformerElem, const
239267
}
240268

241269
mNullColor = QgsSymbolLayerUtils::decodeColor( transformerElem.attribute( "nullColor", "0,0,0,0" ) );
270+
mRampName = transformerElem.attribute( "rampName", QString() );
242271
return true;
243272
}
244273

@@ -263,6 +292,19 @@ QVariant QgsColorRampTransformer::transform( const QgsExpressionContext &context
263292
}
264293
}
265294

295+
QString QgsColorRampTransformer::toExpression( const QString& baseExpression ) const
296+
{
297+
if ( !mGradientRamp )
298+
return QgsExpression::quotedValue( mNullColor.name() );
299+
300+
QString minValueString = QString::number( mMinValue );
301+
QString maxValueString = QString::number( mMaxValue );
302+
QString nullColorString = mNullColor.name();
303+
304+
return QStringLiteral( "coalesce(ramp_color('%1',scale_linear(%2, %3, %4, 0, 1), '%5')" ).arg( !mRampName.isEmpty() ? mRampName : QStringLiteral( "custom ramp" ),
305+
baseExpression, minValueString, maxValueString, nullColorString );
306+
}
307+
266308
QColor QgsColorRampTransformer::color( double value ) const
267309
{
268310
double scaledVal = qBound( 0.0, ( value - mMinValue ) / ( mMaxValue - mMinValue ), 1.0 );

src/core/qgspropertytransformer.h

+23
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ class CORE_EXPORT QgsPropertyTransformer
126126
*/
127127
virtual QVariant transform( const QgsExpressionContext& context, const QVariant& value ) const = 0;
128128

129+
/**
130+
* Converts the transformer to a QGIS expression string. The \a baseExpression string consists
131+
* of a sub-expression reflecting the parent property's state.
132+
*/
133+
virtual QString toExpression( const QString& baseExpression ) const = 0;
134+
129135
protected:
130136

131137
//! Minimum value expected by the transformer
@@ -181,6 +187,7 @@ class CORE_EXPORT QgsSizeScaleTransformer : public QgsPropertyTransformer
181187
virtual bool writeXml( QDomElement& transformerElem, QDomDocument& doc ) const override;
182188
virtual bool readXml( const QDomElement& transformerElem, const QDomDocument& doc ) override;
183189
virtual QVariant transform( const QgsExpressionContext& context, const QVariant& value ) const override;
190+
virtual QString toExpression( const QString& baseExpression ) const override;
184191

185192
/**
186193
* Calculates the size corresponding to a specific value.
@@ -303,6 +310,7 @@ class CORE_EXPORT QgsColorRampTransformer : public QgsPropertyTransformer
303310
virtual bool writeXml( QDomElement& transformerElem, QDomDocument& doc ) const override;
304311
virtual bool readXml( const QDomElement& transformerElem, const QDomDocument& doc ) override;
305312
virtual QVariant transform( const QgsExpressionContext& context, const QVariant& value ) const override;
313+
virtual QString toExpression( const QString& baseExpression ) const override;
306314

307315
/**
308316
* Calculates the color corresponding to a specific value.
@@ -338,10 +346,25 @@ class CORE_EXPORT QgsColorRampTransformer : public QgsPropertyTransformer
338346
*/
339347
void setNullColor( const QColor& color ) { mNullColor = color; }
340348

349+
/**
350+
* Returns the color ramp's name.
351+
* @see setRampName()
352+
*/
353+
QString rampName() const { return mRampName; }
354+
355+
/**
356+
* Sets the color ramp's \a name. The ramp name must be set to match
357+
* a color ramp available in the style database for conversion to expression
358+
* to work correctly.
359+
* @see rampName()
360+
*/
361+
void setRampName( const QString& name ) { mRampName = name; }
362+
341363
private:
342364

343365
QScopedPointer< QgsColorRamp > mGradientRamp;
344366
QColor mNullColor;
367+
QString mRampName;
345368

346369
};
347370

tests/src/core/testqgsproperty.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class TestTransformer : public QgsPropertyTransformer
4747
{
4848
return new TestTransformer( mMinValue, mMaxValue );
4949
}
50+
virtual QString toExpression( const QString& ) const override { return QString(); }
5051

5152
private:
5253

@@ -80,6 +81,7 @@ class TestQgsProperty : public QObject
8081
void propertyTransformer(); //test for QgsPropertyTransformer
8182
void sizeScaleTransformer(); //test for QgsSizeScaleTransformer
8283
void colorRampTransformer(); //test for QgsColorRampTransformer
84+
void asExpression(); //test converting property to expression
8385
void propertyCollection(); //test for QgsPropertyCollection
8486
void collectionStack(); //test for QgsPropertyCollectionStack
8587

@@ -729,6 +731,19 @@ void TestQgsProperty::sizeScaleTransformer()
729731
QCOMPARE( t.size( 100 ), 10.0 );
730732
QVERIFY( qgsDoubleNear( t.size( 150 ), 13.5355, 0.001 ) );
731733
QCOMPARE( t.size( 200 ), 20.0 );
734+
735+
//as expression
736+
QgsSizeScaleTransformer t2( QgsSizeScaleTransformer::Linear,
737+
15,
738+
25,
739+
150,
740+
250,
741+
-10,
742+
1.6 );
743+
QCOMPARE( t2.toExpression( "5+6" ), QStringLiteral( "coalesce(scale_linear(5+6, 15, 25, 150, 250), -10)" ) );
744+
t2.setType( QgsSizeScaleTransformer::Exponential );
745+
t2.setExponent( 1.6 );
746+
QCOMPARE( t2.toExpression( "5+6" ), QStringLiteral( "coalesce(scale_exp(5+6, 15, 25, 150, 250, 1.6), -10)" ) );
732747
}
733748

734749
void TestQgsProperty::colorRampTransformer()
@@ -765,6 +780,7 @@ void TestQgsProperty::colorRampTransformer()
765780
25,
766781
new QgsGradientColorRamp( QColor( 10, 20, 30 ), QColor( 200, 190, 180 ) ),
767782
QColor( 100, 150, 200 ) );
783+
t1.setRampName( "rampname " );
768784

769785
QDomElement element = doc.createElement( "xform" );
770786
QVERIFY( t1.writeXml( element, doc ) );
@@ -773,6 +789,7 @@ void TestQgsProperty::colorRampTransformer()
773789
QCOMPARE( r1.minValue(), 15.0 );
774790
QCOMPARE( r1.maxValue(), 25.0 );
775791
QCOMPARE( r1.nullColor(), QColor( 100, 150, 200 ) );
792+
QCOMPARE( r1.rampName(), QString( "rampname " ) );
776793
QVERIFY( dynamic_cast< QgsGradientColorRamp* >( r1.colorRamp() ) );
777794
QCOMPARE( static_cast< QgsGradientColorRamp* >( r1.colorRamp() )->color1(), QColor( 10, 20, 30 ) );
778795
QCOMPARE( static_cast< QgsGradientColorRamp* >( r1.colorRamp() )->color2(), QColor( 200, 190, 180 ) );
@@ -782,6 +799,7 @@ void TestQgsProperty::colorRampTransformer()
782799
QCOMPARE( r2->minValue(), 15.0 );
783800
QCOMPARE( r2->maxValue(), 25.0 );
784801
QCOMPARE( r2->nullColor(), QColor( 100, 150, 200 ) );
802+
QCOMPARE( r2->rampName(), QString( "rampname " ) );
785803
QCOMPARE( static_cast< QgsGradientColorRamp* >( r2->colorRamp() )->color1(), QColor( 10, 20, 30 ) );
786804
QCOMPARE( static_cast< QgsGradientColorRamp* >( r2->colorRamp() )->color2(), QColor( 200, 190, 180 ) );
787805

@@ -790,6 +808,7 @@ void TestQgsProperty::colorRampTransformer()
790808
QCOMPARE( r3.minValue(), 15.0 );
791809
QCOMPARE( r3.maxValue(), 25.0 );
792810
QCOMPARE( r3.nullColor(), QColor( 100, 150, 200 ) );
811+
QCOMPARE( r3.rampName(), QString( "rampname " ) );
793812
QCOMPARE( static_cast< QgsGradientColorRamp* >( r3.colorRamp() )->color1(), QColor( 10, 20, 30 ) );
794813
QCOMPARE( static_cast< QgsGradientColorRamp* >( r3.colorRamp() )->color2(), QColor( 200, 190, 180 ) );
795814

@@ -799,6 +818,7 @@ void TestQgsProperty::colorRampTransformer()
799818
QCOMPARE( r4.minValue(), 15.0 );
800819
QCOMPARE( r4.maxValue(), 25.0 );
801820
QCOMPARE( r4.nullColor(), QColor( 100, 150, 200 ) );
821+
QCOMPARE( r4.rampName(), QString( "rampname " ) );
802822
QCOMPARE( static_cast< QgsGradientColorRamp* >( r4.colorRamp() )->color1(), QColor( 10, 20, 30 ) );
803823
QCOMPARE( static_cast< QgsGradientColorRamp* >( r4.colorRamp() )->color2(), QColor( 200, 190, 180 ) );
804824

@@ -814,13 +834,51 @@ void TestQgsProperty::colorRampTransformer()
814834
QCOMPARE( t.nullColor(), QColor( 1, 10, 11, 21 ) );
815835
t.setColorRamp( new QgsGradientColorRamp( QColor( 10, 20, 100 ), QColor( 100, 200, 200 ) ) );
816836
QCOMPARE( static_cast< QgsGradientColorRamp* >( t.colorRamp() )->color1(), QColor( 10, 20, 100 ) );
837+
t.setRampName( "colorramp" );
838+
QCOMPARE( t.rampName(), QString( "colorramp" ) );
817839

818840
//test colors
819841
QCOMPARE( t.color( 50 ), QColor( 10, 20, 100 ) ); //out of range
820842
QCOMPARE( t.color( 100 ), QColor( 10, 20, 100 ) );
821843
QCOMPARE( t.color( 150 ), QColor( 55, 110, 150 ) );
822844
QCOMPARE( t.color( 200 ), QColor( 100, 200, 200 ) );
823845
QCOMPARE( t.color( 250 ), QColor( 100, 200, 200 ) ); //out of range
846+
847+
//toExpression
848+
QgsColorRampTransformer t5( 15,
849+
25,
850+
new QgsGradientColorRamp( QColor( 10, 20, 30 ), QColor( 200, 190, 180 ) ),
851+
QColor( 100, 150, 200 ) );
852+
QCOMPARE( t5.toExpression( "5+6" ), QStringLiteral( "coalesce(ramp_color('custom ramp',scale_linear(5+6, 15, 25, 0, 1), '#6496c8')" ) );
853+
t5.setRampName( "my ramp" );
854+
QCOMPARE( t5.toExpression( "5+6" ), QStringLiteral( "coalesce(ramp_color('my ramp',scale_linear(5+6, 15, 25, 0, 1), '#6496c8')" ) );
855+
}
856+
857+
void TestQgsProperty::asExpression()
858+
{
859+
// static property
860+
QgsProperty p = QgsProperty::fromValue( 5 );
861+
QCOMPARE( p.asExpression(), QStringLiteral( "5" ) );
862+
p = QgsProperty::fromValue( "value" );
863+
QCOMPARE( p.asExpression(), QStringLiteral( "'value'" ) );
864+
865+
// field based property
866+
p = QgsProperty::fromField( "a field" );
867+
QCOMPARE( p.asExpression(), QStringLiteral( "\"a field\"" ) );
868+
869+
// expression based property
870+
p = QgsProperty::fromExpression( "5 + 6" );
871+
QCOMPARE( p.asExpression(), QStringLiteral( "5 + 6" ) );
872+
873+
// with transformer
874+
p.setTransformer( new QgsSizeScaleTransformer( QgsSizeScaleTransformer::Linear,
875+
15,
876+
25,
877+
150,
878+
250,
879+
-10,
880+
1 ) );
881+
QCOMPARE( p.asExpression(), QStringLiteral( "coalesce(scale_linear(5 + 6, 15, 25, 150, 250), -10)" ) );
824882
}
825883

826884
void TestQgsProperty::propertyCollection()

0 commit comments

Comments
 (0)