QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsproviderregistry.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsproviderregistry.cpp - Singleton class for
3  registering data providers.
4  -------------------
5  begin : Sat Jan 10 2004
6  copyright : (C) 2004 by Gary E.Sherman
7  email : sherman at mrcc.com
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "qgsproviderregistry.h"
20 
21 #include "qgis.h"
22 #include "qgsdataprovider.h"
23 #include "qgsdataitemprovider.h"
24 #include "qgslogger.h"
25 #include "qgsmessageoutput.h"
26 #include "qgsmessagelog.h"
27 #include "qgsprovidermetadata.h"
28 #include "qgsvectorlayer.h"
30 #include "qgsproject.h"
33 #include "providers/gdal/qgsgdalprovider.h"
34 #include "providers/ogr/qgsogrprovidermetadata.h"
35 #include "providers/ogr/qgsogrprovider.h"
36 #include "providers/meshmemory/qgsmeshmemorydataprovider.h"
37 
38 #ifdef HAVE_EPT
39 #include "providers/ept/qgseptprovider.h"
40 #endif
41 
42 #include "qgsruntimeprofiler.h"
43 #include "qgsfileutils.h"
44 
45 #ifdef HAVE_STATIC_PROVIDERS
46 #include "qgswmsprovider.h"
47 #include "qgswcsprovider.h"
48 #include "qgsdelimitedtextprovider.h"
49 #include "qgsafsprovider.h"
50 #include "qgsamsprovider.h"
51 #ifdef HAVE_SPATIALITE
52 #include "qgsspatialiteprovider.h"
53 #include "qgswfsprovider.h"
54 #include "qgsoapifprovider.h"
55 #include "qgsvirtuallayerprovider.h"
56 #endif
57 #ifdef HAVE_POSTGRESQL
58 #include "qgspostgresprovider.h"
59 #endif
60 #endif
61 
62 #include <QString>
63 #include <QDir>
64 #include <QLibrary>
65 #include <QRegularExpression>
66 
67 static QgsProviderRegistry *sInstance = nullptr;
68 
70 {
71  if ( !sInstance )
72  {
73  static QMutex sMutex;
74  const QMutexLocker locker( &sMutex );
75  if ( !sInstance )
76  {
77  sInstance = new QgsProviderRegistry( pluginPath );
78  }
79  }
80  return sInstance;
81 } // QgsProviderRegistry::instance
82 
83 
92 static
93 QgsProviderMetadata *findMetadata_( const QgsProviderRegistry::Providers &metaData,
94  const QString &providerKey )
95 {
96  // first do case-sensitive match
97  const QgsProviderRegistry::Providers::const_iterator i =
98  metaData.find( providerKey );
99 
100  if ( i != metaData.end() )
101  {
102  return i->second;
103  }
104 
105  // fallback to case-insensitive match
106  for ( auto it = metaData.begin(); it != metaData.end(); ++it )
107  {
108  if ( providerKey.compare( it->first, Qt::CaseInsensitive ) == 0 )
109  return it->second;
110  }
111 
112  return nullptr;
113 }
114 
115 QgsProviderRegistry::QgsProviderRegistry( const QString &pluginPath )
116 {
117  // At startup, examine the libs in the qgis/lib dir and store those that
118  // are a provider shared lib
119  // check all libs in the current plugin directory and get name and descriptions
120  //TODO figure out how to register and identify data source plugin for a specific
121  //TODO layer type
122 #if 0
123  char **argv = qApp->argv();
124  QString appDir = argv[0];
125  int bin = appDir.findRev( "/bin", -1, false );
126  QString baseDir = appDir.left( bin );
127  QString mLibraryDirectory = baseDir + "/lib";
128 #endif
129 
130  const QgsScopedRuntimeProfile profile( QObject::tr( "Initialize data providers" ) );
131  mLibraryDirectory.setPath( pluginPath );
132  init();
133 }
134 
136 class PdalUnusableUriHandlerInterface : public QgsProviderRegistry::UnusableUriHandlerInterface
137 {
138  public:
139  bool matchesUri( const QString &uri ) const override
140  {
141  const QFileInfo fi( uri );
142  if ( fi.suffix().compare( QLatin1String( "las" ), Qt::CaseInsensitive ) == 0 || fi.suffix().compare( QLatin1String( "laz" ), Qt::CaseInsensitive ) == 0 )
143  return true;
144 
145  return false;
146  }
147 
148  QgsProviderRegistry::UnusableUriDetails details( const QString &uri ) const override
149  {
151  QObject::tr( "LAS and LAZ files cannot be opened by this QGIS install." ),
152  QList<QgsMapLayerType>() << QgsMapLayerType::PointCloudLayer );
153 
154 #ifdef Q_OS_WIN
155  res.detailedWarning = QObject::tr( "The installer used to install this version of QGIS does "
156  "not include the PDAL library required for opening LAS and LAZ point clouds. Please "
157  "obtain one of the alternative installers from https://qgis.org which has point "
158  "cloud support enabled." );
159 #else
160  res.detailedWarning = QObject::tr( "This QGIS build does not include the PDAL library dependency required for opening LAS or LAZ point clouds." );
161 #endif
162  return res;
163  }
164 };
166 
167 void QgsProviderRegistry::init()
168 {
169  // add static providers
171  {
172  const QgsScopedRuntimeProfile profile( QObject::tr( "Create memory layer provider" ) );
173  mProviders[ QgsMemoryProvider::providerKey() ] = new QgsProviderMetadata( QgsMemoryProvider::providerKey(), QgsMemoryProvider::providerDescription(), &QgsMemoryProvider::createProvider );
174  }
175  {
176  const QgsScopedRuntimeProfile profile( QObject::tr( "Create mesh memory layer provider" ) );
177  mProviders[ QgsMeshMemoryDataProvider::providerKey() ] = new QgsProviderMetadata( QgsMeshMemoryDataProvider::providerKey(), QgsMeshMemoryDataProvider::providerDescription(), &QgsMeshMemoryDataProvider::createProvider );
178  }
180  {
181  const QgsScopedRuntimeProfile profile( QObject::tr( "Create GDAL provider" ) );
182  mProviders[ QgsGdalProvider::providerKey() ] = new QgsGdalProviderMetadata();
183  }
184  {
185  const QgsScopedRuntimeProfile profile( QObject::tr( "Create OGR provider" ) );
186  mProviders[ QgsOgrProvider::providerKey() ] = new QgsOgrProviderMetadata();
187  }
188  {
189  const QgsScopedRuntimeProfile profile( QObject::tr( "Create vector tile provider" ) );
190  QgsProviderMetadata *vt = new QgsVectorTileProviderMetadata();
191  mProviders[ vt->key() ] = vt;
192  }
193 #ifdef HAVE_EPT
194  {
195  const QgsScopedRuntimeProfile profile( QObject::tr( "Create EPT point cloud provider" ) );
196  QgsProviderMetadata *pc = new QgsEptProviderMetadata();
197  mProviders[ pc->key() ] = pc;
198  }
199 #endif
200 
201  registerUnusableUriHandler( new PdalUnusableUriHandlerInterface() );
202 
203 #ifdef HAVE_STATIC_PROVIDERS
204  mProviders[ QgsWmsProvider::providerKey() ] = new QgsWmsProviderMetadata();
205  mProviders[ QgsWcsProvider::providerKey() ] = new QgsWcsProviderMetadata();
206  mProviders[ QgsDelimitedTextProvider::providerKey() ] = new QgsDelimitedTextProviderMetadata();
207  mProviders[ QgsAfsProvider::providerKey() ] = new QgsAfsProviderMetadata();
208  mProviders[ QgsAmsProvider::providerKey() ] = new QgsAmsProviderMetadata();
209 #ifdef HAVE_SPATIALITE
210  mProviders[ QgsSpatiaLiteProvider::providerKey() ] = new QgsSpatiaLiteProviderMetadata();
211  mProviders[ QgsWFSProvider::providerKey() ] = new QgsWfsProviderMetadata();
212  mProviders[ QgsOapifProvider::providerKey() ] = new QgsOapifProviderMetadata();
213  mProviders[ QgsVirtualLayerProvider::providerKey() ] = new QgsVirtualLayerProviderMetadata();
214 #endif
215 #ifdef HAVE_POSTGRESQL
216  mProviders[ QgsPostgresProvider::providerKey() ] = new QgsPostgresProviderMetadata();
217 #endif
218 #endif
219 
220  // add dynamic providers
221 #ifdef HAVE_STATIC_PROVIDERS
222  QgsDebugMsg( QStringLiteral( "Forced only static providers" ) );
223 #else
224  typedef QgsProviderMetadata *factory_function( );
225 
226  mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
227  mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
228 
229 #if defined(Q_OS_WIN) || defined(__CYGWIN__)
230  mLibraryDirectory.setNameFilters( QStringList( "*.dll" ) );
231 #elif defined(ANDROID)
232  mLibraryDirectory.setNameFilters( QStringList( "*provider_*.so" ) );
233 #else
234  mLibraryDirectory.setNameFilters( QStringList( QStringLiteral( "*.so" ) ) );
235 #endif
236 
237  QgsDebugMsgLevel( QStringLiteral( "Checking %1 for provider plugins" ).arg( mLibraryDirectory.path() ), 2 );
238 
239  if ( mLibraryDirectory.count() == 0 )
240  {
241  QgsDebugMsg( QStringLiteral( "No dynamic QGIS data provider plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() ) );
242  }
243 
244  // provider file regex pattern, only files matching the pattern are loaded if the variable is defined
245  const QString filePattern = getenv( "QGIS_PROVIDER_FILE" );
246  QRegularExpression fileRegexp;
247  if ( !filePattern.isEmpty() )
248  {
249  fileRegexp.setPattern( filePattern );
250  }
251 
252  typedef std::vector<QgsProviderMetadata *> *multiple_factory_function();
253 
254  const auto constEntryInfoList = mLibraryDirectory.entryInfoList();
255  for ( const QFileInfo &fi : constEntryInfoList )
256  {
257  if ( !filePattern.isEmpty() )
258  {
259  if ( fi.fileName().indexOf( fileRegexp ) == -1 )
260  {
261  QgsDebugMsg( "provider " + fi.fileName() + " skipped because doesn't match pattern " + filePattern );
262  continue;
263  }
264  }
265 
266  // Always skip authentication methods
267  if ( fi.fileName().contains( QStringLiteral( "authmethod" ), Qt::CaseSensitivity::CaseInsensitive ) )
268  {
269  continue;
270  }
271 
272  const QgsScopedRuntimeProfile profile( QObject::tr( "Load %1" ).arg( fi.fileName() ) );
273  QLibrary myLib( fi.filePath() );
274  if ( !myLib.load() )
275  {
276  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName(), myLib.errorString() ) );
277  continue;
278  }
279 
280  bool libraryLoaded { false };
281  QFunctionPointer func = myLib.resolve( QStringLiteral( "providerMetadataFactory" ).toLatin1().data() );
282  factory_function *function = reinterpret_cast< factory_function * >( cast_to_fptr( func ) );
283  if ( function )
284  {
285  QgsProviderMetadata *meta = function();
286  if ( meta )
287  {
288  if ( findMetadata_( mProviders, meta->key() ) )
289  {
290  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (key %2 already registered)" ).arg( myLib.fileName() ).arg( meta->key() ) );
291  delete meta;
292  continue;
293  }
294  // add this provider to the provider map
295  mProviders[meta->key()] = meta;
296  libraryLoaded = true;
297  }
298  }
299  else
300  {
301  QFunctionPointer multi_func = myLib.resolve( QStringLiteral( "multipleProviderMetadataFactory" ).toLatin1().data() );
302  multiple_factory_function *multi_function = reinterpret_cast< multiple_factory_function * >( cast_to_fptr( multi_func ) );
303  if ( multi_function )
304  {
305  std::vector<QgsProviderMetadata *> *metadatas = multi_function();
306  for ( const auto meta : *metadatas )
307  {
308  if ( findMetadata_( mProviders, meta->key() ) )
309  {
310  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (key %2 already registered)" ).arg( myLib.fileName() ).arg( meta->key() ) );
311  delete meta;
312  continue;
313  }
314  // add this provider to the provider map
315  mProviders[meta->key()] = meta;
316  libraryLoaded = true;
317  }
318  delete metadatas;
319  }
320  }
321 
322  if ( ! libraryLoaded )
323  {
324  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...invalid (no providerMetadataFactory method)" ).arg( myLib.fileName() ), 2 );
325  }
326  }
327 
328 #endif
329  QgsDebugMsg( QStringLiteral( "Loaded %1 providers (%2) " ).arg( mProviders.size() ).arg( providerList().join( ';' ) ) );
330 
331  QStringList pointCloudWildcards;
332  QStringList pointCloudFilters;
333 
334  // now initialize all providers
335  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
336  {
337  const QString &key = it->first;
338 
339  const QgsScopedRuntimeProfile profile( QObject::tr( "Initialize %1" ).arg( key ) );
340 
341  QgsProviderMetadata *meta = it->second;
342 
343  // now get vector file filters, if any
345  if ( !fileVectorFilters.isEmpty() )
346  {
347  mVectorFileFilters += fileVectorFilters;
348  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file filters)" ).arg( key ).arg( fileVectorFilters.split( ";;" ).count() ), 2 );
349  }
350 
351  // now get raster file filters, if any
353  if ( !fileRasterFilters.isEmpty() )
354  {
355  QgsDebugMsgLevel( "raster filters: " + fileRasterFilters, 2 );
356  mRasterFileFilters += fileRasterFilters;
357  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file filters)" ).arg( key ).arg( fileRasterFilters.split( ";;" ).count() ), 2 );
358  }
359 
360  // now get mesh file filters, if any
362  if ( !fileMeshFilters.isEmpty() )
363  {
364  mMeshFileFilters += fileMeshFilters;
365  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file mesh filters)" ).arg( key ).arg( mMeshFileFilters.split( ";;" ).count() ), 2 );
366 
367  }
368 
370  if ( !fileMeshDatasetFilters.isEmpty() )
371  {
372  mMeshDatasetFileFilters += fileMeshDatasetFilters;
373  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file dataset filters)" ).arg( key ).arg( mMeshDatasetFileFilters.split( ";;" ).count() ), 2 );
374  }
375 
376  // now get point cloud file filters, if any
378  if ( !filePointCloudFilters.isEmpty() )
379  {
380  QgsDebugMsgLevel( "point cloud filters: " + filePointCloudFilters, 2 );
381 
382 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
383  const QStringList filters = filePointCloudFilters.split( QStringLiteral( ";;" ), QString::SkipEmptyParts );
384 #else
385  const QStringList filters = filePointCloudFilters.split( QStringLiteral( ";;" ), Qt::SkipEmptyParts );
386 #endif
387  for ( const QString &filter : filters )
388  {
389  pointCloudFilters.append( filter );
390  pointCloudWildcards.append( QgsFileUtils::wildcardsFromFilter( filter ).split( ' ' ) );
391  }
392  }
393 
394  // call initProvider() - allows provider to register its services to QGIS
395  meta->initProvider();
396  }
397 
398  if ( !pointCloudFilters.empty() )
399  {
400  pointCloudFilters.insert( 0, QObject::tr( "All Supported Files" ) + QStringLiteral( " (%1)" ).arg( pointCloudWildcards.join( ' ' ) ) );
401  pointCloudFilters.insert( 1, QObject::tr( "All Files" ) + QStringLiteral( " (*.*)" ) );
402  mPointCloudFileFilters = pointCloudFilters.join( QLatin1String( ";;" ) );
403  }
404 
405  // load database drivers (only OGR)
406  mDatabaseDrivers = QgsOgrProviderUtils::databaseDrivers();
407 
408  // load directory drivers (only OGR)
409  mDirectoryDrivers = QgsOgrProviderUtils::directoryDrivers();
410 
411  // load protocol drivers (only OGR)
412  mProtocolDrivers = QgsOgrProviderUtils::protocolDrivers();
413 } // QgsProviderRegistry ctor
414 
415 
416 // typedef for the unload dataprovider function
418 
419 void QgsProviderRegistry::clean()
420 {
421  // avoid recreating a new project just to clean it
422  if ( QgsProject::sProject )
424 
425  Providers::const_iterator it = mProviders.begin();
426 
427  while ( it != mProviders.end() )
428  {
429  QgsDebugMsgLevel( QStringLiteral( "cleanup:%1" ).arg( it->first ), 5 );
430  it->second->cleanupProvider();
431  delete it->second;
432  ++it;
433  }
434  mProviders.clear();
435 }
436 
437 bool QgsProviderRegistry::exists()
438 {
439  return static_cast< bool >( sInstance );
440 }
441 
443 {
444  qDeleteAll( mUnusableUriHandlers );
445 
446  clean();
447  if ( sInstance == this )
448  sInstance = nullptr;
449 }
450 
451 QString QgsProviderRegistry::library( QString const &providerKey ) const
452 {
453  QgsProviderMetadata *md = findMetadata_( mProviders, providerKey );
454 
455  if ( md )
456  {
458  return md->library();
460  }
461 
462  return QString();
463 }
464 
465 QString QgsProviderRegistry::pluginList( bool asHTML ) const
466 {
467  Providers::const_iterator it = mProviders.begin();
468 
469  if ( mProviders.empty() )
470  return QObject::tr( "No data provider plugins are available. No vector layers can be loaded" );
471 
472  QString list;
473 
474  if ( asHTML )
475  list += QLatin1String( "<ol>" );
476 
477  while ( it != mProviders.end() )
478  {
479  if ( asHTML )
480  list += QLatin1String( "<li>" );
481 
482  list += it->second->description();
483 
484  if ( asHTML )
485  list += QLatin1String( "<br></li>" );
486  else
487  list += '\n';
488 
489  ++it;
490  }
491 
492  if ( asHTML )
493  list += QLatin1String( "</ol>" );
494 
495  return list;
496 }
497 
499 {
500  mLibraryDirectory = path;
501  clean();
502  init();
503 }
504 
506 {
507  return mLibraryDirectory;
508 }
509 
510 
511 /* Copied from QgsVectorLayer::setDataProvider
512  * TODO: Make it work in the generic environment
513  *
514  * TODO: Is this class really the best place to put a data provider loader?
515  * It seems more sensible to provide the code in one place rather than
516  * in qgsrasterlayer, qgsvectorlayer, serversourceselect, etc.
517  */
518 QgsDataProvider *QgsProviderRegistry::createProvider( QString const &providerKey, QString const &dataSource,
519  const QgsDataProvider::ProviderOptions &options,
520  QgsDataProvider::ReadFlags flags )
521 {
522  // XXX should I check for and possibly delete any pre-existing providers?
523  // XXX How often will that scenario occur?
524 
525  QgsProviderMetadata *metadata = findMetadata_( mProviders, providerKey );
526  if ( !metadata )
527  {
528  QgsMessageLog::logMessage( QObject::tr( "Invalid data provider %1" ).arg( providerKey ) );
529  return nullptr;
530  }
531 
532  return metadata->createProvider( dataSource, options, flags );
533 }
534 
535 int QgsProviderRegistry::providerCapabilities( const QString &providerKey ) const
536 {
537  const QList< QgsDataItemProvider * > itemProviders = dataItemProviders( providerKey );
539  //concat flags
540  for ( const QgsDataItemProvider *itemProvider : itemProviders )
541  {
542  ret = ret | itemProvider->capabilities();
543  }
544  return ret;
545 }
546 
547 QVariantMap QgsProviderRegistry::decodeUri( const QString &providerKey, const QString &uri )
548 {
549  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
550  if ( meta )
551  return meta->decodeUri( uri );
552  else
553  return QVariantMap();
554 }
555 
556 QString QgsProviderRegistry::encodeUri( const QString &providerKey, const QVariantMap &parts )
557 {
558  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
559  if ( meta )
560  return meta->encodeUri( parts );
561  else
562  return QString();
563 }
564 
566  const QString &uri,
567  const QgsFields &fields,
568  QgsWkbTypes::Type wkbType,
569  const QgsCoordinateReferenceSystem &srs,
570  bool overwrite, QMap<int, int> &oldToNewAttrIdxMap,
571  QString &errorMessage,
572  const QMap<QString, QVariant> *options )
573 {
574  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
575  if ( meta )
576  return meta->createEmptyLayer( uri, fields, wkbType, srs, overwrite, oldToNewAttrIdxMap, errorMessage, options );
577  else
578  {
579  errorMessage = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
580  return Qgis::VectorExportResult::ErrorInvalidProvider;
581  }
582 }
583 
584 QgsRasterDataProvider *QgsProviderRegistry::createRasterDataProvider( const QString &providerKey, const QString &uri, const QString &format,
585  int nBands, Qgis::DataType type, int width, int height,
586  double *geoTransform, const QgsCoordinateReferenceSystem &crs,
587  const QStringList &createOptions )
588 {
589  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
590  if ( meta )
591  return meta->createRasterDataProvider( uri, format, nBands, type, width, height, geoTransform, crs, createOptions );
592  else
593  return nullptr;
594 }
595 
596 QList<QPair<QString, QString> > QgsProviderRegistry::pyramidResamplingMethods( const QString &providerKey )
597 {
598  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
599  if ( meta )
600  return meta->pyramidResamplingMethods();
601  else
602  return QList<QPair<QString, QString> >();
603 }
604 
605 QList<QgsDataItemProvider *> QgsProviderRegistry::dataItemProviders( const QString &providerKey ) const
606 {
607  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
608  if ( meta )
609  return meta->dataItemProviders();
610  else
611  return QList<QgsDataItemProvider *>();
612 }
613 
614 int QgsProviderRegistry::listStyles( const QString &providerKey, const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause )
615 {
616  int res = -1;
617  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
618  if ( meta )
619  {
620  res = meta->listStyles( uri, ids, names, descriptions, errCause );
621  }
622  else
623  {
624  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
625  }
626  return res;
627 }
628 
629 bool QgsProviderRegistry::styleExists( const QString &providerKey, const QString &uri, const QString &styleId, QString &errorCause )
630 {
631  errorCause.clear();
632 
633  if ( QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey ) )
634  {
635  return meta->styleExists( uri, styleId, errorCause );
636  }
637  else
638  {
639  errorCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
640  return false;
641  }
642 }
643 
644 QString QgsProviderRegistry::getStyleById( const QString &providerKey, const QString &uri, const QString &styleId, QString &errCause )
645 {
646  QString ret;
647  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
648  if ( meta )
649  {
650  ret = meta->getStyleById( uri, styleId, errCause );
651  }
652  else
653  {
654  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
655  }
656  return ret;
657 }
658 
659 bool QgsProviderRegistry::deleteStyleById( const QString &providerKey, const QString &uri, const QString &styleId, QString &errCause )
660 {
661  const bool ret( false );
662 
663  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
664  if ( meta )
665  return meta->deleteStyleById( uri, styleId, errCause );
666  else
667  {
668  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
669  }
670  return ret;
671 }
672 
673 bool QgsProviderRegistry::saveStyle( const QString &providerKey, const QString &uri, const QString &qmlStyle,
674  const QString &sldStyle, const QString &styleName, const QString &styleDescription,
675  const QString &uiFileContent, bool useAsDefault, QString &errCause )
676 {
677  bool ret( false );
678  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
679  if ( meta )
680  ret = meta->saveStyle( uri, qmlStyle, sldStyle, styleName, styleDescription,
681  uiFileContent, useAsDefault, errCause );
682  else
683  {
684  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
685  }
686  return ret;
687 }
688 
689 QString QgsProviderRegistry::loadStyle( const QString &providerKey, const QString &uri, QString &errCause )
690 {
691  QString ret;
692  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
693  if ( meta )
694  ret = meta->loadStyle( uri, errCause );
695  else
696  {
697  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
698  }
699  return ret;
700 }
701 
702 bool QgsProviderRegistry::saveLayerMetadata( const QString &providerKey, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage )
703 {
704  errorMessage.clear();
705  if ( QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey ) )
706  return meta->saveLayerMetadata( uri, metadata, errorMessage );
707  else
708  {
709  throw QgsNotSupportedException( QObject::tr( "Unable to load %1 provider" ).arg( providerKey ) );
710  }
711 }
712 
713 bool QgsProviderRegistry::createDb( const QString &providerKey, const QString &dbPath, QString &errCause )
714 {
715  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
716  if ( meta )
717  return meta->createDb( dbPath, errCause );
718  else
719  {
720  errCause = QStringLiteral( "Resolving createDb(...) failed" );
721  return false;
722  }
723 }
724 
725 QgsTransaction *QgsProviderRegistry::createTransaction( const QString &providerKey, const QString &connString )
726 {
727  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
728  if ( meta )
729  return meta->createTransaction( connString );
730  else
731  return nullptr;
732 }
733 
734 QWidget *QgsProviderRegistry::createSelectionWidget( const QString &providerKey,
735  QWidget *parent, Qt::WindowFlags fl, QgsProviderRegistry::WidgetMode widgetMode )
736 {
737  Q_UNUSED( providerKey );
738  Q_UNUSED( parent );
739  Q_UNUSED( fl );
740  Q_UNUSED( widgetMode );
741  QgsDebugMsg( "deprecated call - use QgsGui::sourceSelectProviderRegistry()->createDataSourceWidget() instead" );
742  return nullptr;
743 }
744 
745 QFunctionPointer QgsProviderRegistry::function( QString const &providerKey,
746  QString const &functionName )
747 {
749  const QString lib = library( providerKey );
751  if ( lib.isEmpty() )
752  return nullptr;
753 
754  QLibrary myLib( lib );
755 
756  QgsDebugMsg( "Library name is " + myLib.fileName() );
757 
758  if ( myLib.load() )
759  {
760  return myLib.resolve( functionName.toLatin1().data() );
761  }
762  else
763  {
764  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
765  return nullptr;
766  }
767 }
768 
769 QLibrary *QgsProviderRegistry::createProviderLibrary( QString const &providerKey ) const
770 {
772  const QString lib = library( providerKey );
774  if ( lib.isEmpty() )
775  return nullptr;
776 
777  std::unique_ptr< QLibrary > myLib( new QLibrary( lib ) );
778 
779  QgsDebugMsg( "Library name is " + myLib->fileName() );
780 
781  if ( myLib->load() )
782  return myLib.release();
783 
784  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
785 
786  return nullptr;
787 }
788 
790 {
791  QgsDebugMsg( "deprecated - use QgsGui::providerGuiRegistry() instead." );
792 }
793 
795 {
796  if ( providerMetadata )
797  {
798  if ( mProviders.find( providerMetadata->key() ) == mProviders.end() )
799  {
800  mProviders[ providerMetadata->key() ] = providerMetadata;
801  return true;
802  }
803  else
804  {
805  QgsDebugMsgLevel( QStringLiteral( "Cannot register provider metadata: a provider with the same key (%1) was already registered!" ).arg( providerMetadata->key() ), 2 );
806  }
807  }
808  else
809  {
810  QgsDebugMsgLevel( QStringLiteral( "Trying to register a null metadata provider!" ), 2 );
811  }
812  return false;
813 }
814 
816 {
817  return mVectorFileFilters;
818 }
819 
821 {
822  return mRasterFileFilters;
823 }
824 
826 {
827  return mMeshFileFilters;
828 }
829 
831 {
832  return mMeshDatasetFileFilters;
833 }
834 
836 {
837  return mPointCloudFileFilters;
838 }
839 
841 {
842  return mDatabaseDrivers;
843 }
844 
846 {
847  return mDirectoryDrivers;
848 }
849 
851 {
852  return mProtocolDrivers;
853 }
854 
856 {
857  QStringList lst;
858  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
859  {
860  lst.append( it->first );
861  }
862  return lst;
863 }
864 
865 QgsProviderMetadata *QgsProviderRegistry::providerMetadata( const QString &providerKey ) const
866 {
867  return findMetadata_( mProviders, providerKey );
868 }
869 
870 QList<QgsProviderRegistry::ProviderCandidateDetails> QgsProviderRegistry::preferredProvidersForUri( const QString &uri ) const
871 {
872  QList< QgsProviderRegistry::ProviderCandidateDetails > res;
873  int maxPriority = 0;
874  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
875  {
876  if ( !( it->second->capabilities() & QgsProviderMetadata::PriorityForUri ) )
877  continue;
878 
879  const int thisProviderPriority = it->second->priorityForUri( uri );
880  if ( thisProviderPriority == 0 )
881  continue;
882 
883  if ( thisProviderPriority > maxPriority )
884  {
885  res.clear();
886  maxPriority = thisProviderPriority;
887  }
888  if ( thisProviderPriority == maxPriority )
889  {
890  res.append( ProviderCandidateDetails( it->second, it->second->validLayerTypesForUri( uri ) ) );
891  }
892  }
893  return res;
894 }
895 
897 {
898  mUnusableUriHandlers << handler;
899  return true;
900 }
901 
902 bool QgsProviderRegistry::handleUnusableUri( const QString &uri, UnusableUriDetails &details ) const
903 {
904  for ( const QgsProviderRegistry::UnusableUriHandlerInterface *handler : mUnusableUriHandlers )
905  {
906  if ( handler->matchesUri( uri ) )
907  {
908  details = handler->details( uri );
909  return true;
910  }
911  }
912  return false;
913 }
914 
915 bool QgsProviderRegistry::shouldDeferUriForOtherProviders( const QString &uri, const QString &providerKey ) const
916 {
917  const QList< ProviderCandidateDetails > providers = preferredProvidersForUri( uri );
918  if ( providers.empty() )
919  return false;
920 
921  for ( const ProviderCandidateDetails &provider : providers )
922  {
923  if ( provider.metadata()->key() == providerKey )
924  return false;
925  }
926  return true;
927 }
928 
929 bool QgsProviderRegistry::uriIsBlocklisted( const QString &uri ) const
930 {
931  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
932  {
933  if ( it->second->uriIsBlocklisted( uri ) )
934  return true;
935  }
936  return false;
937 }
938 
939 QList<QgsProviderSublayerDetails> QgsProviderRegistry::querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags, QgsFeedback *feedback ) const
940 {
941  // never query sublayers for blocklisted uris
942  if ( uriIsBlocklisted( uri ) )
943  return {};
944 
945  QList<QgsProviderSublayerDetails> res;
946  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
947  {
948  // if we should defer this uri for other providers, do so
949  if ( shouldDeferUriForOtherProviders( uri, it->first ) )
950  continue;
951 
952  res.append( it->second->querySublayers( uri, flags, feedback ) );
953  if ( feedback && feedback->isCanceled() )
954  break;
955  }
956  return res;
957 }
VectorExportResult
Vector layer export result codes.
Definition: qgis.h:361
DataType
Raster data types.
Definition: qgis.h:121
This class represents a coordinate reference system (CRS).
This is the interface for those who want to add custom data items to the browser tree.
Abstract base class for spatial data provider implementations.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Container of fields for a vector layer.
Definition: qgsfields.h:45
static QString wildcardsFromFilter(const QString &filter)
Given a filter string like "GeoTIFF Files (*.tiff *.tif)", extracts the wildcard portion of this filt...
A structured metadata store for a map layer.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Custom exception class which is raised when an operation is not supported.
Definition: qgsexception.h:118
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:470
void removeAllMapLayers()
Removes all registered layers.
Holds data provider key, description, and associated shared library file or function pointer informat...
virtual QgsRasterDataProvider * createRasterDataProvider(const QString &uri, const QString &format, int nBands, Qgis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, const QStringList &createOptions=QStringList())
Creates a new instance of the raster data provider.
@ FilterPointCloud
Point clouds (since QGIS 3.18)
virtual bool deleteStyleById(const QString &uri, const QString &styleId, QString &errCause)
Deletes a layer style defined by styleId.
virtual bool saveStyle(const QString &uri, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause)
Saves a layer style to provider.
virtual QgsDataProvider * createProvider(const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags=QgsDataProvider::ReadFlags())
Class factory to return a pointer to a newly created QgsDataProvider object.
virtual QString filters(FilterType type)
Builds the list of file filter strings (supported formats)
virtual bool saveLayerMetadata(const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage) SIP_THROW(QgsNotSupportedException)
Saves metadata to the layer corresponding to the specified uri.
virtual QString encodeUri(const QVariantMap &parts) const
Reassembles a provider data source URI from its component paths (e.g.
virtual bool styleExists(const QString &uri, const QString &styleId, QString &errorCause)
Returns true if a layer style with the specified styleId exists in the provider defined by uri.
virtual Qgis::VectorExportResult createEmptyLayer(const QString &uri, const QgsFields &fields, QgsWkbTypes::Type wkbType, const QgsCoordinateReferenceSystem &srs, bool overwrite, QMap< int, int > &oldToNewAttrIdxMap, QString &errorMessage, const QMap< QString, QVariant > *options)
Creates new empty vector layer.
QString key() const
This returns the unique key associated with the provider.
virtual QgsTransaction * createTransaction(const QString &connString)
Returns new instance of transaction.
virtual void initProvider()
Initialize the provider.
virtual QString getStyleById(const QString &uri, const QString &styleId, QString &errCause)
Gets a layer style defined by uri.
@ PriorityForUri
Indicates that the metadata can calculate a priority for a URI.
virtual QString loadStyle(const QString &uri, QString &errCause)
Loads a layer style defined by uri.
virtual int listStyles(const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
Lists stored layer styles in the provider defined by uri.
virtual QList< QPair< QString, QString > > pyramidResamplingMethods()
Returns pyramid resampling methods available for provider.
virtual QList< QgsDataItemProvider * > dataItemProviders() const
Returns data item providers.
virtual QVariantMap decodeUri(const QString &uri) const
Breaks a provider data source URI into its component paths (e.g.
Q_DECL_DEPRECATED QString library() const
This returns the library file name.
virtual bool createDb(const QString &dbPath, QString &errCause)
Creates database by the provider on the path.
Contains information pertaining to a candidate provider.
Contains information about unusable URIs which aren't handled by any registered providers.
QString detailedWarning
Contains a longer, user-friendly, translated message advising why the URI is not usable.
An interface used to handle unusable URIs which aren't handled by any registered providers,...
virtual UnusableUriDetails details(const QString &uri) const =0
Returns the details for advising the user why the uri is not usable.
virtual bool matchesUri(const QString &uri) const =0
Returns true if the handle is an unusable URI handler for the specified uri.
A registry / canonical manager of data providers.
QgsDataProvider * createProvider(const QString &providerKey, const QString &dataSource, const QgsDataProvider::ProviderOptions &options=QgsDataProvider::ProviderOptions(), QgsDataProvider::ReadFlags flags=QgsDataProvider::ReadFlags())
Creates a new instance of a provider.
std::map< QString, QgsProviderMetadata * > Providers
Type for data provider metadata associative container.
bool styleExists(const QString &providerKey, const QString &uri, const QString &styleId, QString &errorCause)
Returns true if a layer style with the specified styleId exists in the provider defined by providerKe...
QString loadStyle(const QString &providerKey, const QString &uri, QString &errCause)
Loads a layer style defined by uri.
Q_DECL_DEPRECATED QFunctionPointer function(const QString &providerKey, const QString &functionName)
Gets pointer to provider function.
QString getStyleById(const QString &providerKey, const QString &uri, const QString &styleId, QString &errCause)
Gets a layer style defined by styleId.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
void setLibraryDirectory(const QDir &path)
Sets library directory where to search for plugins.
Qgis::VectorExportResult createEmptyLayer(const QString &providerKey, const QString &uri, const QgsFields &fields, QgsWkbTypes::Type wkbType, const QgsCoordinateReferenceSystem &srs, bool overwrite, QMap< int, int > &oldToNewAttrIdxMap, QString &errorMessage, const QMap< QString, QVariant > *options)
Creates new empty vector layer.
QgsTransaction * createTransaction(const QString &providerKey, const QString &connString)
Returns new instance of transaction.
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...
Q_DECL_DEPRECATED void registerGuis(QWidget *widget)
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
WidgetMode
Different ways a source select dialog can be used.
QString protocolDrivers() const
Returns a string containing the available protocol drivers.
QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProvidersForUri(const QString &uri) const
Returns the details for the preferred provider(s) for opening the specified uri.
Q_DECL_DEPRECATED QString library(const QString &providerKey) const
Returns path for the library of the provider.
QString databaseDrivers() const
Returns a string containing the available database drivers.
QString encodeUri(const QString &providerKey, const QVariantMap &parts)
Reassembles a provider data source URI from its component paths (e.g.
QList< QgsDataItemProvider * > dataItemProviders(const QString &providerKey) const
Returns list of data item providers of the provider.
QgsRasterDataProvider * createRasterDataProvider(const QString &providerKey, const QString &uri, const QString &format, int nBands, Qgis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, const QStringList &createOptions=QStringList())
Creates new instance of raster data provider.
QList< QPair< QString, QString > > pyramidResamplingMethods(const QString &providerKey)
Returns list of raster pyramid resampling methods.
bool uriIsBlocklisted(const QString &uri) const
Returns true if the specified uri is known by any registered provider to be something which should be...
Q_DECL_DEPRECATED QLibrary * createProviderLibrary(const QString &providerKey) const
Returns a new QLibrary for the specified providerKey.
bool handleUnusableUri(const QString &uri, UnusableUriDetails &details) const
Returns true if the specified uri can potentially be handled by QGIS, if additional dependencies or b...
QString fileVectorFilters() const
Returns a file filter string for supported vector files.
QString fileRasterFilters() const
Returns a file filter string for supported raster files.
QString fileMeshFilters() const
Returns a file filter string for supported mesh files.
QString pluginList(bool asHtml=false) const
Returns list of provider plugins found.
Q_DECL_DEPRECATED int providerCapabilities(const QString &providerKey) const
Returns the provider capabilities.
bool shouldDeferUriForOtherProviders(const QString &uri, const QString &providerKey) const
Returns true if the provider with matching providerKey should defer handling of the specified uri to ...
bool deleteStyleById(const QString &providerKey, const QString &uri, const QString &styleId, QString &errCause)
Deletes a layer style defined by styleId.
QStringList providerList() const
Returns list of available providers by their keys.
QString fileMeshDatasetFilters() const
Returns a file filter string for supported mesh dataset files.
QDir libraryDirectory() const
Returns the library directory where plugins are found.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
int listStyles(const QString &providerKey, const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
Lists stored layer styles in the provider defined by providerKey and uri.
bool createDb(const QString &providerKey, const QString &dbPath, QString &errCause)
Creates database by the provider on the path.
bool saveStyle(const QString &providerKey, const QString &uri, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause)
Saves a layer style to provider.
bool registerProvider(QgsProviderMetadata *providerMetadata)
register a new vector data provider from its providerMetadata
QString directoryDrivers() const
Returns a string containing the available directory drivers.
bool saveLayerMetadata(const QString &providerKey, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage) SIP_THROW(QgsNotSupportedException)
Saves metadata to the layer corresponding to the specified uri.
bool registerUnusableUriHandler(UnusableUriHandlerInterface *handler)
Registers an unusable URI handler, used to handle unusable URIs which aren't handled by any registere...
Q_DECL_DEPRECATED QWidget * createSelectionWidget(const QString &providerKey, QWidget *parent=nullptr, Qt::WindowFlags fl=Qt::WindowFlags(), QgsProviderRegistry::WidgetMode widgetMode=QgsProviderRegistry::WidgetMode::None)
Returns a new widget for selecting layers from a provider.
QString filePointCloudFilters() const
Returns a file filter string for supported point clouds.
Base class for raster data providers.
Scoped object for logging of the runtime for a single operation or group of operations.
This class allows including a set of layers in a database-side transaction, provided the layer data p...
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2065
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2064
#define cast_to_fptr(f)
Definition: qgis.h:1463
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void cleanupProviderFunction_t()
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.