QGIS API Documentation  3.2.0-Bonn (bc43194)
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 : [email protected]
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 "qgscolorramp.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsproject.h"
27 #include "qgsrelationmanager.h"
28 
29 
30 #define ENSURE_NO_EVAL_ERROR { if ( parent->hasEvalError() ) return QVariant(); }
31 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString( x ); return QVariant(); }
32 
33 #define FEAT_FROM_CONTEXT(c, f) if ( !(c) || !( c )->hasFeature() ) return QVariant(); \
34  QgsFeature f = ( c )->feature();
35 
37 // three-value logic
38 
40 class QgsExpressionUtils
41 {
42  public:
43  enum TVL
44  {
45  False,
46  True,
47  Unknown
48  };
49 
50 
51  static TVL AND[3][3];
52 
53  static TVL OR[3][3];
54 
55  static TVL NOT[3];
56 
57 #define TVL_True QVariant( 1 )
58 #define TVL_False QVariant( 0 )
59 #define TVL_Unknown QVariant()
60 
61  static QVariant tvl2variant( TVL v )
62  {
63  switch ( v )
64  {
65  case False:
66  return TVL_False;
67  case True:
68  return TVL_True;
69  case Unknown:
70  default:
71  return TVL_Unknown;
72  }
73  }
74 
75 // this handles also NULL values
76  static TVL getTVLValue( const QVariant &value, QgsExpression *parent )
77  {
78  // we need to convert to TVL
79  if ( value.isNull() )
80  return Unknown;
81 
82  //handle some special cases
83  if ( value.canConvert<QgsGeometry>() )
84  {
85  //geom is false if empty
86  QgsGeometry geom = value.value<QgsGeometry>();
87  return geom.isNull() ? False : True;
88  }
89  else if ( value.canConvert<QgsFeature>() )
90  {
91  //feat is false if non-valid
92  QgsFeature feat = value.value<QgsFeature>();
93  return feat.isValid() ? True : False;
94  }
95 
96  if ( value.type() == QVariant::Int )
97  return value.toInt() != 0 ? True : False;
98 
99  bool ok;
100  double x = value.toDouble( &ok );
101  if ( !ok )
102  {
103  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
104  return Unknown;
105  }
106  return !qgsDoubleNear( x, 0.0 ) ? True : False;
107  }
108 
109 
110  static inline bool isIntSafe( const QVariant &v )
111  {
112  if ( v.type() == QVariant::Int )
113  return true;
114  if ( v.type() == QVariant::UInt )
115  return true;
116  if ( v.type() == QVariant::LongLong )
117  return true;
118  if ( v.type() == QVariant::ULongLong )
119  return true;
120  if ( v.type() == QVariant::Double )
121  return false;
122  if ( v.type() == QVariant::String )
123  {
124  bool ok;
125  v.toString().toInt( &ok );
126  return ok;
127  }
128  return false;
129  }
130 
131  static inline bool isDoubleSafe( const QVariant &v )
132  {
133  if ( v.type() == QVariant::Double )
134  return true;
135  if ( v.type() == QVariant::Int )
136  return true;
137  if ( v.type() == QVariant::UInt )
138  return true;
139  if ( v.type() == QVariant::LongLong )
140  return true;
141  if ( v.type() == QVariant::ULongLong )
142  return true;
143  if ( v.type() == QVariant::String )
144  {
145  bool ok;
146  double val = v.toString().toDouble( &ok );
147  ok = ok && std::isfinite( val ) && !std::isnan( val );
148  return ok;
149  }
150  return false;
151  }
152 
153  static inline bool isDateTimeSafe( const QVariant &v )
154  {
155  return v.type() == QVariant::DateTime
156  || v.type() == QVariant::Date
157  || v.type() == QVariant::Time;
158  }
159 
160  static inline bool isIntervalSafe( const QVariant &v )
161  {
162  if ( v.canConvert<QgsInterval>() )
163  {
164  return true;
165  }
166 
167  if ( v.type() == QVariant::String )
168  {
169  return QgsInterval::fromString( v.toString() ).isValid();
170  }
171  return false;
172  }
173 
174  static inline bool isNull( const QVariant &v )
175  {
176  return v.isNull();
177  }
178 
179  static inline bool isList( const QVariant &v )
180  {
181  return v.type() == QVariant::List;
182  }
183 
184 // implicit conversion to string
185  static QString getStringValue( const QVariant &value, QgsExpression * )
186  {
187  return value.toString();
188  }
189 
190  static double getDoubleValue( const QVariant &value, QgsExpression *parent )
191  {
192  bool ok;
193  double x = value.toDouble( &ok );
194  if ( !ok || std::isnan( x ) || !std::isfinite( x ) )
195  {
196  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
197  return 0;
198  }
199  return x;
200  }
201 
202  static qlonglong getIntValue( const QVariant &value, QgsExpression *parent )
203  {
204  bool ok;
205  qlonglong x = value.toLongLong( &ok );
206  if ( ok )
207  {
208  return x;
209  }
210  else
211  {
212  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
213  return 0;
214  }
215  }
216 
217  static int getNativeIntValue( const QVariant &value, QgsExpression *parent )
218  {
219  bool ok;
220  qlonglong x = value.toLongLong( &ok );
221  if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
222  {
223  return x;
224  }
225  else
226  {
227  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to native int" ).arg( value.toString() ) );
228  return 0;
229  }
230  }
231 
232  static QDateTime getDateTimeValue( const QVariant &value, QgsExpression *parent )
233  {
234  QDateTime d = value.toDateTime();
235  if ( d.isValid() )
236  {
237  return d;
238  }
239  else
240  {
241  QTime t = value.toTime();
242  if ( t.isValid() )
243  {
244  return QDateTime( QDate( 1, 1, 1 ), t );
245  }
246 
247  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
248  return QDateTime();
249  }
250  }
251 
252  static QDate getDateValue( const QVariant &value, QgsExpression *parent )
253  {
254  QDate d = value.toDate();
255  if ( d.isValid() )
256  {
257  return d;
258  }
259  else
260  {
261  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
262  return QDate();
263  }
264  }
265 
266  static QTime getTimeValue( const QVariant &value, QgsExpression *parent )
267  {
268  QTime t = value.toTime();
269  if ( t.isValid() )
270  {
271  return t;
272  }
273  else
274  {
275  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
276  return QTime();
277  }
278  }
279 
280  static QgsInterval getInterval( const QVariant &value, QgsExpression *parent, bool report_error = false )
281  {
282  if ( value.canConvert<QgsInterval>() )
283  return value.value<QgsInterval>();
284 
285  QgsInterval inter = QgsInterval::fromString( value.toString() );
286  if ( inter.isValid() )
287  {
288  return inter;
289  }
290  // If we get here then we can't convert so we just error and return invalid.
291  if ( report_error )
292  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to interval" ).arg( value.toString() ) );
293 
294  return QgsInterval();
295  }
296 
297  static QgsGradientColorRamp getRamp( const QVariant &value, QgsExpression *parent, bool report_error = false )
298  {
299  if ( value.canConvert<QgsGradientColorRamp>() )
300  return value.value<QgsGradientColorRamp>();
301 
302  // If we get here then we can't convert so we just error and return invalid.
303  if ( report_error )
304  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to gradient ramp" ).arg( value.toString() ) );
305 
306  return QgsGradientColorRamp();
307  }
308 
309  static QgsGeometry getGeometry( const QVariant &value, QgsExpression *parent )
310  {
311  if ( value.canConvert<QgsGeometry>() )
312  return value.value<QgsGeometry>();
313 
314  parent->setEvalErrorString( QStringLiteral( "Cannot convert to geometry" ) );
315  return QgsGeometry();
316  }
317 
318  static QgsFeature getFeature( const QVariant &value, QgsExpression *parent )
319  {
320  if ( value.canConvert<QgsFeature>() )
321  return value.value<QgsFeature>();
322 
323  parent->setEvalErrorString( QStringLiteral( "Cannot convert to feature" ) );
324  return 0;
325  }
326 
327  static QgsExpressionNode *getNode( const QVariant &value, QgsExpression *parent )
328  {
329  if ( value.canConvert<QgsExpressionNode *>() )
330  return value.value<QgsExpressionNode *>();
331 
332  parent->setEvalErrorString( QStringLiteral( "Cannot convert to node" ) );
333  return nullptr;
334  }
335 
336  static QgsMapLayer *getMapLayer( const QVariant &value, QgsExpression * )
337  {
338  // First check if we already received a layer pointer
339  QgsMapLayer *ml = value.value< QgsWeakMapLayerPointer >().data();
340  QgsProject *project = QgsProject::instance();
341 
342  // No pointer yet, maybe it's a layer id?
343  if ( !ml )
344  ml = project->mapLayer( value.toString() );
345 
346  // Still nothing? Check for layer name
347  if ( !ml )
348  ml = project->mapLayersByName( value.toString() ).value( 0 );
349 
350  return ml;
351  }
352 
353  static QgsVectorLayer *getVectorLayer( const QVariant &value, QgsExpression *e )
354  {
355  return qobject_cast<QgsVectorLayer *>( getMapLayer( value, e ) );
356  }
357 
358 
359  static QVariantList getListValue( const QVariant &value, QgsExpression *parent )
360  {
361  if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
362  {
363  return value.toList();
364  }
365  else
366  {
367  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to array" ).arg( value.toString() ) );
368  return QVariantList();
369  }
370  }
371 
372  static QVariantMap getMapValue( const QVariant &value, QgsExpression *parent )
373  {
374  if ( value.type() == QVariant::Map )
375  {
376  return value.toMap();
377  }
378  else
379  {
380  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to map" ).arg( value.toString() ) );
381  return QVariantMap();
382  }
383  }
384 };
385 
387 
388 #endif // QGSEXPRESSIONUTILS_H
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:176
Class for parsing and evaluation of expressions (formerly called "search strings").
Base class for all map layer types.
Definition: qgsmaplayer.h:61
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:251
static QgsInterval fromString(const QString &string)
Converts a string to an interval.
Definition: qgsinterval.cpp:45
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:104
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:1385
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions)
double value(int index) const override
Returns relative value between [0,1] of color at specified index.
Reads and writes project states.
Definition: qgsproject.h:85
Abstract base class for all nodes that can appear in an expression.
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
A representation of the interval between two datetime values.
Definition: qgsinterval.h:39
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:391
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorramp.h:139
Represents a vector layer which manages a vector based data sets.