QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgsexpressionutils.h
Go to the documentation of this file.
1/***************************************************************************
2 qgsexpressionutils.h
3 -------------------
4 begin : May 2017
5 copyright : (C) 2017 Matthias Kuhn
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16
17#ifndef QGSEXPRESSIONUTILS_H
18#define QGSEXPRESSIONUTILS_H
19
20#define SIP_NO_FILE
21
22#include "qgsfeature.h"
23#include "qgsexpression.h"
24#include "qgsvariantutils.h"
25#include "qgsfeaturerequest.h"
26
27#include <QDate>
28#include <QDateTime>
29#include <QTime>
30#include <QThread>
31#include <QLocale>
32#include <functional>
33
36
37#define ENSURE_NO_EVAL_ERROR { if ( parent->hasEvalError() ) return QVariant(); }
38#define SET_EVAL_ERROR(x) { parent->setEvalErrorString( x ); return QVariant(); }
39
40#define FEAT_FROM_CONTEXT(c, f) if ( !(c) || !( c )->hasFeature() ) return QVariant(); \
41 QgsFeature f = ( c )->feature();
42
50class CORE_EXPORT QgsExpressionUtils
51{
52 public:
55// three-value logic
56 enum TVL
57 {
58 False,
59 True,
60 Unknown
61 };
62
63
64 static TVL AND[3][3];
65
66 static TVL OR[3][3];
67
68 static TVL NOT[3];
69
70#define TVL_True QVariant( 1 )
71#define TVL_False QVariant( 0 )
72#define TVL_Unknown QVariant()
73
74 static QVariant tvl2variant( TVL v )
75 {
76 switch ( v )
77 {
78 case False:
79 return TVL_False;
80 case True:
81 return TVL_True;
82 case Unknown:
83 default:
84 return TVL_Unknown;
85 }
86 }
87
88// this handles also NULL values
89 static TVL getTVLValue( const QVariant &value, QgsExpression *parent )
90 {
91 // we need to convert to TVL
92 if ( QgsVariantUtils::isNull( value ) )
93 return Unknown;
94
95 //handle some special cases
96 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
97 {
98 //geom is false if empty
99 const QgsGeometry geom = value.value<QgsGeometry>();
100 return geom.isNull() ? False : True;
101 }
102 else if ( value.userType() == QMetaType::type( "QgsFeature" ) )
103 {
104 //feat is false if non-valid
105 const QgsFeature feat = value.value<QgsFeature>();
106 return feat.isValid() ? True : False;
107 }
108
109 if ( value.type() == QVariant::Int )
110 return value.toInt() != 0 ? True : False;
111
112 bool ok;
113 const double x = value.toDouble( &ok );
114 if ( !ok )
115 {
116 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
117 return Unknown;
118 }
119 return !qgsDoubleNear( x, 0.0 ) ? True : False;
120 }
121
122
123 static inline bool isIntSafe( const QVariant &v )
124 {
125 if ( v.type() == QVariant::Int )
126 return true;
127 if ( v.type() == QVariant::UInt )
128 return true;
129 if ( v.type() == QVariant::LongLong )
130 return true;
131 if ( v.type() == QVariant::ULongLong )
132 return true;
133 if ( v.type() == QVariant::Double )
134 return false;
135 if ( v.type() == QVariant::String )
136 {
137 bool ok;
138 v.toString().toInt( &ok );
139 return ok;
140 }
141 return false;
142 }
143
144 static inline bool isDoubleSafe( const QVariant &v )
145 {
146 if ( v.type() == QVariant::Double )
147 return true;
148 if ( v.type() == QVariant::Int )
149 return true;
150 if ( v.type() == QVariant::UInt )
151 return true;
152 if ( v.type() == QVariant::LongLong )
153 return true;
154 if ( v.type() == QVariant::ULongLong )
155 return true;
156 if ( v.type() == QVariant::String )
157 {
158 bool ok;
159 const double val = v.toString().toDouble( &ok );
160 ok = ok && std::isfinite( val ) && !std::isnan( val );
161 return ok;
162 }
163 return false;
164 }
165
166 static inline bool isDateTimeSafe( const QVariant &v )
167 {
168 return v.type() == QVariant::DateTime
169 || v.type() == QVariant::Date
170 || v.type() == QVariant::Time;
171 }
172
173 static inline bool isIntervalSafe( const QVariant &v )
174 {
175 if ( v.userType() == QMetaType::type( "QgsInterval" ) )
176 {
177 return true;
178 }
179
180 if ( v.type() == QVariant::String )
181 {
182 return QgsInterval::fromString( v.toString() ).isValid();
183 }
184 return false;
185 }
186
187 static inline bool isNull( const QVariant &v )
188 {
189 return QgsVariantUtils::isNull( v );
190 }
191
192 static inline bool isList( const QVariant &v )
193 {
194 return v.type() == QVariant::List || v.type() == QVariant::StringList;
195 }
196
197// implicit conversion to string
198 static QString getStringValue( const QVariant &value, QgsExpression * )
199 {
200 return value.toString();
201 }
202
210 static QByteArray getBinaryValue( const QVariant &value, QgsExpression *parent )
211 {
212 if ( value.type() != QVariant::ByteArray )
213 {
214 parent->setEvalErrorString( QObject::tr( "Value is not a binary value" ) );
215 return QByteArray();
216 }
217 return value.toByteArray();
218 }
219
220 static double getDoubleValue( const QVariant &value, QgsExpression *parent )
221 {
222 bool ok;
223 const double x = value.toDouble( &ok );
224 if ( !ok || std::isnan( x ) || !std::isfinite( x ) )
225 {
226 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
227 return 0;
228 }
229 return x;
230 }
231
232 static qlonglong getIntValue( const QVariant &value, QgsExpression *parent )
233 {
234 bool ok;
235 const qlonglong x = value.toLongLong( &ok );
236 if ( ok )
237 {
238 return x;
239 }
240 else
241 {
242 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
243 return 0;
244 }
245 }
246
247 static int getNativeIntValue( const QVariant &value, QgsExpression *parent )
248 {
249 bool ok;
250 const qlonglong x = value.toLongLong( &ok );
251 if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
252 {
253 return static_cast<int>( x );
254 }
255 else
256 {
257 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to native int" ).arg( value.toString() ) );
258 return 0;
259 }
260 }
261
262 static QDateTime getDateTimeValue( const QVariant &value, QgsExpression *parent )
263 {
264 QDateTime d = value.toDateTime();
265 if ( d.isValid() )
266 {
267 return d;
268 }
269 else
270 {
271 const QTime t = value.toTime();
272 if ( t.isValid() )
273 {
274 return QDateTime( QDate( 1, 1, 1 ), t );
275 }
276
277 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
278 return QDateTime();
279 }
280 }
281
282 static QDate getDateValue( const QVariant &value, QgsExpression *parent )
283 {
284 QDate d = value.toDate();
285 if ( d.isValid() )
286 {
287 return d;
288 }
289 else
290 {
291 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
292 return QDate();
293 }
294 }
295
296 static QTime getTimeValue( const QVariant &value, QgsExpression *parent )
297 {
298 QTime t = value.toTime();
299 if ( t.isValid() )
300 {
301 return t;
302 }
303 else
304 {
305 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
306 return QTime();
307 }
308 }
309
310 static QgsInterval getInterval( const QVariant &value, QgsExpression *parent, bool report_error = false )
311 {
312 if ( value.userType() == QMetaType::type( "QgsInterval" ) )
313 return value.value<QgsInterval>();
314
315 QgsInterval inter = QgsInterval::fromString( value.toString() );
316 if ( inter.isValid() )
317 {
318 return inter;
319 }
320 // If we get here then we can't convert so we just error and return invalid.
321 if ( report_error )
322 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to interval" ).arg( value.toString() ) );
323
324 return QgsInterval();
325 }
326
327 static QgsGradientColorRamp getRamp( const QVariant &value, QgsExpression *parent, bool report_error = false );
328
329 static QgsGeometry getGeometry( const QVariant &value, QgsExpression *parent )
330 {
331 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
332 return value.value<QgsGeometry>();
333
334 parent->setEvalErrorString( QStringLiteral( "Cannot convert to geometry" ) );
335 return QgsGeometry();
336 }
337
338 static QgsFeature getFeature( const QVariant &value, QgsExpression *parent )
339 {
340 if ( value.userType() == QMetaType::type( "QgsFeature" ) )
341 return value.value<QgsFeature>();
342
343 parent->setEvalErrorString( QStringLiteral( "Cannot convert to feature" ) );
344 return 0;
345 }
346
347 static QgsExpressionNode *getNode( const QVariant &value, QgsExpression *parent )
348 {
349 if ( value.canConvert<QgsExpressionNode *>() )
350 return value.value<QgsExpressionNode *>();
351
352 parent->setEvalErrorString( QStringLiteral( "Cannot convert to node" ) );
353 return nullptr;
354 }
355
359 Q_DECL_DEPRECATED static QgsMapLayer *getMapLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression * );
360
366 static void executeLambdaForMapLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression *expression, const std::function< void( QgsMapLayer * )> &function, bool &foundLayer );
367
373 static QVariant runMapLayerFunctionThreadSafe( const QVariant &value, const QgsExpressionContext *context, QgsExpression *expression, const std::function<QVariant( QgsMapLayer * ) > &function, bool &foundLayer );
374
378 static std::unique_ptr<QgsVectorLayerFeatureSource> getFeatureSource( const QVariant &value, const QgsExpressionContext *context, QgsExpression *e, bool &foundLayer );
379
383 Q_DECL_DEPRECATED static QgsVectorLayer *getVectorLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression *e );
384
390 static QString getFilePathValue( const QVariant &value, const QgsExpressionContext *context, QgsExpression *parent );
391
392 static QVariantList getListValue( const QVariant &value, QgsExpression *parent )
393 {
394 if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
395 {
396 return value.toList();
397 }
398 else
399 {
400 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to array" ).arg( value.toString() ) );
401 return QVariantList();
402 }
403 }
404
405 static QVariantMap getMapValue( const QVariant &value, QgsExpression *parent )
406 {
407 if ( value.type() == QVariant::Map )
408 {
409 return value.toMap();
410 }
411 else
412 {
413 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to map" ).arg( value.toString() ) );
414 return QVariantMap();
415 }
416 }
417
424 static QString toLocalizedString( const QVariant &value )
425 {
426 if ( value.type() == QVariant::Int || value.type() == QVariant::UInt || value.type() == QVariant::LongLong || value.type() == QVariant::ULongLong )
427 {
428 bool ok;
429 QString res;
430
431 if ( value.type() == QVariant::ULongLong )
432 {
433 res = QLocale().toString( value.toULongLong( &ok ) );
434 }
435 else
436 {
437 res = QLocale().toString( value.toLongLong( &ok ) );
438 }
439
440 if ( ok )
441 {
442 return res;
443 }
444 else
445 {
446 return value.toString();
447 }
448 }
449 // Qt madness with QMetaType::Float :/
450 else if ( value.type() == QVariant::Double || value.type() == static_cast<QVariant::Type>( QMetaType::Float ) )
451 {
452 bool ok;
453 const QString strVal = value.toString();
454 const int dotPosition = strVal.indexOf( '.' );
455 const int precision = dotPosition > 0 ? strVal.length() - dotPosition - 1 : 0;
456 const QString res = QLocale().toString( value.toDouble( &ok ), 'f', precision );
457
458 if ( ok )
459 {
460 return res;
461 }
462 else
463 {
464 return value.toString();
465 }
466 }
467 else
468 {
469 return value.toString();
470 }
471 }
473
483 static std::tuple<QVariant::Type, int> determineResultType( const QString &expression, const QgsVectorLayer *layer, QgsFeatureRequest request = QgsFeatureRequest(), QgsExpressionContext context = QgsExpressionContext(), bool *foundFeatures = nullptr );
484
485 private:
486
490 static QgsMapLayer *getMapLayerPrivate( const QVariant &value, const QgsExpressionContext *context, QgsExpression * );
491
492};
493
494
495#endif // QGSEXPRESSIONUTILS_H
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Abstract base class for all nodes that can appear in an expression.
A set of expression-related functions.
Class for parsing and evaluation of expressions (formerly called "search strings").
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions)
This class wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:219
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
A representation of the interval between two datetime values.
Definition: qgsinterval.h:42
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:261
static QgsInterval fromString(const QString &string)
Converts a string to an interval.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
Partial snapshot of vector layer's state (only the members necessary for access to features)
Represents a vector layer which manages a vector based data sets.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:3509
int precision