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