QGIS API Documentation 3.39.0-Master (47f7b3a4989)
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 "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.type() == QVariant::UserType )
98 {
99 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
100 {
101 //geom is false if empty
102 const QgsGeometry geom = value.value<QgsGeometry>();
103 return geom.isNull() ? False : True;
104 }
105 else if ( value.userType() == QMetaType::type( "QgsFeature" ) )
106 {
107 //feat is false if non-valid
108 const QgsFeature feat = value.value<QgsFeature>();
109 return feat.isValid() ? True : False;
110 }
111 }
112
113 if ( value.userType() == QMetaType::Type::Int )
114 return value.toInt() != 0 ? True : False;
115
116 bool ok;
117 const double x = value.toDouble( &ok );
118 if ( !ok )
119 {
120 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
121 return Unknown;
122 }
123 return !qgsDoubleNear( x, 0.0 ) ? True : False;
124 }
125
126
127 static inline bool isIntSafe( const QVariant &v )
128 {
129 if ( v.userType() == QMetaType::Type::Int )
130 return true;
131 if ( v.userType() == QMetaType::Type::UInt )
132 return true;
133 if ( v.userType() == QMetaType::Type::LongLong )
134 return true;
135 if ( v.userType() == QMetaType::Type::ULongLong )
136 return true;
137 if ( v.userType() == QMetaType::Type::Double )
138 return false;
139 if ( v.userType() == QMetaType::Type::QString )
140 {
141 bool ok;
142 v.toString().toInt( &ok );
143 return ok;
144 }
145 return false;
146 }
147
148 static inline bool isDoubleSafe( const QVariant &v )
149 {
150 if ( v.userType() == QMetaType::Type::Double )
151 return true;
152 if ( v.userType() == QMetaType::Type::Int )
153 return true;
154 if ( v.userType() == QMetaType::Type::UInt )
155 return true;
156 if ( v.userType() == QMetaType::Type::LongLong )
157 return true;
158 if ( v.userType() == QMetaType::Type::ULongLong )
159 return true;
160 if ( v.userType() == QMetaType::Type::QString )
161 {
162 bool ok;
163 const double val = v.toString().toDouble( &ok );
164 ok = ok && std::isfinite( val ) && !std::isnan( val );
165 return ok;
166 }
167 return false;
168 }
169
170 static inline bool isDateTimeSafe( const QVariant &v )
171 {
172 return v.userType() == QMetaType::Type::QDateTime
173 || v.userType() == QMetaType::Type::QDate
174 || v.userType() == QMetaType::Type::QTime;
175 }
176
177 static inline bool isIntervalSafe( const QVariant &v )
178 {
179 if ( v.userType() == QMetaType::type( "QgsInterval" ) )
180 {
181 return true;
182 }
183
184 if ( v.userType() == QMetaType::Type::QString )
185 {
186 return QgsInterval::fromString( v.toString() ).isValid();
187 }
188 return false;
189 }
190
191 static inline bool isNull( const QVariant &v )
192 {
193 return QgsVariantUtils::isNull( v );
194 }
195
196 static inline bool isList( const QVariant &v )
197 {
198 return v.userType() == QMetaType::Type::QVariantList || v.userType() == QMetaType::Type::QStringList;
199 }
200
201// implicit conversion to string
202 static QString getStringValue( const QVariant &value, QgsExpression * )
203 {
204 return value.toString();
205 }
206
214 static QByteArray getBinaryValue( const QVariant &value, QgsExpression *parent )
215 {
216 if ( value.userType() != QMetaType::Type::QByteArray )
217 {
218 parent->setEvalErrorString( QObject::tr( "Value is not a binary value" ) );
219 return QByteArray();
220 }
221 return value.toByteArray();
222 }
223
224 static double getDoubleValue( const QVariant &value, QgsExpression *parent )
225 {
226 bool ok;
227 const double x = value.toDouble( &ok );
228 if ( !ok || std::isnan( x ) || !std::isfinite( x ) )
229 {
230 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
231 return 0;
232 }
233 return x;
234 }
235
236 static qlonglong getIntValue( const QVariant &value, QgsExpression *parent )
237 {
238 bool ok;
239 const qlonglong x = value.toLongLong( &ok );
240 if ( ok )
241 {
242 return x;
243 }
244 else
245 {
246 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
247 return 0;
248 }
249 }
250
251 static int getNativeIntValue( const QVariant &value, QgsExpression *parent )
252 {
253 bool ok;
254 const qlonglong x = value.toLongLong( &ok );
255 if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
256 {
257 return static_cast<int>( x );
258 }
259 else
260 {
261 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to native int" ).arg( value.toString() ) );
262 return 0;
263 }
264 }
265
266 static QDateTime getDateTimeValue( const QVariant &value, QgsExpression *parent )
267 {
268 QDateTime d = value.toDateTime();
269 if ( d.isValid() )
270 {
271 return d;
272 }
273 else
274 {
275 const QTime t = value.toTime();
276 if ( t.isValid() )
277 {
278 return QDateTime( QDate( 1, 1, 1 ), t );
279 }
280
281 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
282 return QDateTime();
283 }
284 }
285
286 static QDate getDateValue( const QVariant &value, QgsExpression *parent )
287 {
288 QDate d = value.toDate();
289 if ( d.isValid() )
290 {
291 return d;
292 }
293 else
294 {
295 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
296 return QDate();
297 }
298 }
299
300 static QTime getTimeValue( const QVariant &value, QgsExpression *parent )
301 {
302 QTime t = value.toTime();
303 if ( t.isValid() )
304 {
305 return t;
306 }
307 else
308 {
309 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
310 return QTime();
311 }
312 }
313
314 static QgsInterval getInterval( const QVariant &value, QgsExpression *parent, bool report_error = false )
315 {
316 if ( value.userType() == QMetaType::type( "QgsInterval" ) )
317 return value.value<QgsInterval>();
318
319 QgsInterval inter = QgsInterval::fromString( value.toString() );
320 if ( inter.isValid() )
321 {
322 return inter;
323 }
324 // If we get here then we can't convert so we just error and return invalid.
325 if ( report_error )
326 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to interval" ).arg( value.toString() ) );
327
328 return QgsInterval();
329 }
330
331 static QgsGradientColorRamp getRamp( const QVariant &value, QgsExpression *parent, bool report_error = false );
332
333 static QgsGeometry getGeometry( const QVariant &value, QgsExpression *parent )
334 {
335 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
336 return value.value<QgsGeometry>();
337
338 parent->setEvalErrorString( QStringLiteral( "Cannot convert to geometry" ) );
339 return QgsGeometry();
340 }
341
342 static QgsFeature getFeature( const QVariant &value, QgsExpression *parent )
343 {
344 if ( value.userType() == QMetaType::type( "QgsFeature" ) )
345 return value.value<QgsFeature>();
346
347 parent->setEvalErrorString( QStringLiteral( "Cannot convert to feature" ) );
348 return 0;
349 }
350
351 static QgsExpressionNode *getNode( const QVariant &value, QgsExpression *parent )
352 {
353 if ( value.canConvert<QgsExpressionNode *>() )
354 return value.value<QgsExpressionNode *>();
355
356 parent->setEvalErrorString( QStringLiteral( "Cannot convert to node" ) );
357 return nullptr;
358 }
359
363 Q_DECL_DEPRECATED static QgsMapLayer *getMapLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression * );
364
370 static void executeLambdaForMapLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression *expression, const std::function< void( QgsMapLayer * )> &function, bool &foundLayer );
371
377 static QVariant runMapLayerFunctionThreadSafe( const QVariant &value, const QgsExpressionContext *context, QgsExpression *expression, const std::function<QVariant( QgsMapLayer * ) > &function, bool &foundLayer );
378
382 static std::unique_ptr<QgsVectorLayerFeatureSource> getFeatureSource( const QVariant &value, const QgsExpressionContext *context, QgsExpression *e, bool &foundLayer );
383
387 Q_DECL_DEPRECATED static QgsVectorLayer *getVectorLayer( const QVariant &value, const QgsExpressionContext *context, QgsExpression *e );
388
394 static QString getFilePathValue( const QVariant &value, const QgsExpressionContext *context, QgsExpression *parent );
395
396 static QVariantList getListValue( const QVariant &value, QgsExpression *parent )
397 {
398 if ( value.userType() == QMetaType::Type::QVariantList || value.userType() == QMetaType::Type::QStringList )
399 {
400 return value.toList();
401 }
402 else
403 {
404 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to array" ).arg( value.toString() ) );
405 return QVariantList();
406 }
407 }
408
409 static QVariantMap getMapValue( const QVariant &value, QgsExpression *parent )
410 {
411 if ( value.userType() == QMetaType::Type::QVariantMap )
412 {
413 return value.toMap();
414 }
415 else
416 {
417 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to map" ).arg( value.toString() ) );
418 return QVariantMap();
419 }
420 }
421
428 static QString toLocalizedString( const QVariant &value )
429 {
430 if ( value.userType() == QMetaType::Type::Int || value.userType() == QMetaType::Type::UInt || value.userType() == QMetaType::Type::LongLong || value.userType() == QMetaType::Type::ULongLong )
431 {
432 bool ok;
433 QString res;
434
435 if ( value.userType() == QMetaType::Type::ULongLong )
436 {
437 res = QLocale().toString( value.toULongLong( &ok ) );
438 }
439 else
440 {
441 res = QLocale().toString( value.toLongLong( &ok ) );
442 }
443
444 if ( ok )
445 {
446 return res;
447 }
448 else
449 {
450 return value.toString();
451 }
452 }
453 // Qt madness with QMetaType::Float :/
454 else if ( value.userType() == QMetaType::Type::Double || value.userType() == static_cast<QMetaType::Type>( QMetaType::Float ) )
455 {
456 bool ok;
457 const QString strVal = value.toString();
458 const int dotPosition = strVal.indexOf( '.' );
459 const int precision = dotPosition > 0 ? strVal.length() - dotPosition - 1 : 0;
460 const QString res = QLocale().toString( value.toDouble( &ok ), 'f', precision );
461
462 if ( ok )
463 {
464 return res;
465 }
466 else
467 {
468 return value.toString();
469 }
470 }
471 else
472 {
473 return value.toString();
474 }
475 }
477
487 static std::tuple<QMetaType::Type, int> determineResultType( const QString &expression, const QgsVectorLayer *layer, QgsFeatureRequest request = QgsFeatureRequest(), QgsExpressionContext context = QgsExpressionContext(), bool *foundFeatures = nullptr );
488
489 private:
490
494 static QgsMapLayer *getMapLayerPrivate( const QVariant &value, const QgsExpressionContext *context, QgsExpression * );
495
496};
497
498
499#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: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: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:5465
int precision