QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsfilebaseddataitemprovider.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsfilebaseddataitemprovider.cpp
3 --------------------------------------
4 Date : July 2021
5 Copyright : (C) 2021 by 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
17#include "qgsdataprovider.h"
18#include "qgsproviderregistry.h"
19#include "qgslogger.h"
20#include "qgssettings.h"
21#include "qgsogrproviderutils.h"
22#include "qgsstyle.h"
23#include "qgsgeopackagedataitems.h"
25#include "qgsfieldsitem.h"
26#include "qgsfielddomainsitem.h"
28#include "qgsproviderutils.h"
29#include "qgsmbtiles.h"
31#include "qgsprovidermetadata.h"
32#include <QUrlQuery>
33
34//
35// QgsProviderSublayerItem
36//
37
39 const QgsProviderSublayerDetails &details, const QString &filePath )
40 : QgsLayerItem( parent, name, filePath.isEmpty() ? details.uri() : filePath, details.uri(), layerTypeFromSublayer( details ), details.providerKey() )
41 , mDetails( details )
42{
43 mToolTip = details.uri();
44
45 // no children, except for vector layers, which will show the fields item
47}
48
50{
51 QVector<QgsDataItem *> children;
52
53 if ( mDetails.type() == QgsMapLayerType::VectorLayer )
54 {
55 // sqlite gets special handling because it delegates to the dedicated spatialite provider
56 if ( mDetails.driverName() == QLatin1String( "SQLite" ) )
57 {
58 children.push_back( new QgsFieldsItem( this,
59 path() + QStringLiteral( "/columns/ " ),
60 QStringLiteral( R"(dbname="%1")" ).arg( parent()->path().replace( '"', QLatin1String( R"(\")" ) ) ),
61 QStringLiteral( "spatialite" ), QString(), name() ) );
62 }
63 else if ( mDetails.providerKey() == QLatin1String( "ogr" ) )
64 {
65 // otherwise we use the default OGR database connection approach, which is the generic way to handle this
66 // for all OGR layer types
67 children.push_back( new QgsFieldsItem( this,
68 path() + QStringLiteral( "/columns/ " ),
69 path(),
70 QStringLiteral( "ogr" ), QString(), name() ) );
71
72 std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn( databaseConnection() );
73 if ( conn && ( conn->capabilities() & QgsAbstractDatabaseProviderConnection::Capability::RetrieveRelationships ) )
74 {
75 QString relationError;
76 QList< QgsWeakRelation > relations;
77 try
78 {
79 relations = conn->relationships( QString(), mDetails.name() );
80 }
82 {
83 relationError = ex.what();
84 }
85
86 if ( !relations.empty() || !relationError.isEmpty() )
87 {
88 std::unique_ptr< QgsRelationshipsItem > relationsItem = std::make_unique< QgsRelationshipsItem >( this, mPath + "/relations", conn->uri(), QStringLiteral( "ogr" ), QString(), mDetails.name() );
89 // force this item to appear last by setting a maximum string value for the sort key
90 relationsItem->setSortKey( QString( QChar( 0x11FFFF ) ) );
91 children.append( relationsItem.release() );
92 }
93 }
94 }
95 }
96 return children;
97}
98
100{
101 return mDetails;
102}
103
105{
106 if ( parent() )
107 {
109 return connection;
110 }
111
112 if ( mDetails.providerKey() == QLatin1String( "ogr" ) )
113 {
114 if ( QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) )
115 {
116 QVariantMap parts;
117 parts.insert( QStringLiteral( "path" ), path() );
118 return static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( md->encodeUri( parts ), {} ) );
119 }
120 }
121
122 return nullptr;
123}
124
125Qgis::BrowserLayerType QgsProviderSublayerItem::layerTypeFromSublayer( const QgsProviderSublayerDetails &sublayer )
126{
127 switch ( sublayer.type() )
128 {
130 {
131 switch ( QgsWkbTypes::geometryType( sublayer.wkbType() ) )
132 {
135
138
141
144
147 }
148
149 break;
150 }
153
156
159
162
165
168 break;
169 }
171}
172
174{
175 return mDetails.name();
176}
177
178//
179// QgsFileDataCollectionGroupItem
180//
181QgsFileDataCollectionGroupItem::QgsFileDataCollectionGroupItem( QgsDataItem *parent, const QString &groupName, const QString &path )
182 : QgsDataCollectionItem( parent, groupName, path )
183{
185 mIconName = QStringLiteral( "mIconDbSchema.svg" );
186}
187
189{
190 mSublayers.append( sublayer );
191}
192
194{
195 return true;
196}
197
199{
201 res.reserve( mSublayers.size() );
202
203 for ( const QgsProviderSublayerDetails &sublayer : mSublayers )
204 {
205 res << sublayer.toMimeUri();
206 }
207 return res;
208}
209
210//
211// QgsFileDataCollectionItem
212//
213
214QgsFileDataCollectionItem::QgsFileDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path, const QList<QgsProviderSublayerDetails> &sublayers )
215 : QgsDataCollectionItem( parent, name, path )
216 , mSublayers( sublayers )
217{
220 else
222
223 if ( !qgsVsiPrefix( path ).isEmpty() )
224 {
225 mIconName = QStringLiteral( "/mIconZip.svg" );
226 }
227}
228
230{
231 QList< QgsProviderSublayerDetails> sublayers;
233 || mSublayers.empty() )
234 {
236 }
237 else
238 {
239 sublayers = mSublayers;
240 }
241 // only ever use the initial sublayers for first population -- after that we requery when asked to create children,
242 // or the item won't "refresh" and update its sublayers when the actual file changes
243 mSublayers.clear();
244 // remove the fast flag -- after the first population we need to requery the dataset
246
247 QVector<QgsDataItem *> children;
248 children.reserve( sublayers.size() );
249 QMap< QStringList, QgsFileDataCollectionGroupItem * > groupItems;
250 for ( const QgsProviderSublayerDetails &sublayer : std::as_const( sublayers ) )
251 {
252 QgsProviderSublayerItem *item = new QgsProviderSublayerItem( nullptr, sublayer.name(), sublayer, QString() );
253
254 if ( !sublayer.path().isEmpty() )
255 {
256 QStringList currentPath;
257 QStringList remainingPaths = sublayer.path();
258 QgsFileDataCollectionGroupItem *groupItem = nullptr;
259
260 while ( !remainingPaths.empty() )
261 {
262 currentPath << remainingPaths.takeAt( 0 );
263
264 auto it = groupItems.constFind( currentPath );
265 if ( it == groupItems.constEnd() )
266 {
267 QgsFileDataCollectionGroupItem *newGroupItem = new QgsFileDataCollectionGroupItem( this, currentPath.constLast(), path() + '/' + currentPath.join( ',' ) );
269 groupItems.insert( currentPath, newGroupItem );
270 if ( groupItem )
271 groupItem->addChildItem( newGroupItem );
272 else
273 children.append( newGroupItem );
274 groupItem = newGroupItem;
275 }
276 else
277 {
278 groupItem = it.value();
279 }
280
281 if ( groupItem )
282 groupItem->appendSublayer( sublayer );
283 }
284
285 if ( groupItem )
286 groupItem->addChildItem( item );
287 }
288 else
289 {
290 children.append( item );
291 }
292 }
293
294 std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn( databaseConnection() );
295 if ( conn && ( conn->capabilities() & QgsAbstractDatabaseProviderConnection::Capability::ListFieldDomains ) )
296 {
297 QString domainError;
298 QStringList fieldDomains;
299 try
300 {
301 fieldDomains = conn->fieldDomainNames();
302 }
304 {
305 domainError = ex.what();
306 }
307
308 if ( !fieldDomains.empty() || !domainError.isEmpty() )
309 {
310 std::unique_ptr< QgsFieldDomainsItem > domainsItem = std::make_unique< QgsFieldDomainsItem >( this, mPath + "/domains", conn->uri(), QStringLiteral( "ogr" ) );
311 // force this item to appear last by setting a maximum string value for the sort key
312 domainsItem->setSortKey( QString( QChar( 0x10FFFF ) ) );
313 children.append( domainsItem.release() );
314 }
315 }
316 if ( conn && ( conn->capabilities() & QgsAbstractDatabaseProviderConnection::Capability::RetrieveRelationships ) )
317 {
318 QString relationError;
319 QList< QgsWeakRelation > relations;
320 try
321 {
322 relations = conn->relationships();
323 }
325 {
326 relationError = ex.what();
327 }
328
329 if ( !relations.empty() || !relationError.isEmpty() )
330 {
331 std::unique_ptr< QgsRelationshipsItem > relationsItem = std::make_unique< QgsRelationshipsItem >( this, mPath + "/relations", conn->uri(), QStringLiteral( "ogr" ) );
332 // force this item to appear last by setting a maximum string value for the sort key
333 relationsItem->setSortKey( QString( QChar( 0x11FFFF ) ) );
334 children.append( relationsItem.release() );
335 }
336 }
337
338 return children;
339}
340
342{
343 return true;
344}
345
347{
348 QgsMimeDataUtils::Uri collectionUri;
349 collectionUri.uri = path();
350 collectionUri.layerType = QStringLiteral( "collection" );
351 collectionUri.filePath = path();
352 return { collectionUri };
353}
354
356{
357 // test that file is valid with OGR
358 if ( OGRGetDriverCount() == 0 )
359 {
360 OGRRegisterAll();
361 }
362 // do not print errors, but write to debug
363 CPLPushErrorHandler( CPLQuietErrorHandler );
364 CPLErrorReset();
365 GDALDriverH hDriver = GDALIdentifyDriverEx( path().toUtf8().constData(), GDAL_OF_VECTOR, nullptr, nullptr );
366 CPLPopErrorHandler();
367
368 if ( ! hDriver )
369 {
370 QgsDebugMsgLevel( QStringLiteral( "GDALIdentifyDriverEx error # %1 : %2 on %3" ).arg( CPLGetLastErrorNo() ).arg( CPLGetLastErrorMsg() ).arg( path() ), 2 );
371 return nullptr;
372 }
373
374 const QString driverName = GDALGetDriverShortName( hDriver );
375 if ( driverName == QLatin1String( "PDF" ) )
376 {
377 // unwanted drivers -- it's slow to create connections for these, and we don't really want
378 // to expose database capabilities for them (even though they kind of are database formats)
379 return nullptr;
380 }
381
383 if ( driverName == QLatin1String( "SQLite" ) )
384 {
385 // sqlite gets special handling, as we delegate to the native spatialite provider
386 if ( QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "spatialite" ) ) )
387 {
389 uri.setDatabase( path( ) );
390 conn = static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( uri.uri(), {} ) );
391 }
392 }
393 else
394 {
395 // for all other vector types we use the generic OGR provider
396 if ( QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) )
397 {
398 QVariantMap parts;
399 parts.insert( QStringLiteral( "path" ), path() );
400 conn = static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( md->encodeUri( parts ), {} ) );
401 }
402 }
403 return conn;
404}
405
406//
407// QgsFileBasedDataItemProvider
408//
409
411{
412 return QStringLiteral( "files" );
413}
414
416{
418}
419
421{
422 if ( path.isEmpty() )
423 return nullptr;
424
425 const QFileInfo info( path );
426 QString suffix = info.suffix().toLower();
427 const QString name = info.fileName();
428
429 // special handling for some suffixes
430 if ( suffix.compare( QLatin1String( "gpkg" ), Qt::CaseInsensitive ) == 0 )
431 {
432 // Geopackage is special -- it gets a dedicated collection item type
433 QgsGeoPackageCollectionItem *item = new QgsGeoPackageCollectionItem( parentItem, name, path );
434 item->setCapabilities( item->capabilities2() | Qgis::BrowserItemCapability::ItemRepresentsFile );
435 return item;
436 }
437 else if ( suffix == QLatin1String( "txt" ) )
438 {
439 // never ever show .txt files as datasets in browser -- they are only used for geospatial data in extremely rare cases
440 // and are predominantly just noise in the browser
441 return nullptr;
442 }
443 // If a .tab exists, then the corresponding .map/.dat is very likely a
444 // side-car file of the .tab
445 else if ( suffix == QLatin1String( "map" ) || suffix == QLatin1String( "dat" ) )
446 {
447 if ( QFile::exists( QDir( info.path() ).filePath( info.baseName() + ".tab" ) ) || QFile::exists( QDir( info.path() ).filePath( info.baseName() + ".TAB" ) ) )
448 return nullptr;
449 }
450 // .dbf and .shx should only appear if .shp is not present
451 else if ( suffix == QLatin1String( "dbf" ) || suffix == QLatin1String( "shx" ) )
452 {
453 if ( QFile::exists( QDir( info.path() ).filePath( info.baseName() + ".shp" ) ) || QFile::exists( QDir( info.path() ).filePath( info.baseName() + ".SHP" ) ) )
454 return nullptr;
455 }
456 // skip QGIS style xml files
457 else if ( suffix == QLatin1String( "xml" ) && QgsStyle::isXmlStyleFile( path ) )
458 {
459 return nullptr;
460 }
461 // GDAL 3.1 Shapefile driver directly handles .shp.zip files
462 else if ( path.endsWith( QLatin1String( ".shp.zip" ), Qt::CaseInsensitive ) &&
463 GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, nullptr, nullptr ) )
464 {
465 suffix = QStringLiteral( "shp.zip" );
466 }
467 // special handling for mbtiles files
468 else if ( suffix == QLatin1String( "mbtiles" ) )
469 {
470 QgsMbTiles reader( path );
471 if ( reader.open() )
472 {
473 if ( reader.metadataValue( QStringLiteral( "format" ) ) == QLatin1String( "pbf" ) )
474 {
475 // these are vector tiles
476 QUrlQuery uq;
477 uq.addQueryItem( QStringLiteral( "type" ), QStringLiteral( "mbtiles" ) );
478 uq.addQueryItem( QStringLiteral( "url" ), path );
479 const QString encodedUri = uq.toString();
480 QgsVectorTileLayerItem *item = new QgsVectorTileLayerItem( parentItem, name, path, encodedUri );
481 item->setCapabilities( item->capabilities2() | Qgis::BrowserItemCapability::ItemRepresentsFile );
482 return item;
483 }
484 else
485 {
486 // handled by WMS provider
487 QUrlQuery uq;
488 uq.addQueryItem( QStringLiteral( "type" ), QStringLiteral( "mbtiles" ) );
489 uq.addQueryItem( QStringLiteral( "url" ), QUrl::fromLocalFile( path ).toString() );
490 const QString encodedUri = uq.toString();
491 QgsLayerItem *item = new QgsLayerItem( parentItem, name, path, encodedUri, Qgis::BrowserLayerType::Raster, QStringLiteral( "wms" ) );
494 return item;
495 }
496 }
497 }
498
499 // hide blocklisted URIs, such as .aux.xml files
500 if ( QgsProviderRegistry::instance()->uriIsBlocklisted( path ) )
501 return nullptr;
502
503 QgsSettings settings;
504
505 Qgis::SublayerQueryFlags queryFlags = Qgis::SublayerQueryFlags();
506
507 // should we fast scan only?
508 if ( ( settings.value( QStringLiteral( "qgis/scanItemsInBrowser2" ),
509 "extension" ).toString() == QLatin1String( "extension" ) ) ||
510 ( parentItem && settings.value( QStringLiteral( "qgis/scanItemsFastScanUris" ),
511 QStringList() ).toStringList().contains( parentItem->path() ) ) )
512 {
514 }
515
516 const QList<QgsProviderSublayerDetails> sublayers = QgsProviderRegistry::instance()->querySublayers( path, queryFlags );
517
518 if ( sublayers.size() == 1
521 )
522 {
523 QgsProviderSublayerItem *item = new QgsProviderSublayerItem( parentItem, name, sublayers.at( 0 ), path );
525 return item;
526 }
527 else if ( !sublayers.empty() )
528 {
529 QgsFileDataCollectionItem *item = new QgsFileDataCollectionItem( parentItem, name, path, sublayers );
531 return item;
532 }
533 else
534 {
535 return nullptr;
536 }
537}
538
540{
541 QFileInfo info( path );
542 QString suffix = info.suffix().toLower();
543
544 QStringList dirExtensions = QgsOgrProviderUtils::directoryExtensions();
545 return dirExtensions.contains( suffix );
546}
@ NotPopulated
Children not yet created.
@ Populated
Children created.
@ Fertile
Can create children. Even items without this capability may have children, but cannot create them,...
@ RefreshChildrenWhenItemIsRefreshed
When the item is refreshed, all its populated children will also be refreshed in turn (since QGIS 3....
@ ItemRepresentsFile
Item's path() directly represents a file on disk (since QGIS 3.22)
@ Fast
CreateChildren() is fast enough to be run in main thread when refreshing items, most root items (wms,...
@ FastScan
Indicates that the provider must scan for sublayers using the fastest possible approach – e....
@ ResolveGeometryType
Attempt to resolve the geometry type for vector sublayers.
BrowserLayerType
Browser item layer types.
Definition: qgis.h:403
@ Point
Vector point layer.
@ Plugin
Plugin based layer.
@ Line
Vector line layer.
@ Polygon
Vector polygon layer.
@ Vector
Generic vector layer.
@ VectorTile
Vector tile layer.
@ Raster
Raster layer.
@ TableLayer
Vector non-spatial layer.
@ PointCloud
Point cloud layer.
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
A Collection: logical collection of layers or subcollections, e.g.
Base class for all items in the model.
Definition: qgsdataitem.h:46
QString mToolTip
Definition: qgsdataitem.h:456
QString mPath
Definition: qgsdataitem.h:455
QVector< QgsDataItem * > children() const
Definition: qgsdataitem.h:337
Qgis::BrowserItemCapabilities mCapabilities
Definition: qgsdataitem.h:445
QString mIconName
Definition: qgsdataitem.h:457
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:345
QString path() const
Definition: qgsdataitem.h:354
virtual void setState(Qgis::BrowserItemState state)
Set item state.
virtual void setCapabilities(Qgis::BrowserItemCapabilities capabilities)
Sets the capabilities for the data item.
Definition: qgsdataitem.h:310
virtual void addChildItem(QgsDataItem *child, bool refresh=false)
Inserts a new child item.
QgsDataItem * parent() const
Gets item parent.
Definition: qgsdataitem.h:330
virtual Qgis::BrowserItemCapabilities capabilities2() const
Returns the capabilities for the data item.
Definition: qgsdataitem.h:303
Class for storing the component parts of a RDBMS data source URI (e.g.
QString uri(bool expandAuthConfig=true) const
Returns the complete URI as a string.
void setDatabase(const QString &database)
Sets the URI database name.
QString what() const
Definition: qgsexception.h:48
A collection of field items with some internal logic to retrieve the fields and a the vector layer in...
Definition: qgsfieldsitem.h:34
QString name() override
Human-readable name of the provider name.
int capabilities() const override
Returns combination of flags from QgsDataProvider::DataCapabilities.
bool handlesDirectoryPath(const QString &path) override
Returns true if the provider will handle the directory at the specified path.
QgsDataItem * createDataItem(const QString &path, QgsDataItem *parentItem) override
Create a new instance of QgsDataItem (or nullptr) for given path and parent item.
A data collection item for grouping of the content in file based data collections (e....
QgsFileDataCollectionGroupItem(QgsDataItem *parent, const QString &groupName, const QString &path)
Constructor for QgsFileDataCollectionGroupItem.
void appendSublayer(const QgsProviderSublayerDetails &sublayer)
Adds a sublayer to the group.
QgsMimeDataUtils::UriList mimeUris() const override
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
bool hasDragEnabled() const override
Returns true if the item may be dragged.
A data collection item for file based data collections (e.g.
bool hasDragEnabled() const override
Returns true if the item may be dragged.
QVector< QgsDataItem * > createChildren() override
Create children.
QgsMimeDataUtils::UriList mimeUris() const override
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
QgsAbstractDatabaseProviderConnection * databaseConnection() const override
For data items that represent a DB connection or one of its children, this method returns a connectio...
QgsFileDataCollectionItem(QgsDataItem *parent, const QString &name, const QString &path, const QList< QgsProviderSublayerDetails > &sublayers)
Constructor for QgsFileDataCollectionItem.
Item that represents a layer that can be opened with one of the providers.
Definition: qgslayeritem.h:31
Utility class for reading and writing MBTiles files (which are SQLite3 databases).
Definition: qgsmbtiles.h:39
QString metadataValue(const QString &key) const
Requests metadata value for the given key.
Definition: qgsmbtiles.cpp:80
bool open()
Tries to open the file, returns true on success.
Definition: qgsmbtiles.cpp:29
QList< QgsMimeDataUtils::Uri > UriList
Custom exception class for provider connection related exceptions.
Definition: qgsexception.h:101
Holds data provider key, description, and associated shared library file or function pointer informat...
QList< QgsProviderSublayerDetails > querySublayers(const QString &uri, Qgis::SublayerQueryFlags flags=Qgis::SublayerQueryFlags(), QgsFeedback *feedback=nullptr) const
Queries the specified uri and returns a list of any valid sublayers found in the dataset which can be...
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
Contains details about a sub layer available from a dataset.
QStringList path() const
Returns the path to the sublayer.
QgsWkbTypes::Type wkbType() const
Returns the layer's WKB type, or QgsWkbTypes::Unknown if the WKB type is not application or unknown.
QString uri() const
Returns the layer's URI.
QgsMapLayerType type() const
Returns the layer type.
QgsMimeDataUtils::Uri toMimeUri() const
Converts the sublayer details to a QgsMimeDataUtils::Uri representing the sublayer.
QString driverName() const
Returns the layer's driver name.
QString providerKey() const
Returns the associated data provider key.
QString name() const
Returns the layer's name.
A generic data item for file based layers.
QgsAbstractDatabaseProviderConnection * databaseConnection() const override
For data items that represent a DB connection or one of its children, this method returns a connectio...
QVector< QgsDataItem * > createChildren() override
Create children.
QgsProviderSublayerItem(QgsDataItem *parent, const QString &name, const QgsProviderSublayerDetails &details, const QString &filePath)
Constructor for QgsProviderSublayerItem.
QgsProviderSublayerDetails sublayerDetails() const
Returns the sublayer details for the item.
static bool sublayerDetailsAreIncomplete(const QList< QgsProviderSublayerDetails > &details, QgsProviderUtils::SublayerCompletenessFlags flags=QgsProviderUtils::SublayerCompletenessFlags())
Returns true if the sublayer details are incomplete, and require a more in-depth scan.
@ IgnoreUnknownGeometryType
Indicates that an unknown geometry type should not be considered as incomplete.
@ IgnoreUnknownFeatureCount
Indicates that an unknown feature count should not be considered as incomplete.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
static bool isXmlStyleFile(const QString &path)
Tests if the file at path is a QGIS style XML file.
Definition: qgsstyle.cpp:3035
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:968
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
QString qgsVsiPrefix(const QString &path)
Definition: qgis.cpp:192
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QString filePath
Path to file, if uri is associated with a file.
QString uri
Identifier of the data source recognized by its providerKey.
QString layerType
Type of URI.