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