QGIS API Documentation  2.14.11-Essen
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 <QString>
22 #include <QDir>
23 #include <QLibrary>
24 
25 #include "qgis.h"
26 #include "qgsdataprovider.h"
27 #include "qgslogger.h"
28 #include "qgsmessageoutput.h"
29 #include "qgsmessagelog.h"
30 #include "qgsprovidermetadata.h"
31 #include "qgsvectorlayer.h"
32 #include "qgsmaplayerregistry.h"
33 
34 
35 // typedefs for provider plugin functions of interest
38 typedef bool isprovider_t();
40 typedef void buildsupportedrasterfilefilter_t( QString & theFileFiltersString );
44 //typedef int dataCapabilities_t();
45 //typedef QgsDataItem * dataItem_t(QString);
46 
47 
48 
50 {
51  static QgsProviderRegistry* sInstance( new QgsProviderRegistry( pluginPath ) );
52  return sInstance;
53 } // QgsProviderRegistry::instance
54 
55 
56 
57 QgsProviderRegistry::QgsProviderRegistry( const QString& pluginPath )
58 {
59  // At startup, examine the libs in the qgis/lib dir and store those that
60  // are a provider shared lib
61  // check all libs in the current plugin directory and get name and descriptions
62  //TODO figure out how to register and identify data source plugin for a specific
63  //TODO layer type
64 #if 0
65  char **argv = qApp->argv();
66  QString appDir = argv[0];
67  int bin = appDir.findRev( "/bin", -1, false );
68  QString baseDir = appDir.left( bin );
69  QString mLibraryDirectory = baseDir + "/lib";
70 #endif
71  mLibraryDirectory = pluginPath;
72  init();
73 }
74 
75 
76 void QgsProviderRegistry::init()
77 {
78  mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
79  mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
80 
81 #if defined(Q_OS_WIN) || defined(__CYGWIN__)
82  mLibraryDirectory.setNameFilters( QStringList( "*.dll" ) );
83 #elif defined(ANDROID)
84  mLibraryDirectory.setNameFilters( QStringList( "*provider.so" ) );
85 #else
86  mLibraryDirectory.setNameFilters( QStringList( "*.so" ) );
87 #endif
88 
89  QgsDebugMsg( QString( "Checking %1 for provider plugins" ).arg( mLibraryDirectory.path() ) );
90 
91  if ( mLibraryDirectory.count() == 0 )
92  {
93  QString msg = QObject::tr( "No QGIS data provider plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() );
94  msg += QObject::tr( "No vector layers can be loaded. Check your QGIS installation" );
95 
97  output->setTitle( QObject::tr( "No Data Providers" ) );
99  output->showMessage();
100  return;
101  }
102 
103  // provider file regex pattern, only files matching the pattern are loaded if the variable is defined
104  QString filePattern = getenv( "QGIS_PROVIDER_FILE" );
105  QRegExp fileRegexp;
106  if ( !filePattern.isEmpty() )
107  {
108  fileRegexp.setPattern( filePattern );
109  }
110 
111  QListIterator<QFileInfo> it( mLibraryDirectory.entryInfoList() );
112  while ( it.hasNext() )
113  {
114  QFileInfo fi( it.next() );
115 
116  if ( !fileRegexp.isEmpty() )
117  {
118  if ( fileRegexp.indexIn( fi.fileName() ) == -1 )
119  {
120  QgsDebugMsg( "provider " + fi.fileName() + " skipped because doesn't match pattern " + filePattern );
121  continue;
122  }
123  }
124 
125  QLibrary myLib( fi.filePath() );
126  if ( !myLib.load() )
127  {
128  QgsDebugMsg( QString( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName(), myLib.errorString() ) );
129  continue;
130  }
131 
132  //MH: Added a further test to detect non-provider plugins linked to provider plugins.
133  //Only pure provider plugins have 'type' not defined
134  isprovider_t *hasType = reinterpret_cast< isprovider_t * >( cast_to_fptr( myLib.resolve( "type" ) ) );
135  if ( hasType )
136  {
137  QgsDebugMsg( QString( "Checking %1: ...invalid (has type method)" ).arg( myLib.fileName() ) );
138  continue;
139  }
140 
141  // get the description and the key for the provider plugin
142  isprovider_t *isProvider = reinterpret_cast< isprovider_t * >( cast_to_fptr( myLib.resolve( "isProvider" ) ) );
143  if ( !isProvider )
144  {
145  QgsDebugMsg( QString( "Checking %1: ...invalid (no isProvider method)" ).arg( myLib.fileName() ) );
146  continue;
147  }
148 
149  // check to see if this is a provider plugin
150  if ( !isProvider() )
151  {
152  QgsDebugMsg( QString( "Checking %1: ...invalid (not a provider)" ).arg( myLib.fileName() ) );
153  continue;
154  }
155 
156  // looks like a provider. get the key and description
157  description_t *pDesc = reinterpret_cast< description_t * >( cast_to_fptr( myLib.resolve( "description" ) ) );
158  if ( !pDesc )
159  {
160  QgsDebugMsg( QString( "Checking %1: ...invalid (no description method)" ).arg( myLib.fileName() ) );
161  continue;
162  }
163 
164  providerkey_t *pKey = reinterpret_cast< providerkey_t * >( cast_to_fptr( myLib.resolve( "providerKey" ) ) );
165  if ( !pKey )
166  {
167  QgsDebugMsg( QString( "Checking %1: ...invalid (no providerKey method)" ).arg( myLib.fileName() ) );
168  continue;
169  }
170 
171  // add this provider to the provider map
172  mProviders[pKey()] = new QgsProviderMetadata( pKey(), pDesc(), myLib.fileName() );
173 
174  // load database drivers
175  databaseDrivers_t *pDatabaseDrivers = reinterpret_cast< databaseDrivers_t * >( cast_to_fptr( myLib.resolve( "databaseDrivers" ) ) );
176  if ( pDatabaseDrivers )
177  {
178  mDatabaseDrivers = pDatabaseDrivers();
179  }
180 
181  // load directory drivers
182  directoryDrivers_t *pDirectoryDrivers = reinterpret_cast< directoryDrivers_t * >( cast_to_fptr( myLib.resolve( "directoryDrivers" ) ) );
183  if ( pDirectoryDrivers )
184  {
185  mDirectoryDrivers = pDirectoryDrivers();
186  }
187 
188  // load protocol drivers
189  protocolDrivers_t *pProtocolDrivers = reinterpret_cast< protocolDrivers_t * >( cast_to_fptr( myLib.resolve( "protocolDrivers" ) ) );
190  if ( pProtocolDrivers )
191  {
192  mProtocolDrivers = pProtocolDrivers();
193  }
194 
195  // now get vector file filters, if any
196  fileVectorFilters_t *pFileVectorFilters = reinterpret_cast< fileVectorFilters_t * >( cast_to_fptr( myLib.resolve( "fileVectorFilters" ) ) );
197  if ( pFileVectorFilters )
198  {
199  QString fileVectorFilters = pFileVectorFilters();
200 
201  if ( !fileVectorFilters.isEmpty() )
202  mVectorFileFilters += fileVectorFilters;
203 
204  QgsDebugMsg( QString( "Checking %1: ...loaded ok (%2 file filters)" ).arg( myLib.fileName() ).arg( fileVectorFilters.split( ";;" ).count() ) );
205  }
206 
207  // now get raster file filters, if any
208  // this replaces deprecated QgsRasterLayer::buildSupportedRasterFileFilter
210  reinterpret_cast< buildsupportedrasterfilefilter_t * >( cast_to_fptr( myLib.resolve( "buildSupportedRasterFileFilter" ) ) );
211  if ( pBuild )
212  {
214  pBuild( fileRasterFilters );
215 
216  QgsDebugMsg( "raster filters: " + fileRasterFilters );
217  if ( !fileRasterFilters.isEmpty() )
218  mRasterFileFilters += fileRasterFilters;
219 
220  QgsDebugMsg( QString( "Checking %1: ...loaded ok (%2 file filters)" ).arg( myLib.fileName() ).arg( fileRasterFilters.split( ";;" ).count() ) );
221  }
222  }
223 } // QgsProviderRegistry ctor
224 
225 
226 // typedef for the unload dataprovider function
228 
229 void QgsProviderRegistry::clean()
230 {
232 
233  Providers::const_iterator it = mProviders.begin();
234 
235  while ( it != mProviders.end() )
236  {
237  QgsDebugMsg( QString( "cleanup:%1" ).arg( it->first ) );
238  QString lib = it->second->library();
239  QLibrary myLib( lib );
240  if ( myLib.isLoaded() )
241  {
242  cleanupProviderFunction_t* cleanupFunc = reinterpret_cast< cleanupProviderFunction_t* >( cast_to_fptr( myLib.resolve( "cleanupProvider" ) ) );
243  if ( cleanupFunc )
244  cleanupFunc();
245  }
246  delete it->second;
247  ++it;
248  }
249 }
250 
252 {
253  clean();
254 }
255 
256 
264 static
266  QString const & providerKey )
267 {
268  QgsProviderRegistry::Providers::const_iterator i =
269  metaData.find( providerKey );
270 
271  if ( i != metaData.end() )
272  {
273  return i->second;
274  }
275 
276  return nullptr;
277 } // findMetadata_
278 
279 
280 
281 QString QgsProviderRegistry::library( QString const & providerKey ) const
282 {
283  QgsProviderMetadata * md = findMetadata_( mProviders, providerKey );
284 
285  if ( md )
286  {
287  return md->library();
288  }
289 
290  return QString();
291 }
292 
293 
295 {
296  Providers::const_iterator it = mProviders.begin();
297 
298  if ( mProviders.empty() )
299  return QObject::tr( "No data provider plugins are available. No vector layers can be loaded" );
300 
301  QString list;
302 
303  if ( asHTML )
304  list += "<ol>";
305 
306  while ( it != mProviders.end() )
307  {
308  if ( asHTML )
309  list += "<li>";
310 
311  list += it->second->description();
312 
313  if ( asHTML )
314  list + "<br></li>";
315  else
316  list += '\n';
317 
318  ++it;
319  }
320 
321  if ( asHTML )
322  list += "</ol>";
323 
324  return list;
325 }
326 
328 {
329  mLibraryDirectory = path;
330  clean();
331  init();
332 }
333 
335 {
336  return mLibraryDirectory;
337 }
338 
339 
340 
341 // typedef for the QgsDataProvider class factory
343 
344 
352 QgsDataProvider *QgsProviderRegistry::provider( QString const & providerKey, QString const & dataSource )
353 {
354  // XXX should I check for and possibly delete any pre-existing providers?
355  // XXX How often will that scenario occur?
356 
357  // load the plugin
358  QString lib = library( providerKey );
359 
360 #ifdef TESTPROVIDERLIB
361  const char *cLib = lib.toUtf8();
362 
363  // test code to help debug provider loading problems
364  // void *handle = dlopen(cLib, RTLD_LAZY);
365  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
366  if ( !handle )
367  {
368  QgsLogger::warning( "Error in dlopen" );
369  }
370  else
371  {
372  QgsDebugMsg( "dlopen suceeded" );
373  dlclose( handle );
374  }
375 
376 #endif
377  // load the data provider
378  QLibrary myLib( lib );
379 
380  QgsDebugMsg( "Library name is " + myLib.fileName() );
381  if ( !myLib.load() )
382  {
383  QgsMessageLog::logMessage( QObject::tr( "Failed to load %1: %2" ).arg( lib, myLib.errorString() ) );
384  return nullptr;
385  }
386 
387  classFactoryFunction_t *classFactory = reinterpret_cast< classFactoryFunction_t * >( cast_to_fptr( myLib.resolve( "classFactory" ) ) );
388  if ( !classFactory )
389  {
390  QgsDebugMsg( QString( "Failed to load %1: no classFactory method" ).arg( lib ) );
391  return nullptr;
392  }
393 
394  QgsDataProvider *dataProvider = classFactory( &dataSource );
395  if ( !dataProvider )
396  {
397  QgsMessageLog::logMessage( QObject::tr( "Unable to instantiate the data provider plugin %1" ).arg( lib ) );
398  myLib.unload();
399  return nullptr;
400  }
401 
402  QgsDebugMsg( QString( "Instantiated the data provider plugin: %1" ).arg( dataProvider->name() ) );
403  return dataProvider;
404 } // QgsProviderRegistry::setDataProvider
405 
406 int QgsProviderRegistry::providerCapabilities( const QString &providerKey ) const
407 {
408  QLibrary *library = providerLibrary( providerKey );
409  if ( !library )
410  {
412  }
413 
414  dataCapabilities_t * dataCapabilities = reinterpret_cast< dataCapabilities_t *>( cast_to_fptr( library->resolve( "dataCapabilities" ) ) );
415  if ( !dataCapabilities )
416  {
418  }
419 
420  return dataCapabilities();
421 }
422 
423 // This should be QWidget, not QDialog
425 
427  QWidget * parent, const Qt::WindowFlags& fl )
428 {
429  selectFactoryFunction_t * selectFactory =
430  reinterpret_cast< selectFactoryFunction_t * >( cast_to_fptr( function( providerKey, "selectWidget" ) ) );
431 
432  if ( !selectFactory )
433  return nullptr;
434 
435  return selectFactory( parent, fl );
436 }
437 
438 #if QT_VERSION >= 0x050000
439 QFunctionPointer QgsProviderRegistry::function( QString const & providerKey,
440  QString const & functionName )
441 {
442  QLibrary myLib( library( providerKey ) );
443 
444  QgsDebugMsg( "Library name is " + myLib.fileName() );
445 
446  if ( myLib.load() )
447  {
448  return myLib.resolve( functionName.toAscii().data() );
449  }
450  else
451  {
452  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
453  return 0;
454  }
455 }
456 #else
457 void *QgsProviderRegistry::function( QString const & providerKey,
458  QString const & functionName )
459 {
460  QLibrary myLib( library( providerKey ) );
461 
462  QgsDebugMsg( "Library name is " + myLib.fileName() );
463 
464  if ( myLib.load() )
465  {
466  return myLib.resolve( functionName.toAscii().data() );
467  }
468  else
469  {
470  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
471  return nullptr;
472  }
473 }
474 #endif
475 
477 {
478  QLibrary *myLib = new QLibrary( library( providerKey ) );
479 
480  QgsDebugMsg( "Library name is " + myLib->fileName() );
481 
482  if ( myLib->load() )
483  return myLib;
484 
485  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
486 
487  delete myLib;
488 
489  return nullptr;
490 }
491 
493 {
494  typedef void registerGui_function( QWidget * parent );
495 
496  Q_FOREACH ( const QString &provider, providerList() )
497  {
498  registerGui_function *registerGui = reinterpret_cast< registerGui_function * >( cast_to_fptr( function( provider, "registerGui" ) ) );
499 
500  if ( !registerGui )
501  continue;
502 
503  registerGui( parent );
504  }
505 }
506 
508 {
509  return mVectorFileFilters;
510 }
511 
513 {
514  return mRasterFileFilters;
515 }
516 
518 {
519  return mDatabaseDrivers;
520 }
521 
523 {
524  return mDirectoryDrivers;
525 }
526 
528 {
529  return mProtocolDrivers;
530 }
531 
533 {
534  QStringList lst;
535  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
536  {
537  lst.append( it->first );
538  }
539  return lst;
540 }
541 
543 {
544  return findMetadata_( mProviders, providerKey );
545 }
static QgsProviderRegistry * instance(const QString &pluginPath=QString::null)
Means of accessing canonical single instance.
QgsDataProvider * classFactoryFunction_t(const QString *)
QString databaseDrivers_t()
virtual QString databaseDrivers() const
Return a string containing the available database drivers.
void cleanupProviderFunction_t()
static QgsProviderMetadata * findMetadata_(QgsProviderRegistry::Providers const &metaData, QString const &providerKey)
Convenience function for finding any existing data providers that match "providerKey".
void setNameFilters(const QStringList &nameFilters)
int findRev(QChar c, int i, bool cs) const
bool isEmpty() const
virtual void setTitle(const QString &title)=0
set title for the messages
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QString library(const QString &providerKey) const
Return path for the library of the provider.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:124
const QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Return metadata of the provider or NULL if not found.
const QDir & libraryDirectory() const
Return library directory where plugins are found.
void registerGuis(QWidget *widget)
QString directoryDrivers_t()
static QgsMessageOutput * createMessageOutput()
function that returns new class derived from QgsMessageOutput (don't forget to delete it then if show...
Abstract base class for spatial data provider implementations.
void removeAllMapLayers()
Remove all registered layers.
virtual ~QgsProviderRegistry()
Virtual dectructor.
bool unload()
void setSorting(QFlags< QDir::SortFlag > sort)
QString tr(const char *sourceText, const char *disambiguation, int n)
QWidget * selectFactoryFunction_t(QWidget *parent, Qt::WindowFlags fl)
virtual QString name() const =0
Return a provider name.
QString description_t()
uint count() const
QStringList providerList() const
Return list of available providers by their keys.
void setPattern(const QString &pattern)
int indexIn(const QString &str, int offset, CaretMode caretMode) const
bool isprovider_t()
void setFilter(QFlags< QDir::Filter > filters)
int count(const T &value) const
void append(const T &value)
QString library() const
This returns the library file name.
QString path() const
QgsDataProvider * provider(const QString &providerKey, const QString &dataSource)
Create an instance of the provider.
QFileInfoList entryInfoList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
bool isEmpty() const
virtual QString protocolDrivers() const
Return a string containing the available protocol drivers.
int providerCapabilities(const QString &providerKey) const
Return the provider capabilities.
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
virtual void setMessage(const QString &message, MessageType msgType)=0
set message, it won't be displayed until
void setLibraryDirectory(const QDir &path)
Set library directory where to search for plugins.
virtual QString directoryDrivers() const
Return a string containing the available directory drivers.
void buildsupportedrasterfilefilter_t(QString &theFileFiltersString)
virtual QString fileRasterFilters() const
Return raster file filter string.
bool load()
QString fileVectorFilters_t()
QString pluginList(bool asHtml=false) const
Return list of provider plugins found.
std::map< QString, QgsProviderMetadata * > Providers
Open the given vector data source.
A registry / canonical manager of data providers.
QLibrary * providerLibrary(const QString &providerKey) const
virtual void showMessage(bool blocking=true)=0
display the message to the user and deletes itself
virtual QString fileVectorFilters() const
Return vector file filter string.
QString providerkey_t()
Holds data provider key, description, and associated shared library file information.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
void * resolve(const char *symbol)
char * data()
QString left(int n) const
void * function(const QString &providerKey, const QString &functionName)
Get pointer to provider function.
typedef WindowFlags
void(*)() cast_to_fptr(void *p)
Definition: qgis.h:258
QString protocolDrivers_t()
Interface for showing messages from QGIS in GUI independent way.
int dataCapabilities_t()
QWidget * selectWidget(const QString &providerKey, QWidget *parent=nullptr, const Qt::WindowFlags &fl=nullptr)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QByteArray toAscii() const
QString errorString() const
QByteArray toUtf8() const