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