QGIS API Documentation 4.1.0-Master (60fea48833c)
Loading...
Searching...
No Matches
qgsdataitem.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsdataitem.cpp - Data items
3 -------------------
4 begin : 2011-04-01
5 copyright : (C) 2011 Radim Blazek
6 email : radim dot blazek at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsconfig.h"
19#include "qgsdataitem.h"
20
21#include <mutex>
22
23#include "qgis.h"
24#include "qgsanimatedicon.h"
25#include "qgsapplication.h"
26#include "qgsdataitemprovider.h"
28#include "qgsdataprovider.h"
29#include "qgslogger.h"
30#include "qgsproject.h"
31#include "qgsprovidermetadata.h"
32#include "qgsproviderregistry.h"
33#include "qgssettings.h"
34#include "qgsvectorlayer.h"
35
36#include <QApplication>
37#include <QDateTime>
38#include <QDir>
39#include <QElapsedTimer>
40#include <QFileInfo>
41#include <QMenu>
42#include <QMouseEvent>
43#include <QRegularExpression>
44#include <QString>
45#include <QStyle>
46#include <QTimer>
47#include <QTreeWidget>
48#include <QTreeWidgetItem>
49#include <QVector>
50#include <QtConcurrentRun>
51
52#include "moc_qgsdataitem.cpp"
53
54using namespace Qt::StringLiterals;
55
56// use GDAL VSI mechanism
57#define CPL_SUPRESS_CPLUSPLUS //#spellok
58#include "cpl_vsi.h"
59#include "cpl_string.h"
60
61QgsAnimatedIcon *QgsDataItem::sPopulatingIcon = nullptr;
62
63QgsDataItem::QgsDataItem( Qgis::BrowserItemType type, QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey )
64 // Do not pass parent to QObject, Qt would delete this when parent is deleted
65 : mType( type )
66 , mParent( parent )
67 , mName( name )
69 , mPath( path )
70{}
71
73{
74 QgsDebugMsgLevel( u"mName = %1 mPath = %2 mChildren.size() = %3"_s.arg( mName, mPath ).arg( mChildren.size() ), 2 );
75 const auto constMChildren = mChildren;
76 for ( QgsDataItem *child : constMChildren )
77 {
78 if ( !child ) // should not happen
79 continue;
80 child->deleteLater();
81 }
82 mChildren.clear();
83
84 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
85 {
86 // this should not usually happen (until the item was deleted directly when createChildren was running)
87 QgsDebugError( u"mFutureWatcher not finished (should not happen) -> waitForFinished()"_s );
88 mDeferredDelete = true;
89 mFutureWatcher->waitForFinished();
90 }
91}
92
93QString QgsDataItem::pathComponent( const QString &string )
94{
95 const thread_local QRegularExpression rx( "[\\\\/]" );
96 return QString( string ).replace( rx, u"|"_s );
97}
98
99QVariant QgsDataItem::sortKey() const
100{
101 return mSortKey.isValid() ? mSortKey : name();
102}
103
104void QgsDataItem::setSortKey( const QVariant &key )
105{
106 mSortKey = key;
107}
108
110{
111 QgsDebugMsgLevel( "path = " + path(), 3 );
112 setParent( nullptr ); // also disconnects parent
113 const auto constMChildren = mChildren;
114 for ( QgsDataItem *child : constMChildren )
115 {
116 if ( !child ) // should not happen
117 continue;
118 child->deleteLater();
119 }
120 mChildren.clear();
121
122 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
123 {
124 QgsDebugMsgLevel( u"mFutureWatcher not finished -> schedule to delete later"_s, 2 );
125 mDeferredDelete = true;
126 }
127 else
128 {
129 QObject::deleteLater();
130 }
131}
132
133void QgsDataItem::deleteLater( QVector<QgsDataItem *> &items )
134{
135 const auto constItems = items;
136 for ( QgsDataItem *item : constItems )
137 {
138 if ( !item ) // should not happen
139 continue;
140 item->deleteLater();
141 }
142 items.clear();
143}
144
145void QgsDataItem::moveToThread( QThread *targetThread )
146{
147 // QObject::moveToThread() cannot move objects with parent, but QgsDataItem is not using paren/children from QObject
148 const auto constMChildren = mChildren;
149 for ( QgsDataItem *child : constMChildren )
150 {
151 if ( !child ) // should not happen
152 continue;
153 QgsDebugMsgLevel( "moveToThread child " + child->path(), 3 );
154 child->QObject::setParent( nullptr ); // to be sure
155 child->moveToThread( targetThread );
156 }
157 QObject::moveToThread( targetThread );
158}
159
164
166{
167 if ( state() == Qgis::BrowserItemState::Populating && sPopulatingIcon )
168 return sPopulatingIcon->icon();
169
170 if ( !mIcon.isNull() )
171 return mIcon;
172
173 if ( !mIconMap.contains( mIconName ) )
174 {
175 mIconMap.insert( mIconName, mIconName.startsWith( ':' ) ? QIcon( mIconName ) : QgsApplication::getThemeIcon( mIconName ) );
176 }
177
178 return mIconMap.value( mIconName );
179}
180
181void QgsDataItem::setName( const QString &name )
182{
183 mName = name;
184 emit dataChanged( this );
185}
186
187QVector<QgsDataItem *> QgsDataItem::createChildren()
188{
189 return QVector<QgsDataItem *>();
190}
191
196
197void QgsDataItem::populate( bool foreground )
198{
200 return;
201
202 QgsDebugMsgLevel( "mPath = " + mPath, 2 );
203
204 if ( capabilities2() & Qgis::BrowserItemCapability::Fast || foreground )
205 {
207 }
208 else
209 {
211 // The watcher must not be created with item (in constructor) because the item may be created in thread and the watcher created in thread does not work correctly.
212 if ( !mFutureWatcher )
213 {
214 mFutureWatcher = std::make_unique<QFutureWatcher<QVector<QgsDataItem *> >>( this );
215 }
216
217 connect( mFutureWatcher.get(), &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
218 mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
219 }
220}
221
222// This is expected to be run in a separate thread
223QVector<QgsDataItem *> QgsDataItem::runCreateChildren( QgsDataItem *item )
224{
225 QgsDebugMsgLevel( "path = " + item->path(), 2 );
226 QElapsedTimer time;
227 time.start();
228 const QVector<QgsDataItem *> children = item->createChildren();
229 QgsDebugMsgLevel( u"%1 children created in %2 ms"_s.arg( children.size() ).arg( time.elapsed() ), 3 );
230 // Children objects must be pushed to main thread.
231 for ( QgsDataItem *child : children )
232 {
233 if ( !child ) // should not happen
234 continue;
235 QgsDebugMsgLevel( "moveToThread child " + child->path(), 2 );
236 if ( qApp )
237 child->moveToThread( qApp->thread() ); // moves also children
238 }
239 QgsDebugMsgLevel( u"finished path %1: %2 children"_s.arg( item->path() ).arg( children.size() ), 3 );
240 return children;
241}
242
244{
245 QgsDebugMsgLevel( u"path = %1 children.size() = %2"_s.arg( path() ).arg( mFutureWatcher->result().size() ), 3 );
246
247 if ( deferredDelete() )
248 {
249 QgsDebugMsgLevel( u"Item was scheduled to be deleted later"_s, 2 );
250 QObject::deleteLater();
251 return;
252 }
253
254 if ( mChildren.isEmpty() ) // usually populating but may also be refresh if originally there were no children
255 {
256 populate( mFutureWatcher->result() );
257 }
258 else // refreshing
259 {
260 refresh( mFutureWatcher->result() );
261 }
262 disconnect( mFutureWatcher.get(), &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
263 emit dataChanged( this ); // to replace loading icon by normal icon
264}
265
267{
268 emit dataChanged( this );
269}
270
271void QgsDataItem::populate( const QVector<QgsDataItem *> &children )
272{
273 QgsDebugMsgLevel( "mPath = " + mPath, 3 );
274
275 std::function< void( QgsDataItem *, int ) > setChildAncestorDepthRecursive;
276 setChildAncestorDepthRecursive = [&setChildAncestorDepthRecursive]( QgsDataItem *child, int depth ) {
277 child->mCreatorAncestorDepth = depth;
278 const QVector< QgsDataItem * > children = child->children();
279 for ( QgsDataItem *nextChild : children )
280 {
281 setChildAncestorDepthRecursive( nextChild, depth + 1 );
282 }
283 };
284
285 for ( QgsDataItem *child : children )
286 {
287 if ( !child ) // should not happen
288 continue;
289 setChildAncestorDepthRecursive( child, 1 );
290 // update after thread finished -> refresh
291 addChildItem( child, true );
292 }
294}
295
297{
298 QgsDebugMsgLevel( "mPath = " + mPath, 3 );
299
300 const auto constMChildren = mChildren;
301 for ( QgsDataItem *child : constMChildren )
302 {
303 QgsDebugMsgLevel( "remove " + child->path(), 3 );
304 child->depopulate(); // recursive
305 deleteChildItem( child );
306 }
308}
309
311{
313 return;
314
315 QgsDebugMsgLevel( "mPath = " + mPath, 3 );
316
318 {
320 }
321 else
322 {
324 if ( !mFutureWatcher )
325 {
326 mFutureWatcher = std::make_unique<QFutureWatcher<QVector<QgsDataItem *> >>( this );
327 }
328 connect( mFutureWatcher.get(), &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
329 mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
330 }
331}
332
333void QgsDataItem::refreshConnections( const QString &key )
334{
335 // Walk up until the root node is reached
336 if ( mParent )
337 {
338 mParent->refreshConnections( key );
339 }
340 else
341 {
342 // if a specific key was specified then we use that -- otherwise we assume the connections
343 // changed belong to the same provider as this item
344 emit connectionsChanged( key.isEmpty() ? providerKey() : key );
345 }
346}
347
348void QgsDataItem::refresh( const QVector<QgsDataItem *> &children )
349{
350 QgsDebugMsgLevel( "mPath = " + mPath, 2 );
351
352 // Remove no more present children
353 QVector<QgsDataItem *> remove;
354 const auto constMChildren = mChildren;
355 for ( QgsDataItem *child : constMChildren )
356 {
357 if ( !child ) // should not happen
358 continue;
359 if ( findItem( children, child ) >= 0 )
360 continue;
361 remove.append( child );
362 }
363 const auto constRemove = remove;
364 for ( QgsDataItem *child : constRemove )
365 {
366 QgsDebugMsgLevel( "remove " + child->path(), 3 );
367 deleteChildItem( child );
368 }
369
370 // Add new children
371 for ( QgsDataItem *child : children )
372 {
373 if ( !child ) // should not happen
374 continue;
375
376 const int index = findItem( mChildren, child );
377 if ( index >= 0 )
378 {
379 // Refresh recursively (some providers may create more generations of descendants)
380 if ( !( child->capabilities2() & Qgis::BrowserItemCapability::Fertile ) )
381 {
382 // The child cannot createChildren() itself
383 mChildren.value( index )->refresh( child->children() );
384 }
385 else if ( mChildren.value( index )->state() == Qgis::BrowserItemState::Populated && ( child->capabilities2() & Qgis::BrowserItemCapability::RefreshChildrenWhenItemIsRefreshed ) )
386 {
387 mChildren.value( index )->refresh();
388 }
389
390 child->deleteLater();
391 continue;
392 }
393 addChildItem( child, true );
394 }
396}
397
399{
400 return mProviderKey;
401}
402
403void QgsDataItem::setProviderKey( const QString &value )
404{
405 mProviderKey = value;
406}
407
409{
410 return mChildren.size();
411}
413{
414 return ( state() == Qgis::BrowserItemState::Populated ? !mChildren.isEmpty() : true );
415}
416
418{
419 return false;
420}
421
423{
424 if ( mParent )
425 {
426 disconnect( this, nullptr, mParent, nullptr );
427 }
428 if ( parent )
429 {
436 }
437 mParent = parent;
438}
439
441{
442 Q_ASSERT( child );
443 QgsDebugMsgLevel( u"path = %1 add child #%2 - %3 - %4"_s.arg( mPath ).arg( mChildren.size() ).arg( child->mName ).arg( qgsEnumValueToKey< Qgis::BrowserItemType >( child->mType ) ), 3 );
444
445 //calculate position to insert child
446 int i;
448 {
449 for ( i = 0; i < mChildren.size(); i++ )
450 {
451 // sort items by type, so directories are before data items
452 if ( mChildren.at( i )->mType == child->mType && mChildren.at( i )->mName.localeAwareCompare( child->mName ) > 0 )
453 break;
454 }
455 }
456 else
457 {
458 for ( i = 0; i < mChildren.size(); i++ )
459 {
460 if ( mChildren.at( i )->mName.localeAwareCompare( child->mName ) >= 0 )
461 break;
462 }
463 }
464
465 if ( refresh )
466 emit beginInsertItems( this, i, i );
467
468 mChildren.insert( i, child );
469 child->setParent( this );
470
471 if ( refresh )
472 emit endInsertItems();
473}
474
476{
477 QgsDebugMsgLevel( "mName = " + child->mName, 2 );
478 const int i = mChildren.indexOf( child );
479 Q_ASSERT( i >= 0 );
480 emit beginRemoveItems( this, i, i );
481 mChildren.remove( i );
482 child->deleteLater();
483 emit endRemoveItems();
484}
485
487{
488 QgsDebugMsgLevel( "mName = " + child->mName, 2 );
489 const int i = mChildren.indexOf( child );
490 Q_ASSERT( i >= 0 );
491 if ( i < 0 )
492 {
493 child->setParent( nullptr );
494 return nullptr;
495 }
496
497 emit beginRemoveItems( this, i, i );
498 mChildren.remove( i );
499 emit endRemoveItems();
500 return child;
501}
502
503int QgsDataItem::findItem( QVector<QgsDataItem *> items, QgsDataItem *item )
504{
505 for ( int i = 0; i < items.size(); i++ )
506 {
507 Q_ASSERT_X( items[i], "findItem", u"item %1 is nullptr"_s.arg( i ).toLatin1() );
508 QgsDebugMsgLevel( QString::number( i ) + " : " + items[i]->mPath + " x " + item->mPath, 2 );
509 if ( items[i]->equal( item ) )
510 return i;
511 }
512 return -1;
513}
514
516{
517 if ( depth < 0 )
518 return nullptr;
519
520 QgsDataItem *result = const_cast< QgsDataItem * >( this );
521 while ( result && depth > 0 )
522 {
523 depth--;
524 result = result->parent();
525 }
526 return result;
527}
528
529bool QgsDataItem::equal( const QgsDataItem *other )
530{
531 return ( metaObject()->className() == other->metaObject()->className() && mPath == other->path() );
532}
533
534QList<QAction *> QgsDataItem::actions( QWidget *parent )
535{
536 Q_UNUSED( parent )
537 return QList<QAction *>();
538}
539
541{
542 return false;
543}
544
546{
547 return mimeUris().isEmpty() ? QgsMimeDataUtils::Uri() : mimeUris().constFirst();
548}
549
551{
553 {
555 uri.uri = path();
556 uri.filePath = path();
557 return { uri };
558 }
559
560 return {};
561}
562
564{
565 Q_UNUSED( crs )
566 return false;
567}
568
569bool QgsDataItem::rename( const QString & )
570{
571 return false;
572}
573
574void QgsDataItem::setCapabilities( int capabilities )
575{
576 setCapabilities( static_cast< Qgis::BrowserItemCapabilities >( capabilities ) );
577}
578
583
585{
586 QgsDebugMsgLevel( u"item %1 set state %2 -> %3"_s.arg( path() ).arg( qgsEnumValueToKey< Qgis::BrowserItemState >( this->state() ) ).arg( qgsEnumValueToKey< Qgis::BrowserItemState >( state ) ), 3 );
587 if ( state == mState )
588 return;
589
590 const Qgis::BrowserItemState oldState = mState;
591
592 if ( state == Qgis::BrowserItemState::Populating ) // start loading
593 {
594 if ( !sPopulatingIcon )
595 {
596 // TODO: ensure that QgsAnimatedIcon is created on UI thread only
597 sPopulatingIcon = new QgsAnimatedIcon( QgsApplication::iconPath( u"/mIconLoading.gif"_s ), QgsApplication::instance() );
598 }
599
600 sPopulatingIcon->connectFrameChanged( this, &QgsDataItem::updateIcon );
601 }
602 else if ( mState == Qgis::BrowserItemState::Populating && sPopulatingIcon ) // stop loading
603 {
604 sPopulatingIcon->disconnectFrameChanged( this, &QgsDataItem::updateIcon );
605 }
606
607
608 mState = state;
609
610 emit stateChanged( this, oldState );
612 updateIcon();
613}
614
615QList<QMenu *> QgsDataItem::menus( QWidget *parent )
616{
617 Q_UNUSED( parent )
618 return QList<QMenu *>();
619}
620
621QgsErrorItem::QgsErrorItem( QgsDataItem *parent, const QString &error, const QString &path )
622 : QgsDataItem( Qgis::BrowserItemType::Error, parent, error, path )
623{
624 mIconName = u"/mIconDelete.svg"_s;
625
626 setState( Qgis::BrowserItemState::Populated ); // no more children
627}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
BrowserItemState
Browser item states.
Definition qgis.h:964
@ NotPopulated
Children not yet created.
Definition qgis.h:965
@ Populating
Creating children in separate thread (populating or refreshing).
Definition qgis.h:966
@ Populated
Children created.
Definition qgis.h:967
@ Fertile
Can create children. Even items without this capability may have children, but cannot create them,...
Definition qgis.h:980
@ RefreshChildrenWhenItemIsRefreshed
When the item is refreshed, all its populated children will also be refreshed in turn.
Definition qgis.h:986
@ ItemRepresentsFile
Item's path() directly represents a file on disk.
Definition qgis.h:985
@ Fast
CreateChildren() is fast enough to be run in main thread when refreshing items, most root items (wms,...
Definition qgis.h:981
BrowserItemType
Browser item types.
Definition qgis.h:945
@ Directory
Represents a file directory.
Definition qgis.h:947
QFlags< BrowserItemCapability > BrowserItemCapabilities
Browser item capabilities.
Definition qgis.h:991
Provides common functionality for database based connections.
virtual QIcon icon() const
Returns an icon representing the connection.
Animated icon is keeping an animation running if there are listeners connected to frameChanged.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
Represents a coordinate reference system (CRS).
Base class for all items in the model.
Definition qgsdataitem.h:50
void stateChanged(QgsDataItem *item, Qgis::BrowserItemState oldState)
Emitted when an item's state is changed.
void setSortKey(const QVariant &key)
Sets a custom sorting key for the item.
static int findItem(QVector< QgsDataItem * > items, QgsDataItem *item)
bool hasChildren() const
Returns whether this item has children.
QString mName
Qgis::BrowserItemType mType
virtual QList< QMenu * > menus(QWidget *parent)
Returns the list of menus available for this item.
int rowCount() const
Returns the number of rows of this item.
virtual void deleteChildItem(QgsDataItem *child)
Removes and deletes a child item, emitting relevant signals to the model.
QVector< QgsDataItem * > mChildren
int mCreatorAncestorDepth
Creator ancestor depth.
virtual QVariant sortKey() const
Returns the sorting key for the item.
Qgis::BrowserItemState mState
virtual bool handleDoubleClick()
Called when a user double clicks on the item.
virtual void refresh(const QVector< QgsDataItem * > &children)
Refresh the items from a specified list of child items.
void dataChanged(QgsDataItem *item)
Emitted when data changes for an item.
void setParent(QgsDataItem *parent)
Set item parent and connect / disconnect parent to / from item signals.
int creatorAncestorDepth() const
Returns the hierarchical depth of the item's original creator/source.
static void deleteLater(QVector< QgsDataItem * > &items)
void endRemoveItems()
Emitted after child items have been removed from this data item.
virtual bool layerCollection() const
Returns true if the data item is a collection of layers The default implementation returns false,...
QString mPath
QVector< QgsDataItem * > children() const
void beginRemoveItems(QgsDataItem *parent, int first, int last)
Emitted before child items are removed from this data item.
QgsDataItem * ancestorAtDepth(int depth) const
Returns the ancestor item at the specified depth.
virtual void deleteLater()
Safely delete the item:
virtual QgsAbstractDatabaseProviderConnection * databaseConnection() const
For data items that represent a DB connection or one of its children, this method returns a connectio...
Qgis::BrowserItemType type() const
QgsDataItem(Qgis::BrowserItemType type, QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey=QString())
Constructor for QgsDataItem, with the specified parent item.
QString mIconName
virtual QVector< QgsDataItem * > createChildren()
Create children.
QMap< QString, QIcon > mIconMap
Qgis::BrowserItemState state() const
virtual void childrenCreated()
virtual QgsDataItem * removeChildItem(QgsDataItem *child)
Removes a child item and returns it without deleting it.
static QString pathComponent(const QString &component)
Create path component replacing path separators.
virtual QList< QAction * > actions(QWidget *parent)
Returns the list of actions available for this item.
QVariant mSortKey
Custom sort key. If invalid, name() will be used for sorting instead.
void updateIcon()
Will request a repaint of this icon.
virtual Q_DECL_DEPRECATED bool rename(const QString &name)
Sets a new name for the item, and returns true if the item was successfully renamed.
void connectionsChanged(const QString &providerKey=QString())
Emitted when the connections of the provider with the specified providerKey have changed.
virtual Q_DECL_DEPRECATED QgsMimeDataUtils::Uri mimeUri() const
Returns mime URI for the data item.
QgsDataItem * mParent
QString name() const
Returns the name of the item (the displayed text for the item).
QString path() const
virtual QIcon icon()
virtual void setState(Qgis::BrowserItemState state)
Set item state.
void beginInsertItems(QgsDataItem *parent, int first, int last)
Emitted before child items are added to this data item.
virtual void refreshConnections(const QString &providerKey=QString())
Causes a data item provider to refresh all registered connections.
virtual void setCapabilities(Qgis::BrowserItemCapabilities capabilities)
Sets the capabilities for the data item.
virtual void addChildItem(QgsDataItem *child, bool refresh=false)
Inserts a new child item.
void setName(const QString &name)
Sets the name of the item (the displayed text for the item).
virtual void refresh()
QgsDataItem * parent() const
Gets item parent.
void moveToThread(QThread *targetThread)
Move object and all its descendants to thread.
virtual QgsMimeDataUtils::UriList mimeUris() const
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
QString providerKey() const
Returns the provider key that created this item (e.g.
void endInsertItems()
Emitted after child items have been added to this data item.
virtual Q_DECL_DEPRECATED bool setCrs(const QgsCoordinateReferenceSystem &crs)
Writes the selected crs into data source.
virtual Qgis::BrowserItemCapabilities capabilities2() const
Returns the capabilities for the data item.
~QgsDataItem() override
void setProviderKey(const QString &value)
Sets the provider key that created this item (e.g.
QString mProviderKey
virtual void populate(const QVector< QgsDataItem * > &children)
virtual bool equal(const QgsDataItem *other)
Returns true if this item is equal to another item (by testing item type and path).
virtual void depopulate()
Remove children recursively and set as not populated. This is used when refreshing collapsed items.
bool deferredDelete() const
Returns true if the item is scheduled to be deleted.
QgsErrorItem(QgsDataItem *parent, const QString &error, const QString &path)
QList< QgsMimeDataUtils::Uri > UriList
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7157
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
QString filePath
Path to file, if uri is associated with a file.
QString uri
Identifier of the data source recognized by its providerKey.