QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
34class QgsMapLayer;
37
38#define ENSURE_NO_EVAL_ERROR { if ( parent->hasEvalError() ) return QVariant(); }
39#define SET_EVAL_ERROR(x) { parent->setEvalErrorString( x ); return QVariant(); }
40
41#define FEAT_FROM_CONTEXT(c, f) if ( !(c) || !( c )->hasFeature() ) return QVariant(); \
42 QgsFeature f = ( c )->feature();
43
51class CORE_EXPORT QgsExpressionUtils
52{
53 public:
56// three-value logic
57 enum TVL
58 {
59 False,
60 True,
61 Unknown
62 };
63
64
65 static TVL AND[3][3];
66
67 static TVL OR[3][3];
68
69 static TVL NOT[3];
70
71#define TVL_True QVariant( 1 )
72#define TVL_False QVariant( 0 )
73#define TVL_Unknown QVariant()
74
75 static QVariant tvl2variant( TVL v )
76 {
77 switch ( v )
78 {
79 case False:
80 return TVL_False;
81 case True:
82 return TVL_True;
83 case Unknown:
84 default:
85 return TVL_Unknown;
86 }
87 }
88
89// this handles also NULL values
90 static TVL getTVLValue( const QVariant &value, QgsExpression *parent )
91 {
92 // we need to convert to TVL
93 if ( QgsVariantUtils::isNull( value ) )
94 return Unknown;
95
96 //handle some special cases
97 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
98 {
99 //geom is false if empty
100 const QgsGeometry geom = value.value<QgsGeometry>();
101 return geom.isNull() ? False : True;
102 }
103 else if ( value.userType() == QMetaType::type( "QgsFeature" ) )
104 {
105 //feat is false if non-valid
106 const QgsFeature feat = value.value<QgsFeature>();
107 return feat.isValid() ? True : False;
108 }
109
110 if ( value.type() == QVariant::Int )
111 return value.toInt() != 0 ? True : False;
112
113 bool ok;
114 const double x = value.toDouble( &ok );
115 if ( !ok )
116 {
117 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
118 return Unknown;
119 }
120 return !qgsDoubleNear( x, 0.0 ) ? True : False;
121 }
122
123
124 static inline bool isIntSafe( const QVariant &v )
125 {
126 if ( v.type() == QVariant::Int )
127 return true;
128 if ( v.type() == QVariant::UInt )
129 return true;
130 if ( v.type() == QVariant::LongLong )
131 return true;
132 if ( v.type() == QVariant::ULongLong )
133 return true;
134 if ( v.type() == QVariant::Double )
135 return false;
136 if ( v.type() == QVariant::String )
137 {
138 bool ok;
139 v.toString().toInt( &ok );
140 return ok;
141 }
142 return false;
143 }
144
145 static inline bool isDoubleSafe( const QVariant &v )
146 {
147 if ( v.type() == QVariant::Double )
148 return true;
149 if ( v.type() == QVariant::Int )
150 return true;
151 if ( v.type() == QVariant::UInt )
152 return true;
153 if ( v.type() == QVariant::LongLong )
154 return true;
155 if ( v.type() == QVariant::ULongLong )
156 return true;
157 if ( v.type() == QVariant::String )
158 {
159 bool ok;
160 const double val = v.toString().toDouble( &ok );
161 ok = ok && std::isfinite( val ) && !std::isnan( val );
162 return ok;
163 }
164 return false;
165 }
166
167 static inline bool isDateTimeSafe( const QVariant &v )
168 {
169 return v.type() == QVariant::DateTime
170 || v.type() == QVariant::Date
171 || v.type() == QVariant::Time;
172 }
173
174 static inline bool isIntervalSafe( const QVariant &v )
175 {
176 if ( v.userType() == QMetaType::type( "QgsInterval" ) )
177 {
178 return true;
179 }
180
181 if ( v.type() == QVariant::String )
182 {
183 return QgsInterval::fromString( v.toString() ).isValid();
184 }
185 return false;
186 }
187
188 static inline bool isNull( const QVariant &v )
189 {
190 return QgsVariantUtils::isNull( v );
191 }
192
193 static inline bool isList( const QVariant &v )
194 {
195 return v.type() == QVariant::List || v.type() == QVariant::StringList;
196 }
197
198// implicit conversion to string
199 static QString getStringValue( const QVariant &value, QgsExpression * )
200 {
201 return value.toString();
202 }
203
211 static QByteArray getBinaryValue( const QVariant &value, QgsExpression *parent )
212 {
213 if ( value.type() != QVariant::ByteArray )
214 {
215 parent->setEvalErrorString( QObject::tr( "Value is not a binary value" ) );
216 return QByteArray();
217 }
218 return value.toByteArray();
219 }
220
221 static double getDoubleValue( const QVariant &value, QgsExpression *parent )
222 {
223 bool ok;
224 const double x = value.toDouble( &ok );
225 if ( !ok || std::isnan( x ) || !std::isfinite( x ) )
226 {
227 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
228 return 0;
229 }
230 return x;
231 }
232
233 static qlonglong getIntValue( const QVariant &value, QgsExpression *parent )
234 {
235 bool ok;
236 const qlonglong x = value.toLongLong( &ok );
237 if ( ok )
238 {
239 return x;
240 }
241 else
242 {
243 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
244 return 0;
245 }
246 }
247
248 static int getNativeIntValue( const QVariant &value, QgsExpression *parent )
249 {
250 bool ok;
251 const qlonglong x = value.toLongLong( &ok );
252 if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
253 {
254 return static_cast<int>( x );
255 }
256 else
257 {
258 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to native int" ).arg( value.toString() ) );
259 return 0;
260 }
261 }
262
263 static QDateTime getDateTimeValue( const QVariant &value, QgsExpression *parent )
264 {
265 QDateTime d = value.toDateTime();
266 if ( d.isValid() )
267 {
268 return d;
269 }
270 else
271 {
272 const QTime t = value.toTime();
273 if ( t.isValid() )
274 {
275 return QDateTime( QDate( 1, 1, 1 ), t );
276 }
277
278 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
279 return QDateTime();
280 }
281 }
282
283 static QDate getDateValue( const QVariant &value, QgsExpression *parent )
284 {
285 QDate d = value.toDate();
286 if ( d.isValid() )
287 {
288 return d;
289 }
290 else
291 {
292 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
293 return QDate();
294 }
295 }
296
297 static QTime getTimeValue( const QVariant &value, QgsExpression *parent )
298 {
299 QTime t = value.toTime();
300 if ( t.isValid() )
301 {
302 return t;
303 }
304 else
305 {
306 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
307 return QTime();
308 }
309 }
310
311 static QgsInterval getInterval( const QVariant &value, QgsExpression *parent, bool report_error = false )
312 {
313 if ( value.userType() == QMetaType::type( "QgsInterval" ) )
314 return value.value<QgsInterval>();
315
316 QgsInterval inter = QgsInterval::fromString( value.toString() );
317 if ( inter.isValid() )
318 {
319 return inter;
320 }
321 // If we get here then we can't convert so we just error and return invalid.
322 if ( report_error )
323 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to interval" ).arg( value.toString() ) );
324
325 return QgsInterval();
326 }
327
328 static QgsGradientColorRamp getRamp( const QVariant &value, QgsExpression *parent, bool report_error = false );
329
330 static QgsGeometry getGeometry( const QVariant &value, QgsExpression *parent )
331 {
332 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
333 return value.value<QgsGeometry>();
334
335 parent->setEvalErrorString( QStringLiteral( "Cannot convert to geometry" ) );
336 return QgsGeometry();
337 }
338
339 static QgsFeature getFeature( const QVariant &value, QgsExpression *parent )
340 {
341 if ( value.userType() == QMetaType::type( "QgsFeature" ) )
342 return value.value<QgsFeature>();
343
344 parent->setEvalErrorString( QStringLiteral( "Cannot convert to feature" ) );
345 return 0;
346 }
347
348 static QgsExpressionNode *getNode( const QVariant &value, QgsExpression *parent )
349 {
350 if ( value.canConvert<QgsExpressionNode *>() )
351 return value.value<QgsExpressionNode *>();
352
353 parent->setEvalErrorString( QStringLiteral( "Cannot convert to node" ) );
354 return nullptr;
355 }
356
360 Q_DECL_DEPRECATED static QgsMapLayer *getMapLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression * );
361
367 static void executeLambdaForMapLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression *expression, const std::function< void( QgsMapLayer * )> &function, bool &foundLayer );
368
374 static QVariant runMapLayerFunctionThreadSafe( const QVariant &value, const QgsExpressionContext *context, QgsExpression *expression, const std::function<QVariant( QgsMapLayer * ) > &function, bool &foundLayer );
375
379 static std::unique_ptr<QgsVectorLayerFeatureSource> getFeatureSource( const QVariant &value, const QgsExpressionContext *context, QgsExpression *e, bool &foundLayer );
380
384 Q_DECL_DEPRECATED static QgsVectorLayer *getVectorLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression *e );
385
391 static QString getFilePathValue( const QVariant &value, const QgsExpressionContext *context, QgsExpression *parent );
392
393 static QVariantList getListValue( const QVariant &value, QgsExpression *parent )
394 {
395 if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
396 {
397 return value.toList();
398 }
399 else
400 {
401 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to array" ).arg( value.toString() ) );
402 return QVariantList();
403 }
404 }
405
406 static QVariantMap getMapValue( const QVariant &value, QgsExpression *parent )
407 {
408 if ( value.type() == QVariant::Map )
409 {
410 return value.toMap();
411 }
412 else
413 {
414 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to map" ).arg( value.toString() ) );
415 return QVariantMap();
416 }
417 }
418
425 static QString toLocalizedString( const QVariant &value )
426 {
427 if ( value.type() == QVariant::Int || value.type() == QVariant::UInt || value.type() == QVariant::LongLong || value.type() == QVariant::ULongLong )
428 {
429 bool ok;
430 QString res;
431
432 if ( value.type() == QVariant::ULongLong )
433 {
434 res = QLocale().toString( value.toULongLong( &ok ) );
435 }
436 else
437 {
438 res = QLocale().toString( value.toLongLong( &ok ) );
439 }
440
441 if ( ok )
442 {
443 return res;
444 }
445 else
446 {
447 return value.toString();
448 }
449 }
450 // Qt madness with QMetaType::Float :/
451 else if ( value.type() == QVariant::Double || value.type() == static_cast<QVariant::Type>( QMetaType::Float ) )
452 {
453 bool ok;
454 const QString strVal = value.toString();
455 const int dotPosition = strVal.indexOf( '.' );
456 const int precision = dotPosition > 0 ? strVal.length() - dotPosition - 1 : 0;
457 const QString res = QLocale().toString( value.toDouble( &ok ), 'f', precision );
458
459 if ( ok )
460 {
461 return res;
462 }
463 else
464 {
465 return value.toString();
466 }
467 }
468 else
469 {
470 return value.toString();
471 }
472 }
474
484 static std::tuple<QVariant::Type, int> determineResultType( const QString &expression, const QgsVectorLayer *layer, QgsFeatureRequest request = QgsFeatureRequest(), QgsExpressionContext context = QgsExpressionContext(), bool *foundFeatures = nullptr );
485
486 private:
487
491 static QgsMapLayer *getMapLayerPrivate( const QVariant &value, const QgsExpressionContext *context, QgsExpression * );
492
493};
494
495
496#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:216
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
Q_GADGET bool isNull
Definition: qgsgeometry.h:164
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:46
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:279
static QgsInterval fromString(const QString &string)
Converts a string to an interval.
Base class for all map layer types.
Definition: qgsmaplayer.h:75
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
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:5207
int precision