QGIS API Documentation 3.41.0-Master (88383c3d16f)
Loading...
Searching...
No Matches
qgsexpressionutils.h
Go to the documentation of this file.
1/***************************************************************************
2 qgsexpressionutils.h
3 -------------------
4 begin : May 2017
5 copyright : (C) 2017 Matthias Kuhn
6 email : matthias@opengis.ch
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"
28
29#include <QDate>
30#include <QDateTime>
31#include <QTime>
32#include <QThread>
33#include <QLocale>
34#include <functional>
35
36class QgsMapLayer;
39
40#define ENSURE_NO_EVAL_ERROR { if ( parent->hasEvalError() ) return QVariant(); }
41#define SET_EVAL_ERROR(x) { parent->setEvalErrorString( x ); return QVariant(); }
42
43#define FEAT_FROM_CONTEXT(c, f) if ( !(c) || !( c )->hasFeature() ) return QVariant(); \
44 QgsFeature f = ( c )->feature();
45
53class CORE_EXPORT QgsExpressionUtils
54{
55 public:
58// three-value logic
59 enum TVL
60 {
61 False,
62 True,
63 Unknown
64 };
65
66
67 static TVL AND[3][3];
68
69 static TVL OR[3][3];
70
71 static TVL NOT[3];
72
73#define TVL_True QVariant( 1 )
74#define TVL_False QVariant( 0 )
75#define TVL_Unknown QVariant()
76
77 static QVariant tvl2variant( TVL v )
78 {
79 switch ( v )
80 {
81 case False:
82 return TVL_False;
83 case True:
84 return TVL_True;
85 case Unknown:
86 default:
87 return TVL_Unknown;
88 }
89 }
90
91// this handles also NULL values
92 static TVL getTVLValue( const QVariant &value, QgsExpression *parent )
93 {
94 // we need to convert to TVL
95 if ( QgsVariantUtils::isNull( value ) )
96 return Unknown;
97
98 //handle some special cases
99 int userType = value.userType();
100 if ( value.type() == QVariant::UserType )
101 {
102 if ( userType == qMetaTypeId< QgsGeometry>() || userType == qMetaTypeId<QgsReferencedGeometry>() )
103 {
104 //geom is false if empty
105 const QgsGeometry geom = getGeometry( value, nullptr );
106 return geom.isNull() ? False : True;
107 }
108 else if ( userType == qMetaTypeId<QgsFeature>() )
109 {
110 //feat is false if non-valid
111 const QgsFeature feat = value.value<QgsFeature>();
112 return feat.isValid() ? True : False;
113 }
114 }
115
116 if ( userType == QMetaType::Type::Int )
117 return value.toInt() != 0 ? True : False;
118
119 bool ok;
120 const double x = value.toDouble( &ok );
121 if ( !ok )
122 {
123 if ( parent )
124 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
125 return Unknown;
126 }
127 return !qgsDoubleNear( x, 0.0 ) ? True : False;
128 }
129
130
131 static inline bool isIntSafe( const QVariant &v )
132 {
133 if ( v.userType() == QMetaType::Type::Int )
134 return true;
135 if ( v.userType() == QMetaType::Type::UInt )
136 return true;
137 if ( v.userType() == QMetaType::Type::LongLong )
138 return true;
139 if ( v.userType() == QMetaType::Type::ULongLong )
140 return true;
141 if ( v.userType() == QMetaType::Type::Double )
142 return false;
143 if ( v.userType() == QMetaType::Type::QString )
144 {
145 bool ok;
146 v.toString().toInt( &ok );
147 return ok;
148 }
149 return false;
150 }
151
152 static inline bool isDoubleSafe( const QVariant &v )
153 {
154 if ( v.userType() == QMetaType::Type::Double )
155 return true;
156 if ( v.userType() == QMetaType::Type::Int )
157 return true;
158 if ( v.userType() == QMetaType::Type::UInt )
159 return true;
160 if ( v.userType() == QMetaType::Type::LongLong )
161 return true;
162 if ( v.userType() == QMetaType::Type::ULongLong )
163 return true;
164 if ( v.userType() == QMetaType::Type::QString )
165 {
166 bool ok;
167 const double val = v.toString().toDouble( &ok );
168 ok = ok && std::isfinite( val ) && !std::isnan( val );
169 return ok;
170 }
171 return false;
172 }
173
174 static inline bool isDateTimeSafe( const QVariant &v )
175 {
176 return v.userType() == QMetaType::Type::QDateTime
177 || v.userType() == QMetaType::Type::QDate
178 || v.userType() == QMetaType::Type::QTime;
179 }
180
181 static inline bool isIntervalSafe( const QVariant &v )
182 {
183 if ( v.userType() == qMetaTypeId<QgsInterval>() )
184 {
185 return true;
186 }
187
188 if ( v.userType() == QMetaType::Type::QString )
189 {
190 return QgsInterval::fromString( v.toString() ).isValid();
191 }
192 return false;
193 }
194
195 static inline bool isNull( const QVariant &v )
196 {
197 return QgsVariantUtils::isNull( v );
198 }
199
200 static inline bool isList( const QVariant &v )
201 {
202 return v.userType() == QMetaType::Type::QVariantList || v.userType() == QMetaType::Type::QStringList;
203 }
204
205 // implicit conversion to string
206 static QString getStringValue( const QVariant &value, QgsExpression * )
207 {
208 return value.toString();
209 }
210
218 static QByteArray getBinaryValue( const QVariant &value, QgsExpression *parent )
219 {
220 if ( value.userType() != QMetaType::Type::QByteArray )
221 {
222 if ( parent )
223 parent->setEvalErrorString( QObject::tr( "Value is not a binary value" ) );
224 return QByteArray();
225 }
226 return value.toByteArray();
227 }
228
229 static double getDoubleValue( const QVariant &value, QgsExpression *parent )
230 {
231 bool ok;
232 const double x = value.toDouble( &ok );
233 if ( !ok || std::isnan( x ) || !std::isfinite( x ) )
234 {
235 if ( parent )
236 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
237 return 0;
238 }
239 return x;
240 }
241
242 static qlonglong getIntValue( const QVariant &value, QgsExpression *parent )
243 {
244 bool ok;
245 const qlonglong x = value.toLongLong( &ok );
246 if ( ok )
247 {
248 return x;
249 }
250 else
251 {
252 if ( parent )
253 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
254 return 0;
255 }
256 }
257
258 static int getNativeIntValue( const QVariant &value, QgsExpression *parent )
259 {
260 bool ok;
261 const qlonglong x = value.toLongLong( &ok );
262 if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
263 {
264 return static_cast<int>( x );
265 }
266 else
267 {
268 if ( parent )
269 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to native int" ).arg( value.toString() ) );
270 return 0;
271 }
272 }
273
274 static QDateTime getDateTimeValue( const QVariant &value, QgsExpression *parent )
275 {
276 QDateTime d = value.toDateTime();
277 if ( d.isValid() )
278 {
279 return d;
280 }
281 else
282 {
283 const QTime t = value.toTime();
284 if ( t.isValid() )
285 {
286 return QDateTime( QDate( 1, 1, 1 ), t );
287 }
288
289 if ( parent )
290 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
291 return QDateTime();
292 }
293 }
294
295 static QDate getDateValue( const QVariant &value, QgsExpression *parent )
296 {
297 QDate d = value.toDate();
298 if ( d.isValid() )
299 {
300 return d;
301 }
302 else
303 {
304 if ( parent )
305 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
306 return QDate();
307 }
308 }
309
310 static QTime getTimeValue( const QVariant &value, QgsExpression *parent )
311 {
312 QTime t = value.toTime();
313 if ( t.isValid() )
314 {
315 return t;
316 }
317 else
318 {
319 if ( parent )
320 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
321 return QTime();
322 }
323 }
324
325 static QColor getColorValue( const QVariant &value, QgsExpression *parent, bool &isQColor );
326
327 static QgsInterval getInterval( const QVariant &value, QgsExpression *parent, bool report_error = false )
328 {
329 if ( value.userType() == qMetaTypeId<QgsInterval>() )
330 return value.value<QgsInterval>();
331
332 QgsInterval inter = QgsInterval::fromString( value.toString() );
333 if ( inter.isValid() )
334 {
335 return inter;
336 }
337 // If we get here then we can't convert so we just error and return invalid.
338 if ( report_error && parent )
339 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to interval" ).arg( value.toString() ) );
340
341 return QgsInterval();
342 }
343
344 static QgsGradientColorRamp getRamp( const QVariant &value, QgsExpression *parent, bool report_error = false );
345
346 static QgsGeometry getGeometry( const QVariant &value, QgsExpression *parent, bool tolerant = false )
347 {
348 if ( value.userType() == qMetaTypeId< QgsReferencedGeometry>() )
349 return value.value<QgsReferencedGeometry>();
350
351 if ( value.userType() == qMetaTypeId< QgsGeometry>() )
352 return value.value<QgsGeometry>();
353
354 if ( !tolerant && parent )
355 parent->setEvalErrorString( QStringLiteral( "Cannot convert to geometry" ) );
356 return QgsGeometry();
357 }
358
359 static QgsFeature getFeature( const QVariant &value, QgsExpression *parent )
360 {
361 if ( value.userType() == qMetaTypeId<QgsFeature>() )
362 return value.value<QgsFeature>();
363
364 if ( parent )
365 parent->setEvalErrorString( QStringLiteral( "Cannot convert to feature" ) );
366 return 0;
367 }
368
374 static QgsCoordinateReferenceSystem getCrsValue( const QVariant &value, QgsExpression *parent );
375
376 static QgsExpressionNode *getNode( const QVariant &value, QgsExpression *parent )
377 {
378 if ( value.canConvert<QgsExpressionNode *>() )
379 return value.value<QgsExpressionNode *>();
380
381 if ( parent )
382 parent->setEvalErrorString( QStringLiteral( "Cannot convert to node" ) );
383 return nullptr;
384 }
385
389 Q_DECL_DEPRECATED static QgsMapLayer *getMapLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression * );
390
396 static void executeLambdaForMapLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression *expression, const std::function< void( QgsMapLayer * )> &function, bool &foundLayer );
397
403 static QVariant runMapLayerFunctionThreadSafe( const QVariant &value, const QgsExpressionContext *context, QgsExpression *expression, const std::function<QVariant( QgsMapLayer * ) > &function, bool &foundLayer );
404
408 static std::unique_ptr<QgsVectorLayerFeatureSource> getFeatureSource( const QVariant &value, const QgsExpressionContext *context, QgsExpression *e, bool &foundLayer );
409
413 Q_DECL_DEPRECATED static QgsVectorLayer *getVectorLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression *e );
414
420 static QString getFilePathValue( const QVariant &value, const QgsExpressionContext *context, QgsExpression *parent );
421
422 static QVariantList getListValue( const QVariant &value, QgsExpression *parent )
423 {
424 if ( value.userType() == QMetaType::Type::QVariantList || value.userType() == QMetaType::Type::QStringList )
425 {
426 return value.toList();
427 }
428 else
429 {
430 if ( parent )
431 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to array" ).arg( value.toString() ) );
432 return QVariantList();
433 }
434 }
435
436 static QVariantMap getMapValue( const QVariant &value, QgsExpression *parent )
437 {
438 if ( value.userType() == QMetaType::Type::QVariantMap )
439 {
440 return value.toMap();
441 }
442 else
443 {
444 if ( parent )
445 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to map" ).arg( value.toString() ) );
446 return QVariantMap();
447 }
448 }
449
456 static QString toLocalizedString( const QVariant &value )
457 {
458 if ( value.userType() == QMetaType::Type::Int || value.userType() == QMetaType::Type::UInt || value.userType() == QMetaType::Type::LongLong || value.userType() == QMetaType::Type::ULongLong )
459 {
460 bool ok;
461 QString res;
462
463 if ( value.userType() == QMetaType::Type::ULongLong )
464 {
465 res = QLocale().toString( value.toULongLong( &ok ) );
466 }
467 else
468 {
469 res = QLocale().toString( value.toLongLong( &ok ) );
470 }
471
472 if ( ok )
473 {
474 return res;
475 }
476 else
477 {
478 return value.toString();
479 }
480 }
481 // Qt madness with QMetaType::Float :/
482 else if ( value.userType() == QMetaType::Type::Double || value.userType() == static_cast<QMetaType::Type>( QMetaType::Float ) )
483 {
484 bool ok;
485 const QString strVal = value.toString();
486 const int dotPosition = strVal.indexOf( '.' );
487 const int precision = dotPosition > 0 ? strVal.length() - dotPosition - 1 : 0;
488 const QString res = QLocale().toString( value.toDouble( &ok ), 'f', precision );
489
490 if ( ok )
491 {
492 return res;
493 }
494 else
495 {
496 return value.toString();
497 }
498 }
499 else
500 {
501 return value.toString();
502 }
503 }
505
515 static std::tuple<QMetaType::Type, int> determineResultType( const QString &expression, const QgsVectorLayer *layer, const QgsFeatureRequest &request = QgsFeatureRequest(), const QgsExpressionContext &context = QgsExpressionContext(), bool *foundFeatures = nullptr );
516
517 private:
518
522 static QgsMapLayer *getMapLayerPrivate( const QVariant &value, const QgsExpressionContext *context, QgsExpression * );
523
524};
525
526
527#endif // QGSEXPRESSIONUTILS_H
This class represents a coordinate reference system (CRS).
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:58
bool isValid() const
Returns the validity of this feature.
A geometry is the spatial representation of a feature.
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.
static QgsInterval fromString(const QString &string)
Converts a string to an interval.
Base class for all map layer types.
Definition qgsmaplayer.h:76
A QgsGeometry with associated coordinate reference system.
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:6125
int precision