QGIS API Documentation 3.99.0-Master (1d785854362)
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}
72
74{
75 QgsDebugMsgLevel( u"mName = %1 mPath = %2 mChildren.size() = %3"_s.arg( mName, mPath ).arg( mChildren.size() ), 2 );
76 const auto constMChildren = mChildren;
77 for ( QgsDataItem *child : constMChildren )
78 {
79 if ( !child ) // should not happen
80 continue;
81 child->deleteLater();
82 }
83 mChildren.clear();
84
85 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
86 {
87 // this should not usually happen (until the item was deleted directly when createChildren was running)
88 QgsDebugError( u"mFutureWatcher not finished (should not happen) -> waitForFinished()"_s );
89 mDeferredDelete = true;
90 mFutureWatcher->waitForFinished();
91 }
92
93
94}
95
96QString QgsDataItem::pathComponent( const QString &string )
97{
98 const thread_local QRegularExpression rx( "[\\\\/]" );
99 return QString( string ).replace( rx, u"|"_s );
100}
101
102QVariant QgsDataItem::sortKey() const
103{
104 return mSortKey.isValid() ? mSortKey : name();
105}
106
107void QgsDataItem::setSortKey( const QVariant &key )
108{
109 mSortKey = key;
110}
111
113{
114 QgsDebugMsgLevel( "path = " + path(), 3 );
115 setParent( nullptr ); // also disconnects parent
116 const auto constMChildren = mChildren;
117 for ( QgsDataItem *child : constMChildren )
118 {
119 if ( !child ) // should not happen
120 continue;
121 child->deleteLater();
122 }
123 mChildren.clear();
124
125 if ( mFutureWatcher && !mFutureWatcher->isFinished() )
126 {
127 QgsDebugMsgLevel( u"mFutureWatcher not finished -> schedule to delete later"_s, 2 );
128 mDeferredDelete = true;
129 }
130 else
131 {
132 QObject::deleteLater();
133 }
134}
135
136void QgsDataItem::deleteLater( QVector<QgsDataItem *> &items )
137{
138 const auto constItems = items;
139 for ( QgsDataItem *item : constItems )
140 {
141 if ( !item ) // should not happen
142 continue;
143 item->deleteLater();
144 }
145 items.clear();
146}
147
148void QgsDataItem::moveToThread( QThread *targetThread )
149{
150 // QObject::moveToThread() cannot move objects with parent, but QgsDataItem is not using paren/children from QObject
151 const auto constMChildren = mChildren;
152 for ( QgsDataItem *child : constMChildren )
153 {
154 if ( !child ) // should not happen
155 continue;
156 QgsDebugMsgLevel( "moveToThread child " + child->path(), 3 );
157 child->QObject::setParent( nullptr ); // to be sure
158 child->moveToThread( targetThread );
159 }
160 QObject::moveToThread( targetThread );
161}
162
167
169{
170 if ( state() == Qgis::BrowserItemState::Populating && sPopulatingIcon )
171 return sPopulatingIcon->icon();
172
173 if ( !mIcon.isNull() )
174 return mIcon;
175
176 if ( !mIconMap.contains( mIconName ) )
177 {
178 mIconMap.insert( mIconName, mIconName.startsWith( ':' ) ? QIcon( mIconName ) : QgsApplication::getThemeIcon( mIconName ) );
179 }
180
181 return mIconMap.value( mIconName );
182}
183
184void QgsDataItem::setName( const QString &name )
185{
186 mName = name;
187 emit dataChanged( this );
188}
189
190QVector<QgsDataItem *> QgsDataItem::createChildren()
191{
192 return QVector<QgsDataItem *>();
193}
194
199
200void QgsDataItem::populate( bool foreground )
201{
203 return;
204
205 QgsDebugMsgLevel( "mPath = " + mPath, 2 );
206
207 if ( capabilities2() & Qgis::BrowserItemCapability::Fast || foreground )
208 {
210 }
211 else
212 {
214 // 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.
215 if ( !mFutureWatcher )
216 {
217 mFutureWatcher = std::make_unique<QFutureWatcher<QVector<QgsDataItem *> >>( this );
218 }
219
220 connect( mFutureWatcher.get(), &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
221 mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
222 }
223}
224
225// This is expected to be run in a separate thread
226QVector<QgsDataItem *> QgsDataItem::runCreateChildren( QgsDataItem *item )
227{
228 QgsDebugMsgLevel( "path = " + item->path(), 2 );
229 QElapsedTimer time;
230 time.start();
231 const QVector <QgsDataItem *> children = item->createChildren();
232 QgsDebugMsgLevel( u"%1 children created in %2 ms"_s.arg( children.size() ).arg( time.elapsed() ), 3 );
233 // Children objects must be pushed to main thread.
234 for ( QgsDataItem *child : children )
235 {
236 if ( !child ) // should not happen
237 continue;
238 QgsDebugMsgLevel( "moveToThread child " + child->path(), 2 );
239 if ( qApp )
240 child->moveToThread( qApp->thread() ); // moves also children
241 }
242 QgsDebugMsgLevel( u"finished path %1: %2 children"_s.arg( item->path() ).arg( children.size() ), 3 );
243 return children;
244}
245
247{
248 QgsDebugMsgLevel( u"path = %1 children.size() = %2"_s.arg( path() ).arg( mFutureWatcher->result().size() ), 3 );
249
250 if ( deferredDelete() )
251 {
252 QgsDebugMsgLevel( u"Item was scheduled to be deleted later"_s, 2 );
253 QObject::deleteLater();
254 return;
255 }
256
257 if ( mChildren.isEmpty() ) // usually populating but may also be refresh if originally there were no children
258 {
259 populate( mFutureWatcher->result() );
260 }
261 else // refreshing
262 {
263 refresh( mFutureWatcher->result() );
264 }
265 disconnect( mFutureWatcher.get(), &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
266 emit dataChanged( this ); // to replace loading icon by normal icon
267}
268
270{
271 emit dataChanged( this );
272}
273
274void QgsDataItem::populate( const QVector<QgsDataItem *> &children )
275{
276 QgsDebugMsgLevel( "mPath = " + mPath, 3 );
277
278 std::function< void( QgsDataItem *, int ) > setChildAncestorDepthRecursive;
279 setChildAncestorDepthRecursive = [&setChildAncestorDepthRecursive]( QgsDataItem * child, int depth )
280 {
281 child->mCreatorAncestorDepth = depth;
282 const QVector< QgsDataItem * > children = child->children();
283 for ( QgsDataItem *nextChild : children )
284 {
285 setChildAncestorDepthRecursive( nextChild, depth + 1 );
286 }
287 };
288
289 for ( QgsDataItem *child : children )
290 {
291 if ( !child ) // should not happen
292 continue;
293 setChildAncestorDepthRecursive( child, 1 );
294 // update after thread finished -> refresh
295 addChildItem( child, true );
296 }
298}
299
301{
302 QgsDebugMsgLevel( "mPath = " + mPath, 3 );
303
304 const auto constMChildren = mChildren;
305 for ( QgsDataItem *child : constMChildren )
306 {
307 QgsDebugMsgLevel( "remove " + child->path(), 3 );
308 child->depopulate(); // recursive
309 deleteChildItem( child );
310 }
312}
313
315{
317 return;
318
319 QgsDebugMsgLevel( "mPath = " + mPath, 3 );
320
322 {
324 }
325 else
326 {
328 if ( !mFutureWatcher )
329 {
330 mFutureWatcher = std::make_unique<QFutureWatcher<QVector<QgsDataItem *> >>( this );
331 }
332 connect( mFutureWatcher.get(), &QFutureWatcherBase::finished, this, &QgsDataItem::childrenCreated );
333 mFutureWatcher->setFuture( QtConcurrent::run( runCreateChildren, this ) );
334 }
335}
336
337void QgsDataItem::refreshConnections( const QString &key )
338{
339 // Walk up until the root node is reached
340 if ( mParent )
341 {
342 mParent->refreshConnections( key );
343 }
344 else
345 {
346 // if a specific key was specified then we use that -- otherwise we assume the connections
347 // changed belong to the same provider as this item
348 emit connectionsChanged( key.isEmpty() ? providerKey() : key );
349 }
350}
351
352void QgsDataItem::refresh( const QVector<QgsDataItem *> &children )
353{
354 QgsDebugMsgLevel( "mPath = " + mPath, 2 );
355
356 // Remove no more present children
357 QVector<QgsDataItem *> remove;
358 const auto constMChildren = mChildren;
359 for ( QgsDataItem *child : constMChildren )
360 {
361 if ( !child ) // should not happen
362 continue;
363 if ( findItem( children, child ) >= 0 )
364 continue;
365 remove.append( child );
366 }
367 const auto constRemove = remove;
368 for ( QgsDataItem *child : constRemove )
369 {
370 QgsDebugMsgLevel( "remove " + child->path(), 3 );
371 deleteChildItem( child );
372 }
373
374 // Add new children
375 for ( QgsDataItem *child : children )
376 {
377 if ( !child ) // should not happen
378 continue;
379
380 const int index = findItem( mChildren, child );
381 if ( index >= 0 )
382 {
383 // Refresh recursively (some providers may create more generations of descendants)
384 if ( !( child->capabilities2() & Qgis::BrowserItemCapability::Fertile ) )
385 {
386 // The child cannot createChildren() itself
387 mChildren.value( index )->refresh( child->children() );
388 }
389 else if ( mChildren.value( index )->state() == Qgis::BrowserItemState::Populated
391 {
392 mChildren.value( index )->refresh();
393 }
394
395 child->deleteLater();
396 continue;
397 }
398 addChildItem( child, true );
399 }
401}
402
404{
405 return mProviderKey;
406}
407
408void QgsDataItem::setProviderKey( const QString &value )
409{
410 mProviderKey = value;
411}
412
414{
415 return mChildren.size();
416}
418{
419 return ( state() == Qgis::BrowserItemState::Populated ? !mChildren.isEmpty() : true );
420}
421
423{
424 return false;
425}
426
428{
429 if ( mParent )
430 {
431 disconnect( this, nullptr, mParent, nullptr );
432 }
433 if ( parent )
434 {
441 }
442 mParent = parent;
443}
444
446{
447 Q_ASSERT( child );
448 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 );
449
450 //calculate position to insert child
451 int i;
453 {
454 for ( i = 0; i < mChildren.size(); i++ )
455 {
456 // sort items by type, so directories are before data items
457 if ( mChildren.at( i )->mType == child->mType &&
458 mChildren.at( i )->mName.localeAwareCompare( child->mName ) > 0 )
459 break;
460 }
461 }
462 else
463 {
464 for ( i = 0; i < mChildren.size(); i++ )
465 {
466 if ( mChildren.at( i )->mName.localeAwareCompare( child->mName ) >= 0 )
467 break;
468 }
469 }
470
471 if ( refresh )
472 emit beginInsertItems( this, i, i );
473
474 mChildren.insert( i, child );
475 child->setParent( this );
476
477 if ( refresh )
478 emit endInsertItems();
479}
480
482{
483 QgsDebugMsgLevel( "mName = " + child->mName, 2 );
484 const int i = mChildren.indexOf( child );
485 Q_ASSERT( i >= 0 );
486 emit beginRemoveItems( this, i, i );
487 mChildren.remove( i );
488 child->deleteLater();
489 emit endRemoveItems();
490}
491
493{
494 QgsDebugMsgLevel( "mName = " + child->mName, 2 );
495 const int i = mChildren.indexOf( child );
496 Q_ASSERT( i >= 0 );
497 if ( i < 0 )
498 {
499 child->setParent( nullptr );
500 return nullptr;
501 }
502
503 emit beginRemoveItems( this, i, i );
504 mChildren.remove( i );
505 emit endRemoveItems();
506 return child;
507}
508
509int QgsDataItem::findItem( QVector<QgsDataItem *> items, QgsDataItem *item )
510{
511 for ( int i = 0; i < items.size(); i++ )
512 {
513 Q_ASSERT_X( items[i], "findItem", u"item %1 is nullptr"_s.arg( i ).toLatin1() );
514 QgsDebugMsgLevel( QString::number( i ) + " : " + items[i]->mPath + " x " + item->mPath, 2 );
515 if ( items[i]->equal( item ) )
516 return i;
517 }
518 return -1;
519}
520
522{
523 if ( depth < 0 )
524 return nullptr;
525
526 QgsDataItem *result = const_cast< QgsDataItem * >( this );
527 while ( result && depth > 0 )
528 {
529 depth--;
530 result = result->parent();
531 }
532 return result;
533}
534
535bool QgsDataItem::equal( const QgsDataItem *other )
536{
537 return ( metaObject()->className() == other->metaObject()->className() &&
538 mPath == other->path() );
539}
540
541QList<QAction *> QgsDataItem::actions( QWidget *parent )
542{
543 Q_UNUSED( parent )
544 return QList<QAction *>();
545}
546
548{
549 return false;
550}
551
553{
554 return mimeUris().isEmpty() ? QgsMimeDataUtils::Uri() : mimeUris().constFirst();
555}
556
558{
560 {
562 uri.uri = path();
563 uri.filePath = path();
564 return { uri };
565 }
566
567 return {};
568}
569
571{
572 Q_UNUSED( crs )
573 return false;
574}
575
576bool QgsDataItem::rename( const QString & )
577{
578 return false;
579}
580
581void QgsDataItem::setCapabilities( int capabilities )
582{
583 setCapabilities( static_cast< Qgis::BrowserItemCapabilities >( capabilities ) );
584}
585
590
592{
593 QgsDebugMsgLevel( u"item %1 set state %2 -> %3"_s.arg( path() ).arg( qgsEnumValueToKey< Qgis::BrowserItemState >( this->state() ) ).arg( qgsEnumValueToKey< Qgis::BrowserItemState >( state ) ), 3 );
594 if ( state == mState )
595 return;
596
597 const Qgis::BrowserItemState oldState = mState;
598
599 if ( state == Qgis::BrowserItemState::Populating ) // start loading
600 {
601 if ( !sPopulatingIcon )
602 {
603 // TODO: ensure that QgsAnimatedIcon is created on UI thread only
604 sPopulatingIcon = new QgsAnimatedIcon( QgsApplication::iconPath( u"/mIconLoading.gif"_s ), QgsApplication::instance() );
605 }
606
607 sPopulatingIcon->connectFrameChanged( this, &QgsDataItem::updateIcon );
608 }
609 else if ( mState == Qgis::BrowserItemState::Populating && sPopulatingIcon ) // stop loading
610 {
611 sPopulatingIcon->disconnectFrameChanged( this, &QgsDataItem::updateIcon );
612 }
613
614
615 mState = state;
616
617 emit stateChanged( this, oldState );
619 updateIcon();
620}
621
622QList<QMenu *> QgsDataItem::menus( QWidget *parent )
623{
624 Q_UNUSED( parent )
625 return QList<QMenu *>();
626}
627
628QgsErrorItem::QgsErrorItem( QgsDataItem *parent, const QString &error, const QString &path )
629 : QgsDataItem( Qgis::BrowserItemType::Error, parent, error, path )
630{
631 mIconName = u"/mIconDelete.svg"_s;
632
633 setState( Qgis::BrowserItemState::Populated ); // no more children
634}
635
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:59
BrowserItemState
Browser item states.
Definition qgis.h:957
@ NotPopulated
Children not yet created.
Definition qgis.h:958
@ Populating
Creating children in separate thread (populating or refreshing).
Definition qgis.h:959
@ Populated
Children created.
Definition qgis.h:960
@ Fertile
Can create children. Even items without this capability may have children, but cannot create them,...
Definition qgis.h:973
@ RefreshChildrenWhenItemIsRefreshed
When the item is refreshed, all its populated children will also be refreshed in turn.
Definition qgis.h:979
@ ItemRepresentsFile
Item's path() directly represents a file on disk.
Definition qgis.h:978
@ Fast
CreateChildren() is fast enough to be run in main thread when refreshing items, most root items (wms,...
Definition qgis.h:974
BrowserItemType
Browser item types.
Definition qgis.h:938
@ Directory
Represents a file directory.
Definition qgis.h:940
QFlags< BrowserItemCapability > BrowserItemCapabilities
Browser item capabilities.
Definition qgis.h:984
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:7126
#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.