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