QGIS API Documentation  3.27.0-Master (e113457133)
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 #ifdef HAVE_COPC
43 #include "providers/copc/qgscopcprovider.h"
44 #endif
45 
46 #include "qgsruntimeprofiler.h"
47 #include "qgsfileutils.h"
48 
49 #ifdef HAVE_STATIC_PROVIDERS
50 #include "qgswmsprovider.h"
51 #include "qgswcsprovider.h"
52 #include "qgsdelimitedtextprovider.h"
53 #include "qgsafsprovider.h"
54 #include "qgsamsprovider.h"
55 #ifdef HAVE_SPATIALITE
56 #include "qgsspatialiteprovider.h"
57 #include "qgswfsprovider.h"
58 #include "qgsoapifprovider.h"
59 #include "qgsvirtuallayerprovider.h"
60 #endif
61 #ifdef HAVE_POSTGRESQL
62 #include "qgspostgresprovider.h"
63 #endif
64 #endif
65 
66 #include <QString>
67 #include <QDir>
68 #include <QLibrary>
69 #include <QRegularExpression>
70 
71 static QgsProviderRegistry *sInstance = nullptr;
72 
74 {
75  if ( !sInstance )
76  {
77  static QMutex sMutex;
78  const QMutexLocker locker( &sMutex );
79  if ( !sInstance )
80  {
81  sInstance = new QgsProviderRegistry( pluginPath );
82  }
83  }
84  return sInstance;
85 } // QgsProviderRegistry::instance
86 
87 
96 static
97 QgsProviderMetadata *findMetadata_( const QgsProviderRegistry::Providers &metaData,
98  const QString &providerKey )
99 {
100  // first do case-sensitive match
101  const QgsProviderRegistry::Providers::const_iterator i =
102  metaData.find( providerKey );
103 
104  if ( i != metaData.end() )
105  {
106  return i->second;
107  }
108 
109  // fallback to case-insensitive match
110  for ( auto it = metaData.begin(); it != metaData.end(); ++it )
111  {
112  if ( providerKey.compare( it->first, Qt::CaseInsensitive ) == 0 )
113  return it->second;
114  }
115 
116  return nullptr;
117 }
118 
119 QgsProviderRegistry::QgsProviderRegistry( const QString &pluginPath )
120 {
121  // At startup, examine the libs in the qgis/lib dir and store those that
122  // are a provider shared lib
123  // check all libs in the current plugin directory and get name and descriptions
124  //TODO figure out how to register and identify data source plugin for a specific
125  //TODO layer type
126 #if 0
127  char **argv = qApp->argv();
128  QString appDir = argv[0];
129  int bin = appDir.findRev( "/bin", -1, false );
130  QString baseDir = appDir.left( bin );
131  QString mLibraryDirectory = baseDir + "/lib";
132 #endif
133 
134  const QgsScopedRuntimeProfile profile( QObject::tr( "Initialize data providers" ) );
135  mLibraryDirectory.setPath( pluginPath );
136  init();
137 }
138 
140 class PdalUnusableUriHandlerInterface : public QgsProviderRegistry::UnusableUriHandlerInterface
141 {
142  public:
143  bool matchesUri( const QString &uri ) const override
144  {
145  const QFileInfo fi( uri );
146  if ( fi.suffix().compare( QLatin1String( "las" ), Qt::CaseInsensitive ) == 0 || fi.suffix().compare( QLatin1String( "laz" ), Qt::CaseInsensitive ) == 0 )
147  return true;
148 
149  return false;
150  }
151 
152  QgsProviderRegistry::UnusableUriDetails details( const QString &uri ) const override
153  {
155  QObject::tr( "LAS and LAZ files cannot be opened by this QGIS install." ),
156  QList<QgsMapLayerType>() << QgsMapLayerType::PointCloudLayer );
157 
158 #ifdef Q_OS_WIN
159  res.detailedWarning = QObject::tr( "The installer used to install this version of QGIS does "
160  "not include the PDAL library required for opening LAS and LAZ point clouds. Please "
161  "obtain one of the alternative installers from https://qgis.org which has point "
162  "cloud support enabled." );
163 #else
164  res.detailedWarning = QObject::tr( "This QGIS build does not include the PDAL library dependency required for opening LAS or LAZ point clouds." );
165 #endif
166  return res;
167  }
168 };
170 
171 void QgsProviderRegistry::init()
172 {
173  // add static providers
174  {
175  const QgsScopedRuntimeProfile profile( QObject::tr( "Create memory layer provider" ) );
176  mProviders[ QgsMemoryProvider::providerKey() ] = new QgsMemoryProviderMetadata();
177  }
178  {
179  const QgsScopedRuntimeProfile profile( QObject::tr( "Create mesh memory layer provider" ) );
180  mProviders[ QgsMeshMemoryDataProvider::providerKey() ] = new QgsMeshMemoryProviderMetadata();
181  }
182  {
183  const QgsScopedRuntimeProfile profile( QObject::tr( "Create GDAL provider" ) );
184  mProviders[ QgsGdalProvider::providerKey() ] = new QgsGdalProviderMetadata();
185  }
186  {
187  const QgsScopedRuntimeProfile profile( QObject::tr( "Create OGR provider" ) );
188  mProviders[ QgsOgrProvider::providerKey() ] = new QgsOgrProviderMetadata();
189  }
190  {
191  const QgsScopedRuntimeProfile profile( QObject::tr( "Create vector tile provider" ) );
192  QgsProviderMetadata *vt = new QgsVectorTileProviderMetadata();
193  mProviders[ vt->key() ] = vt;
194  }
195 #ifdef HAVE_EPT
196  {
197  const QgsScopedRuntimeProfile profile( QObject::tr( "Create EPT point cloud provider" ) );
198  QgsProviderMetadata *pc = new QgsEptProviderMetadata();
199  mProviders[ pc->key() ] = pc;
200  }
201 #endif
202 #ifdef HAVE_COPC
203  {
204  const QgsScopedRuntimeProfile profile( QObject::tr( "Create COPC point cloud provider" ) );
205  QgsProviderMetadata *pc = new QgsCopcProviderMetadata();
206  mProviders[ pc->key() ] = pc;
207  }
208 #endif
209  registerUnusableUriHandler( new PdalUnusableUriHandlerInterface() );
210 
211 #ifdef HAVE_STATIC_PROVIDERS
212  mProviders[ QgsWmsProvider::providerKey() ] = new QgsWmsProviderMetadata();
213  mProviders[ QgsWcsProvider::providerKey() ] = new QgsWcsProviderMetadata();
214  mProviders[ QgsDelimitedTextProvider::providerKey() ] = new QgsDelimitedTextProviderMetadata();
215  mProviders[ QgsAfsProvider::providerKey() ] = new QgsAfsProviderMetadata();
216  mProviders[ QgsAmsProvider::providerKey() ] = new QgsAmsProviderMetadata();
217 #ifdef HAVE_SPATIALITE
218  mProviders[ QgsSpatiaLiteProvider::providerKey() ] = new QgsSpatiaLiteProviderMetadata();
219  mProviders[ QgsWFSProvider::providerKey() ] = new QgsWfsProviderMetadata();
220  mProviders[ QgsOapifProvider::providerKey() ] = new QgsOapifProviderMetadata();
221  mProviders[ QgsVirtualLayerProvider::providerKey() ] = new QgsVirtualLayerProviderMetadata();
222 #endif
223 #ifdef HAVE_POSTGRESQL
224  mProviders[ QgsPostgresProvider::providerKey() ] = new QgsPostgresProviderMetadata();
225 #endif
226 #endif
227 
228  // add dynamic providers
229 #ifdef HAVE_STATIC_PROVIDERS
230  QgsDebugMsg( QStringLiteral( "Forced only static providers" ) );
231 #else
232  typedef QgsProviderMetadata *factory_function( );
233 
234  mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
235  mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
236 
237 #if defined(Q_OS_WIN) || defined(__CYGWIN__)
238  mLibraryDirectory.setNameFilters( QStringList( "*.dll" ) );
239 #elif defined(ANDROID)
240  mLibraryDirectory.setNameFilters( QStringList( "*provider_*.so" ) );
241 #else
242  mLibraryDirectory.setNameFilters( QStringList( QStringLiteral( "*.so" ) ) );
243 #endif
244 
245  QgsDebugMsgLevel( QStringLiteral( "Checking %1 for provider plugins" ).arg( mLibraryDirectory.path() ), 2 );
246 
247  if ( mLibraryDirectory.count() == 0 )
248  {
249  QgsDebugMsg( QStringLiteral( "No dynamic QGIS data provider plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() ) );
250  }
251 
252  // provider file regex pattern, only files matching the pattern are loaded if the variable is defined
253  const QString filePattern = getenv( "QGIS_PROVIDER_FILE" );
254  QRegularExpression fileRegexp;
255  if ( !filePattern.isEmpty() )
256  {
257  fileRegexp.setPattern( filePattern );
258  }
259 
260  typedef std::vector<QgsProviderMetadata *> *multiple_factory_function();
261 
262  const auto constEntryInfoList = mLibraryDirectory.entryInfoList();
263  for ( const QFileInfo &fi : constEntryInfoList )
264  {
265  if ( !filePattern.isEmpty() )
266  {
267  if ( fi.fileName().indexOf( fileRegexp ) == -1 )
268  {
269  QgsDebugMsg( "provider " + fi.fileName() + " skipped because doesn't match pattern " + filePattern );
270  continue;
271  }
272  }
273 
274  // Always skip authentication methods
275  if ( fi.fileName().contains( QStringLiteral( "authmethod" ), Qt::CaseSensitivity::CaseInsensitive ) )
276  {
277  continue;
278  }
279 
280  const QgsScopedRuntimeProfile profile( QObject::tr( "Load %1" ).arg( fi.fileName() ) );
281  QLibrary myLib( fi.filePath() );
282  if ( !myLib.load() )
283  {
284  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName(), myLib.errorString() ) );
285  continue;
286  }
287 
288  bool libraryLoaded { false };
289  QFunctionPointer func = myLib.resolve( QStringLiteral( "providerMetadataFactory" ).toLatin1().data() );
290  factory_function *function = reinterpret_cast< factory_function * >( cast_to_fptr( func ) );
291  if ( function )
292  {
293  QgsProviderMetadata *meta = function();
294  if ( meta )
295  {
296  if ( findMetadata_( mProviders, meta->key() ) )
297  {
298  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (key %2 already registered)" ).arg( myLib.fileName() ).arg( meta->key() ) );
299  delete meta;
300  continue;
301  }
302  // add this provider to the provider map
303  mProviders[meta->key()] = meta;
304  libraryLoaded = true;
305  }
306  }
307  else
308  {
309  QFunctionPointer multi_func = myLib.resolve( QStringLiteral( "multipleProviderMetadataFactory" ).toLatin1().data() );
310  multiple_factory_function *multi_function = reinterpret_cast< multiple_factory_function * >( cast_to_fptr( multi_func ) );
311  if ( multi_function )
312  {
313  std::vector<QgsProviderMetadata *> *metadatas = multi_function();
314  for ( const auto meta : *metadatas )
315  {
316  if ( findMetadata_( mProviders, meta->key() ) )
317  {
318  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (key %2 already registered)" ).arg( myLib.fileName() ).arg( meta->key() ) );
319  delete meta;
320  continue;
321  }
322  // add this provider to the provider map
323  mProviders[meta->key()] = meta;
324  libraryLoaded = true;
325  }
326  delete metadatas;
327  }
328  }
329 
330  if ( ! libraryLoaded )
331  {
332  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...invalid (no providerMetadataFactory method)" ).arg( myLib.fileName() ), 2 );
333  }
334  }
335 
336 #endif
337  QgsDebugMsg( QStringLiteral( "Loaded %1 providers (%2) " ).arg( mProviders.size() ).arg( providerList().join( ';' ) ) );
338 
339  QStringList pointCloudWildcards;
340  QStringList pointCloudFilters;
341 
342  // now initialize all providers
343  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
344  {
345  const QString &key = it->first;
346 
347  const QgsScopedRuntimeProfile profile( QObject::tr( "Initialize %1" ).arg( key ) );
348 
349  QgsProviderMetadata *meta = it->second;
350 
351  // now get vector file filters, if any
353  if ( !fileVectorFilters.isEmpty() )
354  {
355  mVectorFileFilters += fileVectorFilters;
356  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file filters)" ).arg( key ).arg( fileVectorFilters.split( ";;" ).count() ), 2 );
357  }
358 
359  // now get raster file filters, if any
361  if ( !fileRasterFilters.isEmpty() )
362  {
363  QgsDebugMsgLevel( "raster filters: " + fileRasterFilters, 2 );
364  mRasterFileFilters += fileRasterFilters;
365  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file filters)" ).arg( key ).arg( fileRasterFilters.split( ";;" ).count() ), 2 );
366  }
367 
368  // now get mesh file filters, if any
370  if ( !fileMeshFilters.isEmpty() )
371  {
372  mMeshFileFilters += fileMeshFilters;
373  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file mesh filters)" ).arg( key ).arg( mMeshFileFilters.split( ";;" ).count() ), 2 );
374 
375  }
376 
378  if ( !fileMeshDatasetFilters.isEmpty() )
379  {
380  mMeshDatasetFileFilters += fileMeshDatasetFilters;
381  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...loaded OK (%2 file dataset filters)" ).arg( key ).arg( mMeshDatasetFileFilters.split( ";;" ).count() ), 2 );
382  }
383 
384  // now get point cloud file filters, if any
386  if ( !filePointCloudFilters.isEmpty() )
387  {
388  QgsDebugMsgLevel( "point cloud filters: " + filePointCloudFilters, 2 );
389 
390 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
391  const QStringList filters = filePointCloudFilters.split( QStringLiteral( ";;" ), QString::SkipEmptyParts );
392 #else
393  const QStringList filters = filePointCloudFilters.split( QStringLiteral( ";;" ), Qt::SkipEmptyParts );
394 #endif
395  for ( const QString &filter : filters )
396  {
397  pointCloudFilters.append( filter );
398  pointCloudWildcards.append( QgsFileUtils::wildcardsFromFilter( filter ).split( ' ' ) );
399  }
400  }
401 
402  // call initProvider() - allows provider to register its services to QGIS
403  meta->initProvider();
404  }
405 
406  if ( !pointCloudFilters.empty() )
407  {
408  pointCloudFilters.insert( 0, QObject::tr( "All Supported Files" ) + QStringLiteral( " (%1)" ).arg( pointCloudWildcards.join( ' ' ) ) );
409  pointCloudFilters.insert( 1, QObject::tr( "All Files" ) + QStringLiteral( " (*.*)" ) );
410  mPointCloudFileFilters = pointCloudFilters.join( QLatin1String( ";;" ) );
411  }
412 
413  // load database drivers (only OGR)
414  mDatabaseDrivers = QgsOgrProviderUtils::databaseDrivers();
415 
416  // load directory drivers (only OGR)
417  mDirectoryDrivers = QgsOgrProviderUtils::directoryDrivers();
418 
419  // load protocol drivers (only OGR)
420  mProtocolDrivers = QgsOgrProviderUtils::protocolDrivers();
421 } // QgsProviderRegistry ctor
422 
423 
424 // typedef for the unload dataprovider function
426 
427 void QgsProviderRegistry::clean()
428 {
429  // avoid recreating a new project just to clean it
430  if ( QgsProject::sProject )
432 
433  Providers::const_iterator it = mProviders.begin();
434 
435  while ( it != mProviders.end() )
436  {
437  QgsDebugMsgLevel( QStringLiteral( "cleanup:%1" ).arg( it->first ), 5 );
438  it->second->cleanupProvider();
439  delete it->second;
440  ++it;
441  }
442  mProviders.clear();
443 }
444 
445 bool QgsProviderRegistry::exists()
446 {
447  return static_cast< bool >( sInstance );
448 }
449 
451 {
452  qDeleteAll( mUnusableUriHandlers );
453 
454  clean();
455  if ( sInstance == this )
456  sInstance = nullptr;
457 }
458 
459 QString QgsProviderRegistry::library( QString const &providerKey ) const
460 {
461  QgsProviderMetadata *md = findMetadata_( mProviders, providerKey );
462 
463  if ( md )
464  {
466  return md->library();
468  }
469 
470  return QString();
471 }
472 
473 QString QgsProviderRegistry::pluginList( bool asHTML ) const
474 {
475  Providers::const_iterator it = mProviders.begin();
476 
477  if ( mProviders.empty() )
478  return QObject::tr( "No data provider plugins are available. No vector layers can be loaded" );
479 
480  QString list;
481 
482  if ( asHTML )
483  list += QLatin1String( "<ol>" );
484 
485  while ( it != mProviders.end() )
486  {
487  if ( asHTML )
488  list += QLatin1String( "<li>" );
489 
490  list += it->second->description();
491 
492  if ( asHTML )
493  list += QLatin1String( "<br></li>" );
494  else
495  list += '\n';
496 
497  ++it;
498  }
499 
500  if ( asHTML )
501  list += QLatin1String( "</ol>" );
502 
503  return list;
504 }
505 
507 {
508  mLibraryDirectory = path;
509  clean();
510  init();
511 }
512 
514 {
515  return mLibraryDirectory;
516 }
517 
518 
519 /* Copied from QgsVectorLayer::setDataProvider
520  * TODO: Make it work in the generic environment
521  *
522  * TODO: Is this class really the best place to put a data provider loader?
523  * It seems more sensible to provide the code in one place rather than
524  * in qgsrasterlayer, qgsvectorlayer, serversourceselect, etc.
525  */
526 QgsDataProvider *QgsProviderRegistry::createProvider( QString const &providerKey, QString const &dataSource,
527  const QgsDataProvider::ProviderOptions &options,
528  QgsDataProvider::ReadFlags flags )
529 {
530  // XXX should I check for and possibly delete any pre-existing providers?
531  // XXX How often will that scenario occur?
532 
533  QgsProviderMetadata *metadata = findMetadata_( mProviders, providerKey );
534  if ( !metadata )
535  {
536  QgsMessageLog::logMessage( QObject::tr( "Invalid data provider %1" ).arg( providerKey ) );
537  return nullptr;
538  }
539 
540  return metadata->createProvider( dataSource, options, flags );
541 }
542 
543 int QgsProviderRegistry::providerCapabilities( const QString &providerKey ) const
544 {
545  const QList< QgsDataItemProvider * > itemProviders = dataItemProviders( providerKey );
547  //concat flags
548  for ( const QgsDataItemProvider *itemProvider : itemProviders )
549  {
550  ret = ret | itemProvider->capabilities();
551  }
552  return ret;
553 }
554 
555 QVariantMap QgsProviderRegistry::decodeUri( const QString &providerKey, const QString &uri )
556 {
557  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
558  if ( meta )
559  return meta->decodeUri( uri );
560  else
561  return QVariantMap();
562 }
563 
564 QString QgsProviderRegistry::encodeUri( const QString &providerKey, const QVariantMap &parts )
565 {
566  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
567  if ( meta )
568  return meta->encodeUri( parts );
569  else
570  return QString();
571 }
572 
574  const QString &uri,
575  const QgsFields &fields,
576  QgsWkbTypes::Type wkbType,
577  const QgsCoordinateReferenceSystem &srs,
578  bool overwrite, QMap<int, int> &oldToNewAttrIdxMap,
579  QString &errorMessage,
580  const QMap<QString, QVariant> *options )
581 {
582  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
583  if ( meta )
584  return meta->createEmptyLayer( uri, fields, wkbType, srs, overwrite, oldToNewAttrIdxMap, errorMessage, options );
585  else
586  {
587  errorMessage = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
588  return Qgis::VectorExportResult::ErrorInvalidProvider;
589  }
590 }
591 
592 QgsRasterDataProvider *QgsProviderRegistry::createRasterDataProvider( const QString &providerKey, const QString &uri, const QString &format,
593  int nBands, Qgis::DataType type, int width, int height,
594  double *geoTransform, const QgsCoordinateReferenceSystem &crs,
595  const QStringList &createOptions )
596 {
597  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
598  if ( meta )
599  return meta->createRasterDataProvider( uri, format, nBands, type, width, height, geoTransform, crs, createOptions );
600  else
601  return nullptr;
602 }
603 
604 QList<QPair<QString, QString> > QgsProviderRegistry::pyramidResamplingMethods( const QString &providerKey )
605 {
606  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
607  if ( meta )
608  return meta->pyramidResamplingMethods();
609  else
610  return QList<QPair<QString, QString> >();
611 }
612 
613 QList<QgsDataItemProvider *> QgsProviderRegistry::dataItemProviders( const QString &providerKey ) const
614 {
615  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
616  if ( meta )
617  return meta->dataItemProviders();
618  else
619  return QList<QgsDataItemProvider *>();
620 }
621 
622 int QgsProviderRegistry::listStyles( const QString &providerKey, const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause )
623 {
624  int res = -1;
625  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
626  if ( meta )
627  {
628  res = meta->listStyles( uri, ids, names, descriptions, errCause );
629  }
630  else
631  {
632  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
633  }
634  return res;
635 }
636 
637 bool QgsProviderRegistry::styleExists( const QString &providerKey, const QString &uri, const QString &styleId, QString &errorCause )
638 {
639  errorCause.clear();
640 
641  if ( QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey ) )
642  {
643  return meta->styleExists( uri, styleId, errorCause );
644  }
645  else
646  {
647  errorCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
648  return false;
649  }
650 }
651 
652 QString QgsProviderRegistry::getStyleById( const QString &providerKey, const QString &uri, const QString &styleId, QString &errCause )
653 {
654  QString ret;
655  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
656  if ( meta )
657  {
658  ret = meta->getStyleById( uri, styleId, errCause );
659  }
660  else
661  {
662  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
663  }
664  return ret;
665 }
666 
667 bool QgsProviderRegistry::deleteStyleById( const QString &providerKey, const QString &uri, const QString &styleId, QString &errCause )
668 {
669  const bool ret( false );
670 
671  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
672  if ( meta )
673  return meta->deleteStyleById( uri, styleId, errCause );
674  else
675  {
676  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
677  }
678  return ret;
679 }
680 
681 bool QgsProviderRegistry::saveStyle( const QString &providerKey, const QString &uri, const QString &qmlStyle,
682  const QString &sldStyle, const QString &styleName, const QString &styleDescription,
683  const QString &uiFileContent, bool useAsDefault, QString &errCause )
684 {
685  bool ret( false );
686  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
687  if ( meta )
688  ret = meta->saveStyle( uri, qmlStyle, sldStyle, styleName, styleDescription,
689  uiFileContent, useAsDefault, errCause );
690  else
691  {
692  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
693  }
694  return ret;
695 }
696 
697 QString QgsProviderRegistry::loadStyle( const QString &providerKey, const QString &uri, QString &errCause )
698 {
699  QString ret;
700  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
701  if ( meta )
702  ret = meta->loadStyle( uri, errCause );
703  else
704  {
705  errCause = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
706  }
707  return ret;
708 }
709 
710 bool QgsProviderRegistry::saveLayerMetadata( const QString &providerKey, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage )
711 {
712  errorMessage.clear();
713  if ( QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey ) )
714  return meta->saveLayerMetadata( uri, metadata, errorMessage );
715  else
716  {
717  throw QgsNotSupportedException( QObject::tr( "Unable to load %1 provider" ).arg( providerKey ) );
718  }
719 }
720 
721 bool QgsProviderRegistry::createDb( const QString &providerKey, const QString &dbPath, QString &errCause )
722 {
723  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
724  if ( meta )
725  return meta->createDb( dbPath, errCause );
726  else
727  {
728  errCause = QStringLiteral( "Resolving createDb(...) failed" );
729  return false;
730  }
731 }
732 
733 QgsTransaction *QgsProviderRegistry::createTransaction( const QString &providerKey, const QString &connString )
734 {
735  QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
736  if ( meta )
737  return meta->createTransaction( connString );
738  else
739  return nullptr;
740 }
741 
742 QWidget *QgsProviderRegistry::createSelectionWidget( const QString &providerKey,
743  QWidget *parent, Qt::WindowFlags fl, QgsProviderRegistry::WidgetMode widgetMode )
744 {
745  Q_UNUSED( providerKey );
746  Q_UNUSED( parent );
747  Q_UNUSED( fl );
748  Q_UNUSED( widgetMode );
749  QgsDebugMsg( "deprecated call - use QgsGui::sourceSelectProviderRegistry()->createDataSourceWidget() instead" );
750  return nullptr;
751 }
752 
753 QFunctionPointer QgsProviderRegistry::function( QString const &providerKey,
754  QString const &functionName ) const
755 {
757  const QString lib = library( providerKey );
759  if ( lib.isEmpty() )
760  return nullptr;
761 
762  QLibrary myLib( lib );
763 
764  QgsDebugMsg( "Library name is " + myLib.fileName() );
765 
766  if ( myLib.load() )
767  {
768  return myLib.resolve( functionName.toLatin1().data() );
769  }
770  else
771  {
772  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
773  return nullptr;
774  }
775 }
776 
777 QLibrary *QgsProviderRegistry::createProviderLibrary( QString const &providerKey ) const
778 {
780  const QString lib = library( providerKey );
782  if ( lib.isEmpty() )
783  return nullptr;
784 
785  std::unique_ptr< QLibrary > myLib( new QLibrary( lib ) );
786 
787  QgsDebugMsg( "Library name is " + myLib->fileName() );
788 
789  if ( myLib->load() )
790  return myLib.release();
791 
792  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
793 
794  return nullptr;
795 }
796 
798 {
799  QgsDebugMsg( "deprecated - use QgsGui::providerGuiRegistry() instead." );
800 }
801 
803 {
804  if ( providerMetadata )
805  {
806  if ( mProviders.find( providerMetadata->key() ) == mProviders.end() )
807  {
808  mProviders[ providerMetadata->key() ] = providerMetadata;
809  return true;
810  }
811  else
812  {
813  QgsDebugMsgLevel( QStringLiteral( "Cannot register provider metadata: a provider with the same key (%1) was already registered!" ).arg( providerMetadata->key() ), 2 );
814  }
815  }
816  else
817  {
818  QgsDebugMsgLevel( QStringLiteral( "Trying to register a null metadata provider!" ), 2 );
819  }
820  return false;
821 }
822 
824 {
825  return mVectorFileFilters;
826 }
827 
829 {
830  return mRasterFileFilters;
831 }
832 
834 {
835  return mMeshFileFilters;
836 }
837 
839 {
840  return mMeshDatasetFileFilters;
841 }
842 
844 {
845  return mPointCloudFileFilters;
846 }
847 
849 {
850  return mDatabaseDrivers;
851 }
852 
854 {
855  return mDirectoryDrivers;
856 }
857 
859 {
860  return mProtocolDrivers;
861 }
862 
864 {
865  QStringList lst;
866  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
867  {
868  lst.append( it->first );
869  }
870  return lst;
871 }
872 
873 QgsProviderMetadata *QgsProviderRegistry::providerMetadata( const QString &providerKey ) const
874 {
875  return findMetadata_( mProviders, providerKey );
876 }
877 
879 {
880  QSet<QString> lst;
881  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
882  {
883  if ( it->second->supportedLayerTypes().contains( type ) )
884  lst.insert( it->first );
885  }
886  return lst;
887 }
888 
889 QList<QgsProviderRegistry::ProviderCandidateDetails> QgsProviderRegistry::preferredProvidersForUri( const QString &uri ) const
890 {
891  QList< QgsProviderRegistry::ProviderCandidateDetails > res;
892  int maxPriority = 0;
893  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
894  {
895  if ( !( it->second->capabilities() & QgsProviderMetadata::PriorityForUri ) )
896  continue;
897 
898  const int thisProviderPriority = it->second->priorityForUri( uri );
899  if ( thisProviderPriority == 0 )
900  continue;
901 
902  if ( thisProviderPriority > maxPriority )
903  {
904  res.clear();
905  maxPriority = thisProviderPriority;
906  }
907  if ( thisProviderPriority == maxPriority )
908  {
909  res.append( ProviderCandidateDetails( it->second, it->second->validLayerTypesForUri( uri ) ) );
910  }
911  }
912  return res;
913 }
914 
916 {
917  mUnusableUriHandlers << handler;
918  return true;
919 }
920 
921 bool QgsProviderRegistry::handleUnusableUri( const QString &uri, UnusableUriDetails &details ) const
922 {
923  for ( const QgsProviderRegistry::UnusableUriHandlerInterface *handler : mUnusableUriHandlers )
924  {
925  if ( handler->matchesUri( uri ) )
926  {
927  details = handler->details( uri );
928  return true;
929  }
930  }
931  return false;
932 }
933 
934 bool QgsProviderRegistry::shouldDeferUriForOtherProviders( const QString &uri, const QString &providerKey ) const
935 {
936  const QList< ProviderCandidateDetails > providers = preferredProvidersForUri( uri );
937  if ( providers.empty() )
938  return false;
939 
940  for ( const ProviderCandidateDetails &provider : providers )
941  {
942  if ( provider.metadata()->key() == providerKey )
943  return false;
944  }
945  return true;
946 }
947 
948 bool QgsProviderRegistry::uriIsBlocklisted( const QString &uri ) const
949 {
950  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
951  {
952  if ( it->second->uriIsBlocklisted( uri ) )
953  return true;
954  }
955  return false;
956 }
957 
958 QList<QgsProviderSublayerDetails> QgsProviderRegistry::querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags, QgsFeedback *feedback ) const
959 {
960  // never query sublayers for blocklisted uris
961  if ( uriIsBlocklisted( uri ) )
962  return {};
963 
964  QList<QgsProviderSublayerDetails> res;
965  for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
966  {
967  // if we should defer this uri for other providers, do so
968  if ( shouldDeferUriForOtherProviders( uri, it->first ) )
969  continue;
970 
971  res.append( it->second->querySublayers( uri, flags, feedback ) );
972  if ( feedback && feedback->isCanceled() )
973  break;
974  }
975  return res;
976 }
VectorExportResult
Vector layer export result codes.
Definition: qgis.h:450
DataType
Raster data types.
Definition: qgis.h:129
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:479
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.
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)
QSet< QString > providersForLayerType(QgsMapLayerType type) const
Returns a list of the provider keys for available providers which handle the specified layer type.
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
Q_DECL_DEPRECATED QFunctionPointer function(const QString &providerKey, const QString &functionName) const
Gets pointer to provider function.
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
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:47
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2815
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2814
#define cast_to_fptr(f)
Definition: qgis.h:2132
#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.