QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgsjsonutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsjsonutils.h
3  -------------
4  Date : May 206
5  Copyright : (C) 2016 Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
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 #include "qgsjsonutils.h"
17 #include "qgsfeatureiterator.h"
18 #include "qgsogrutils.h"
19 #include "qgsgeometry.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsrelation.h"
22 #include "qgsrelationmanager.h"
23 #include "qgsproject.h"
24 #include "qgsexception.h"
25 #include "qgslogger.h"
27 #include "qgsfieldformatter.h"
28 #include "qgsapplication.h"
29 
30 #include <QJsonDocument>
31 #include <QJsonArray>
32 #include <nlohmann/json.hpp>
33 
35  : mPrecision( precision )
36  , mLayer( vectorLayer )
37 {
38  if ( vectorLayer )
39  {
40  mCrs = vectorLayer->crs();
41  mTransform.setSourceCrs( mCrs );
42  }
43  mTransform.setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
44 }
45 
47 {
48  mLayer = vectorLayer;
49  if ( vectorLayer )
50  {
51  mCrs = vectorLayer->crs();
52  mTransform.setSourceCrs( mCrs );
53  }
54 }
55 
57 {
58  return mLayer.data();
59 }
60 
62 {
63  mCrs = crs;
64  mTransform.setSourceCrs( mCrs );
65 }
66 
68 {
69  return mCrs;
70 }
71 
72 QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVariantMap &extraProperties,
73  const QVariant &id, int indent ) const
74 {
75  return QString::fromStdString( exportFeatureToJsonObject( feature, extraProperties, id ).dump( indent ) );
76 }
77 
78 json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, const QVariantMap &extraProperties, const QVariant &id ) const
79 {
80  json featureJson
81  {
82  { "type", "Feature" },
83  };
84  if ( id.isValid() )
85  {
86  bool ok = false;
87  auto intId = id.toLongLong( &ok );
88  if ( ok )
89  {
90  featureJson["id"] = intId;
91  }
92  else
93  {
94  featureJson["id"] = id.toString().toStdString();
95  }
96  }
97  else
98  {
99  featureJson["id"] = feature.id();
100  }
101 
102  QgsGeometry geom = feature.geometry();
103  if ( !geom.isNull() && mIncludeGeometry )
104  {
105  if ( mCrs.isValid() )
106  {
107  try
108  {
109  QgsGeometry transformed = geom;
110  if ( mTransformGeometries && transformed.transform( mTransform ) == 0 )
111  geom = transformed;
112  }
113  catch ( QgsCsException &cse )
114  {
115  Q_UNUSED( cse )
116  }
117  }
118  QgsRectangle box = geom.boundingBox();
119 
121  {
122  featureJson[ "bbox" ] =
123  {
124  qgsRound( box.xMinimum(), mPrecision ),
125  qgsRound( box.yMinimum(), mPrecision ),
126  qgsRound( box.xMaximum(), mPrecision ),
127  qgsRound( box.yMaximum(), mPrecision )
128  };
129  }
130  featureJson[ "geometry" ] = geom.asJsonObject( mPrecision );
131  }
132  else
133  {
134  featureJson[ "geometry" ] = nullptr;
135  }
136 
137  // build up properties element
138  int attributeCounter { 0 };
139  json properties;
140  if ( mIncludeAttributes || !extraProperties.isEmpty() )
141  {
142  //read all attribute values from the feature
143  if ( mIncludeAttributes )
144  {
145  QgsFields fields = mLayer ? mLayer->fields() : feature.fields();
146  // List of formatters through we want to pass the values
147  QStringList formattersWhiteList;
148  formattersWhiteList << QStringLiteral( "KeyValue" )
149  << QStringLiteral( "List" )
150  << QStringLiteral( "ValueRelation" )
151  << QStringLiteral( "ValueMap" );
152 
153  for ( int i = 0; i < fields.count(); ++i )
154  {
155  if ( ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) ) || mExcludedAttributeIndexes.contains( i ) )
156  continue;
157 
158  QVariant val = feature.attributes().at( i );
159 
160  if ( mLayer )
161  {
162  const QgsEditorWidgetSetup setup = fields.at( i ).editorWidgetSetup();
163  const QgsFieldFormatter *fieldFormatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
164  if ( formattersWhiteList.contains( fieldFormatter->id() ) )
165  val = fieldFormatter->representValue( mLayer.data(), i, setup.config(), QVariant(), val );
166  }
167 
168  QString name = fields.at( i ).name();
169  if ( mAttributeDisplayName )
170  {
171  name = mLayer->attributeDisplayName( i );
172  }
173  properties[ name.toStdString() ] = QgsJsonUtils::jsonFromVariant( val );
174  attributeCounter++;
175  }
176  }
177 
178  if ( !extraProperties.isEmpty() )
179  {
180  QVariantMap::const_iterator it = extraProperties.constBegin();
181  for ( ; it != extraProperties.constEnd(); ++it )
182  {
183  properties[ it.key().toStdString() ] = QgsJsonUtils::jsonFromVariant( it.value() );
184  attributeCounter++;
185  }
186  }
187 
188  // related attributes
189  if ( mLayer && mIncludeRelatedAttributes )
190  {
191  QList< QgsRelation > relations = QgsProject::instance()->relationManager()->referencedRelations( mLayer.data() );
192  for ( const auto &relation : qgis::as_const( relations ) )
193  {
194  QgsFeatureRequest req = relation.getRelatedFeaturesRequest( feature );
196  QgsVectorLayer *childLayer = relation.referencingLayer();
197  json relatedFeatureAttributes;
198  if ( childLayer )
199  {
200  QgsFeatureIterator it = childLayer->getFeatures( req );
201  QVector<QVariant> attributeWidgetCaches;
202  int fieldIndex = 0;
203  const QgsFields fields { childLayer->fields() };
204  for ( const QgsField &field : fields )
205  {
206  QgsEditorWidgetSetup setup = field.editorWidgetSetup();
208  attributeWidgetCaches.append( fieldFormatter->createCache( childLayer, fieldIndex, setup.config() ) );
209  fieldIndex++;
210  }
211  QgsFeature relatedFet;
212  while ( it.nextFeature( relatedFet ) )
213  {
214  relatedFeatureAttributes += QgsJsonUtils::exportAttributesToJsonObject( relatedFet, childLayer, attributeWidgetCaches );
215  }
216  }
217  properties[ relation.name().toStdString() ] = relatedFeatureAttributes;
218  attributeCounter++;
219  }
220  }
221  }
222  featureJson[ "properties" ] = properties;
223  return featureJson;
224 }
225 
226 QString QgsJsonExporter::exportFeatures( const QgsFeatureList &features, int indent ) const
227 {
228  return QString::fromStdString( exportFeaturesToJsonObject( features ).dump( indent ) );
229 }
230 
232 {
233  json data
234  {
235  { "type", "FeatureCollection" },
236  { "features", json::array() }
237  };
238  for ( const QgsFeature &feature : qgis::as_const( features ) )
239  {
240  data["features"].push_back( exportFeatureToJsonObject( feature ) );
241  }
242  return data;
243 }
244 
245 //
246 // QgsJsonUtils
247 //
248 
249 QgsFeatureList QgsJsonUtils::stringToFeatureList( const QString &string, const QgsFields &fields, QTextCodec *encoding )
250 {
251  if ( !encoding )
252  encoding = QTextCodec::codecForName( "UTF-8" );
253 
254  return QgsOgrUtils::stringToFeatureList( string, fields, encoding );
255 }
256 
257 QgsFields QgsJsonUtils::stringToFields( const QString &string, QTextCodec *encoding )
258 {
259  if ( !encoding )
260  encoding = QTextCodec::codecForName( "UTF-8" );
261 
262  return QgsOgrUtils::stringToFields( string, encoding );
263 }
264 
265 QString QgsJsonUtils::encodeValue( const QVariant &value )
266 {
267  if ( value.isNull() )
268  return QStringLiteral( "null" );
269 
270  switch ( value.type() )
271  {
272  case QVariant::Int:
273  case QVariant::UInt:
274  case QVariant::LongLong:
275  case QVariant::ULongLong:
276  case QVariant::Double:
277  return value.toString();
278 
279  case QVariant::Bool:
280  return value.toBool() ? "true" : "false";
281 
282  case QVariant::StringList:
283  case QVariant::List:
284  case QVariant::Map:
285  return QString::fromUtf8( QJsonDocument::fromVariant( value ).toJson( QJsonDocument::Compact ) );
286 
287  default:
288  case QVariant::String:
289  QString v = value.toString()
290  .replace( '\\', QLatin1String( "\\\\" ) )
291  .replace( '"', QLatin1String( "\\\"" ) )
292  .replace( '\r', QLatin1String( "\\r" ) )
293  .replace( '\b', QLatin1String( "\\b" ) )
294  .replace( '\t', QLatin1String( "\\t" ) )
295  .replace( '/', QLatin1String( "\\/" ) )
296  .replace( '\n', QLatin1String( "\\n" ) );
297 
298  return v.prepend( '"' ).append( '"' );
299  }
300 }
301 
302 QString QgsJsonUtils::exportAttributes( const QgsFeature &feature, QgsVectorLayer *layer, const QVector<QVariant> &attributeWidgetCaches )
303 {
304  QgsFields fields = feature.fields();
305  QString attrs;
306  for ( int i = 0; i < fields.count(); ++i )
307  {
308  if ( i > 0 )
309  attrs += QLatin1String( ",\n" );
310 
311  QVariant val = feature.attributes().at( i );
312 
313  if ( layer )
314  {
315  QgsEditorWidgetSetup setup = layer->fields().at( i ).editorWidgetSetup();
318  val = fieldFormatter->representValue( layer, i, setup.config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
319  }
320 
321  attrs += encodeValue( fields.at( i ).name() ) + ':' + encodeValue( val );
322  }
323  return attrs.prepend( '{' ).append( '}' );
324 }
325 
326 QVariantList QgsJsonUtils::parseArray( const QString &json, QVariant::Type type )
327 {
328  QString errorMessage;
329  QVariantList result;
330  try
331  {
332  const auto jObj( json::parse( json.toStdString() ) );
333  if ( ! jObj.is_array() )
334  {
335  throw json::parse_error::create( 0, 0, QStringLiteral( "JSON value must be an array" ).toStdString() );
336  }
337  for ( const auto &item : jObj )
338  {
339  // Create a QVariant from the array item
340  QVariant v;
341  if ( item.is_number_integer() )
342  {
343  v = item.get<int>();
344  }
345  else if ( item.is_number_unsigned() )
346  {
347  v = item.get<unsigned>();
348  }
349  else if ( item.is_number_float() )
350  {
351  // Note: it's a double and not a float on purpose
352  v = item.get<double>();
353  }
354  else if ( item.is_string() )
355  {
356  v = QString::fromStdString( item.get<std::string>() );
357  }
358  else if ( item.is_boolean() )
359  {
360  v = item.get<bool>();
361  }
362  else if ( item.is_null() )
363  {
364  // Fallback to int
365  v = QVariant( type == QVariant::Type::Invalid ? QVariant::Type::Int : type );
366  }
367 
368  // If a destination type was specified (it's not invalid), try to convert
369  if ( type != QVariant::Invalid )
370  {
371  if ( ! v.convert( static_cast<int>( type ) ) )
372  {
373  QgsLogger::warning( QStringLiteral( "Cannot convert json array element to specified type, ignoring: %1" ).arg( v.toString() ) );
374  }
375  else
376  {
377  result.push_back( v );
378  }
379  }
380  else
381  {
382  result.push_back( v );
383  }
384  }
385  }
386  catch ( json::parse_error &ex )
387  {
388  errorMessage = ex.what();
389  QgsLogger::warning( QStringLiteral( "Cannot parse json (%1): %2" ).arg( ex.what(), json ) );
390  }
391 
392  return result;
393 }
394 
395 json QgsJsonUtils::jsonFromVariant( const QVariant &val )
396 {
397  if ( val.isNull() || ! val.isValid() )
398  {
399  return nullptr;
400  }
401  json j;
402  if ( val.type() == QVariant::Type::Map )
403  {
404  const QVariantMap &vMap = val.toMap();
405  json jMap = json::object();
406  for ( auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
407  {
408  jMap[ it.key().toStdString() ] = jsonFromVariant( it.value() );
409  }
410  j = jMap;
411  }
412  else if ( val.type() == QVariant::Type::List || val.type() == QVariant::Type::StringList )
413  {
414  const QVariantList &vList = val.toList();
415  json jList = json::array();
416  for ( const auto &v : vList )
417  {
418  jList.push_back( jsonFromVariant( v ) );
419  }
420  j = jList;
421  }
422  else
423  {
424  switch ( val.userType() )
425  {
426  case QMetaType::Int:
427  case QMetaType::UInt:
428  case QMetaType::LongLong:
429  case QMetaType::ULongLong:
430  j = val.toLongLong();
431  break;
432  case QMetaType::Double:
433  case QMetaType::Float:
434  j = val.toDouble();
435  break;
436  case QMetaType::Bool:
437  j = val.toBool();
438  break;
439  case QMetaType::QByteArray:
440  j = val.toByteArray().toBase64().toStdString();
441  break;
442  default:
443  j = val.toString().toStdString();
444  break;
445  }
446  }
447  return j;
448 }
449 
450 QVariant QgsJsonUtils::parseJson( const std::string &jsonString )
451 {
452  // tracks whether entire json string is a primitive
453  bool isPrimitive = true;
454 
455  std::function<QVariant( json )> _parser { [ & ]( json jObj ) -> QVariant {
456  QVariant result;
457  if ( jObj.is_array() )
458  {
459  isPrimitive = false;
460  QVariantList results;
461  for ( const auto &item : jObj )
462  {
463  results.push_back( _parser( item ) );
464  }
465  result = results;
466  }
467  else if ( jObj.is_object() )
468  {
469  isPrimitive = false;
470  QVariantMap results;
471  for ( const auto &item : jObj.items() )
472  {
473  const auto key { QString::fromStdString( item.key() ) };
474  const auto value { _parser( item.value() ) };
475  results[ key ] = value;
476  }
477  result = results;
478  }
479  else
480  {
481  if ( jObj.is_number_integer() )
482  {
483  result = jObj.get<int>();
484  }
485  else if ( jObj.is_number_unsigned() )
486  {
487  result = jObj.get<unsigned>();
488  }
489  else if ( jObj.is_boolean() )
490  {
491  result = jObj.get<bool>();
492  }
493  else if ( jObj.is_number_float() )
494  {
495  // Note: it's a double and not a float on purpose
496  result = jObj.get<double>();
497  }
498  else if ( jObj.is_string() )
499  {
500  if ( isPrimitive && jObj.get<std::string>().length() == 0 )
501  {
502  result = QString::fromStdString( jObj.get<std::string>() ).append( "\"" ).insert( 0, "\"" );
503  }
504  else
505  {
506  result = QString::fromStdString( jObj.get<std::string>() );
507  }
508  }
509  else if ( jObj.is_null() )
510  {
511  // Do nothing (leave invalid)
512  }
513  }
514  return result;
515  }
516  };
517 
518  try
519  {
520  const json j = json::parse( jsonString );
521  return _parser( j );
522  }
523  catch ( json::parse_error &ex )
524  {
525  QgsLogger::warning( QStringLiteral( "Cannot parse json (%1): %2" ).arg( QString::fromStdString( ex.what() ),
526  QString::fromStdString( jsonString ) ) );
527  }
528  return QVariant();
529 }
530 
531 QVariant QgsJsonUtils::parseJson( const QString &jsonString )
532 {
533  return parseJson( jsonString.toStdString() );
534 }
535 
536 json QgsJsonUtils::exportAttributesToJsonObject( const QgsFeature &feature, QgsVectorLayer *layer, const QVector<QVariant> &attributeWidgetCaches )
537 {
538  QgsFields fields = feature.fields();
539  json attrs;
540  for ( int i = 0; i < fields.count(); ++i )
541  {
542  QVariant val = feature.attributes().at( i );
543 
544  if ( layer )
545  {
546  QgsEditorWidgetSetup setup = layer->fields().at( i ).editorWidgetSetup();
549  val = fieldFormatter->representValue( layer, i, setup.config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
550  }
551  attrs[fields.at( i ).name().toStdString()] = jsonFromVariant( val );
552  }
553  return attrs;
554 }
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
int precision
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QVariantMap config() const
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
static json jsonFromVariant(const QVariant &v)
Converts a QVariant v to a json object.
json exportFeatureToJsonObject(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant()) const
Returns a QJsonObject representation of a feature.
QString name
Definition: qgsfield.h:59
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS for feature geometries.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
virtual QVariant createCache(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config) const
Create a cache for a given field.
void setVectorLayer(QgsVectorLayer *vectorLayer)
Sets the associated vector layer (required for related attribute export).
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source CRS for feature geometries.
QString exportFeature(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant(), int indent=-1) const
Returns a GeoJSON string representation of a feature.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:473
virtual QString id() const =0
Returns a unique id for this field formatter.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
const QgsCoordinateReferenceSystem & crs
QgsFields fields
Definition: qgsfeature.h:66
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsVectorLayer * vectorLayer() const
Returns the associated vector layer, if set.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
QString exportFeatures(const QgsFeatureList &features, int indent=-1) const
Returns a GeoJSON string representation of a list of features (feature collection).
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
static QgsFields stringToFields(const QString &string, QTextCodec *encoding=nullptr)
Attempts to retrieve the fields from a GeoJSON string representing a collection of features...
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination coordinate reference system.
static QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a string representing a collection of features using OGR...
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:49
QgsRelationManager relationManager
Definition: qgsproject.h:102
static json exportAttributesToJsonObject(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >())
Exports all attributes from a QgsFeature as a json object.
QgsFieldFormatter * fieldFormatter(const QString &id) const
Gets a field formatter by its id.
static QString exportAttributes(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >())
Exports all attributes from a QgsFeature as a JSON map type.
A field formatter helps to handle and display values for a field.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsJsonExporter(QgsVectorLayer *vectorLayer=nullptr, int precision=6)
Constructor for QgsJsonExporter.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
json exportFeaturesToJsonObject(const QgsFeatureList &features) const
Returns a JSON object representation of a list of features (feature collection).
virtual QString representValue(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value) const
Create a pretty String representation of the value.
virtual json asJsonObject(int precision=17) const
Exports the geometry to a json object.
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places...
Definition: qgis.h:363
Holder for the widget type and its configuration for a field.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:450
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
This class represents a coordinate reference system (CRS).
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields=QgsFields(), QTextCodec *encoding=nullptr)
Attempts to parse a GeoJSON string to a collection of features.
static QVariantList parseArray(const QString &json, QVariant::Type type=QVariant::Invalid)
Parse a simple array (depth=1)
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
QgsFieldFormatter * fallbackFieldFormatter() const
Returns a basic fallback field formatter which can be used to represent any field in an unspectacular...
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned...
QgsGeometry geometry
Definition: qgsfeature.h:67
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg)
Represents a vector layer which manages a vector based data sets.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:576
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source coordinate reference system.
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:86
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.