QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 QString QgsProviderRegistry::getStyleById( const QString &providerKey, const QString &uri, QString styleId, QString &errCause )
630 {
631  QString ret;
632  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
633  if ( meta )
634  {
635  ret = meta->getStyleById( uri, styleId, errCause );
636  }
637  else
638  {
639  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
640  }
641  return ret;
642 }
643 
644 bool QgsProviderRegistry::deleteStyleById( const QString &providerKey, const QString &uri, QString styleId, QString &errCause )
645 {
646  const bool ret( false );
647 
648  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
649  if ( meta )
650  return meta->deleteStyleById( uri, styleId, errCause );
651  else
652  {
653  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
654  }
655  return ret;
656 }
657 
658 bool QgsProviderRegistry::saveStyle( const QString &providerKey, const QString &uri, const QString &qmlStyle,
659  const QString &sldStyle, const QString &styleName, const QString &styleDescription,
660  const QString &uiFileContent, bool useAsDefault, QString &errCause )
661 {
662  bool ret( false );
663  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
664  if ( meta )
665  ret = meta->saveStyle( uri, qmlStyle, sldStyle, styleName, styleDescription,
666  uiFileContent, useAsDefault, errCause );
667  else
668  {
669  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
670  }
671  return ret;
672 }
673 
674 QString QgsProviderRegistry::loadStyle( const QString &providerKey, const QString &uri, QString &errCause )
675 {
676  QString ret;
677  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
678  if ( meta )
679  ret = meta->loadStyle( uri, errCause );
680  else
681  {
682  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
683  }
684  return ret;
685 }
686 
687 bool QgsProviderRegistry::saveLayerMetadata( const QString &providerKey, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage )
688 {
689  errorMessage.clear();
690  if ( QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey ) )
691  return meta->saveLayerMetadata( uri, metadata, errorMessage );
692  else
693  {
694  throw QgsNotSupportedException( QObject::tr( "Unable to load %1 provider" ).arg( providerKey ) );
695  }
696 }
697 
698 bool QgsProviderRegistry::createDb( const QString &providerKey, const QString &dbPath, QString &errCause )
699 {
700  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
701  if ( meta )
702  return meta->createDb( dbPath, errCause );
703  else
704  {
705  errCause = QStringLiteral( "Resolving createDb(...) failed" );
706  return false;
707  }
708 }
709 
710 QgsTransaction *QgsProviderRegistry::createTransaction( const QString &providerKey, const QString &connString )
711 {
712  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
713  if ( meta )
714  return meta->createTransaction( connString );
715  else
716  return nullptr;
717 }
718 
719 QWidget *QgsProviderRegistry::createSelectionWidget( const QString &providerKey,
720  QWidget *parent, Qt::WindowFlags fl, QgsProviderRegistry::WidgetMode widgetMode )
721 {
722  Q_UNUSED( providerKey );
723  Q_UNUSED( parent );
724  Q_UNUSED( fl );
725  Q_UNUSED( widgetMode );
726  QgsDebugMsg( "deprecated call - use QgsGui::sourceSelectProviderRegistry()->createDataSourceWidget() instead" );
727  return nullptr;
728 }
729 
730 QFunctionPointer QgsProviderRegistry::function( QString const &providerKey,
731  QString const &functionName )
732 {
734  const QString lib = library( providerKey );
736  if ( lib.isEmpty() )
737  return nullptr;
738 
739  QLibrary myLib( lib );
740 
741  QgsDebugMsg( "Library name is " + myLib.fileName() );
742 
743  if ( myLib.load() )
744  {
745  return myLib.resolve( functionName.toLatin1().data() );
746  }
747  else
748  {
749  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
750  return nullptr;
751  }
752 }
753 
754 QLibrary *QgsProviderRegistry::createProviderLibrary( QString const &providerKey ) const
755 {
757  const QString lib = library( providerKey );
759  if ( lib.isEmpty() )
760  return nullptr;
761 
762  std::unique_ptr< QLibrary > myLib( new QLibrary( lib ) );
763 
764  QgsDebugMsg( "Library name is " + myLib->fileName() );
765 
766  if ( myLib->load() )
767  return myLib.release();
768 
769  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
770 
771  return nullptr;
772 }
773 
775 {
776  QgsDebugMsg( "deprecated - use QgsGui::providerGuiRegistry() instead." );
777 }
778 
780 {
781  if ( providerMetadata )
782  {
783  if ( mProviders.find( providerMetadata->key() ) == mProviders.end() )
784  {
785  mProviders[ providerMetadata->key() ] = providerMetadata;
786  return true;
787  }
788  else
789  {
790  QgsDebugMsgLevel( QStringLiteral( "Cannot register provider metadata: a provider with the same key (%1) was already registered!" ).arg( providerMetadata->key() ), 2 );
791  }
792  }
793  else
794  {
795  QgsDebugMsgLevel( QStringLiteral( "Trying to register a null metadata provider!" ), 2 );
796  }
797  return false;
798 }
799 
801 {
802  return mVectorFileFilters;
803 }
804 
806 {
807  return mRasterFileFilters;
808 }
809 
811 {
812  return mMeshFileFilters;
813 }
814 
816 {
817  return mMeshDatasetFileFilters;
818 }
819 
821 {
822  return mPointCloudFileFilters;
823 }
824 
826 {
827  return mDatabaseDrivers;
828 }
829 
831 {
832  return mDirectoryDrivers;
833 }
834 
836 {
837  return mProtocolDrivers;
838 }
839 
841 {
842  QStringList lst;
843  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
844  {
845  lst.append( it->first );
846  }
847  return lst;
848 }
849 
850 QgsProviderMetadata *QgsProviderRegistry::providerMetadata( const QString &providerKey ) const
851 {
852  return findMetadata_( mProviders, providerKey );
853 }
854 
855 QList<QgsProviderRegistry::ProviderCandidateDetails> QgsProviderRegistry::preferredProvidersForUri( const QString &uri ) const
856 {
857  QList< QgsProviderRegistry::ProviderCandidateDetails > res;
858  int maxPriority = 0;
859  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
860  {
861  if ( !( it->second->capabilities() & QgsProviderMetadata::PriorityForUri ) )
862  continue;
863 
864  const int thisProviderPriority = it->second->priorityForUri( uri );
865  if ( thisProviderPriority == 0 )
866  continue;
867 
868  if ( thisProviderPriority > maxPriority )
869  {
870  res.clear();
871  maxPriority = thisProviderPriority;
872  }
873  if ( thisProviderPriority == maxPriority )
874  {
875  res.append( ProviderCandidateDetails( it->second, it->second->validLayerTypesForUri( uri ) ) );
876  }
877  }
878  return res;
879 }
880 
882 {
883  mUnusableUriHandlers << handler;
884  return true;
885 }
886 
887 bool QgsProviderRegistry::handleUnusableUri( const QString &uri, UnusableUriDetails &details ) const
888 {
889  for ( const QgsProviderRegistry::UnusableUriHandlerInterface *handler : mUnusableUriHandlers )
890  {
891  if ( handler->matchesUri( uri ) )
892  {
893  details = handler->details( uri );
894  return true;
895  }
896  }
897  return false;
898 }
899 
900 bool QgsProviderRegistry::shouldDeferUriForOtherProviders( const QString &uri, const QString &providerKey ) const
901 {
902  const QList< ProviderCandidateDetails > providers = preferredProvidersForUri( uri );
903  if ( providers.empty() )
904  return false;
905 
906  for ( const ProviderCandidateDetails &provider : providers )
907  {
908  if ( provider.metadata()->key() == providerKey )
909  return false;
910  }
911  return true;
912 }
913 
914 bool QgsProviderRegistry::uriIsBlocklisted( const QString &uri ) const
915 {
916  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
917  {
918  if ( it->second->uriIsBlocklisted( uri ) )
919  return true;
920  }
921  return false;
922 }
923 
924 QList<QgsProviderSublayerDetails> QgsProviderRegistry::querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags, QgsFeedback *feedback ) const
925 {
926  // never query sublayers for blocklisted uris
927  if ( uriIsBlocklisted( uri ) )
928  return {};
929 
930  QList<QgsProviderSublayerDetails> res;
931  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
932  {
933  // if we should defer this uri for other providers, do so
934  if ( shouldDeferUriForOtherProviders( uri, it->first ) )
935  continue;
936 
937  res.append( it->second->querySublayers( uri, flags, feedback ) );
938  if ( feedback && feedback->isCanceled() )
939  break;
940  }
941  return res;
942 }
VectorExportResult
Vector layer export result codes.
Definition: qgis.h:347
DataType
Raster data types.
Definition: qgis.h:120
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:467
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 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 deleteStyleById(const QString &uri, QString styleId, QString &errCause)
Deletes a layer style defined by styleId.
virtual QString getStyleById(const QString &uri, QString styleId, QString &errCause)
Gets a layer style 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.
@ 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 deleteStyleById(const QString &providerKey, const QString &uri, QString styleId, QString &errCause)
Deletes a layer style defined by styleId.
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.
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 ...
QStringList providerList() const
Returns list of available providers by their keys.
QString getStyleById(const QString &providerKey, const QString &uri, QString styleId, QString &errCause)
Gets a layer style defined by styleId.
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
Added in 3.18.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:1742
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:1741
#define cast_to_fptr(f)
Definition: qgis.h:1131
#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.