QGIS API Documentation  2.11.0-Master
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( 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  mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
73  mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
74 
75 #if defined(Q_OS_WIN) || defined(__CYGWIN__)
76  mLibraryDirectory.setNameFilters( QStringList( "*.dll" ) );
77 #elif ANDROID
78  mLibraryDirectory.setNameFilters( QStringList( "*provider.so" ) );
79 #else
80  mLibraryDirectory.setNameFilters( QStringList( "*.so" ) );
81 #endif
82 
83  QgsDebugMsg( QString( "Checking %1 for provider plugins" ).arg( mLibraryDirectory.path() ) );
84 
85  if ( mLibraryDirectory.count() == 0 )
86  {
87  QString msg = QObject::tr( "No QGIS data provider plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() );
88  msg += QObject::tr( "No vector layers can be loaded. Check your QGIS installation" );
89 
91  output->setTitle( QObject::tr( "No Data Providers" ) );
93  output->showMessage();
94  return;
95  }
96 
97  // provider file regex pattern, only files matching the pattern are loaded if the variable is defined
98  QString filePattern = getenv( "QGIS_PROVIDER_FILE" );
99  QRegExp fileRegexp;
100  if ( !filePattern.isEmpty() )
101  {
102  fileRegexp.setPattern( filePattern );
103  }
104 
105  QListIterator<QFileInfo> it( mLibraryDirectory.entryInfoList() );
106  while ( it.hasNext() )
107  {
108  QFileInfo fi( it.next() );
109 
110  if ( !fileRegexp.isEmpty() )
111  {
112  if ( fileRegexp.indexIn( fi.fileName() ) == -1 )
113  {
114  QgsDebugMsg( "provider " + fi.fileName() + " skipped because doesn't match pattern " + filePattern );
115  continue;
116  }
117  }
118 
119  QLibrary myLib( fi.filePath() );
120  if ( !myLib.load() )
121  {
122  QgsDebugMsg( QString( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName() ).arg( myLib.errorString() ) );
123  continue;
124  }
125 
126  //MH: Added a further test to detect non-provider plugins linked to provider plugins.
127  //Only pure provider plugins have 'type' not defined
128  isprovider_t *hasType = ( isprovider_t * ) cast_to_fptr( myLib.resolve( "type" ) );
129  if ( hasType )
130  {
131  QgsDebugMsg( QString( "Checking %1: ...invalid (has type method)" ).arg( myLib.fileName() ) );
132  continue;
133  }
134 
135  // get the description and the key for the provider plugin
136  isprovider_t *isProvider = ( isprovider_t * ) cast_to_fptr( myLib.resolve( "isProvider" ) );
137  if ( !isProvider )
138  {
139  QgsDebugMsg( QString( "Checking %1: ...invalid (no isProvider method)" ).arg( myLib.fileName() ) );
140  continue;
141  }
142 
143  // check to see if this is a provider plugin
144  if ( !isProvider() )
145  {
146  QgsDebugMsg( QString( "Checking %1: ...invalid (not a provider)" ).arg( myLib.fileName() ) );
147  continue;
148  }
149 
150  // looks like a provider. get the key and description
151  description_t *pDesc = ( description_t * ) cast_to_fptr( myLib.resolve( "description" ) );
152  if ( !pDesc )
153  {
154  QgsDebugMsg( QString( "Checking %1: ...invalid (no description method)" ).arg( myLib.fileName() ) );
155  continue;
156  }
157 
158  providerkey_t *pKey = ( providerkey_t * ) cast_to_fptr( myLib.resolve( "providerKey" ) );
159  if ( !pKey )
160  {
161  QgsDebugMsg( QString( "Checking %1: ...invalid (no providerKey method)" ).arg( myLib.fileName() ) );
162  continue;
163  }
164 
165  // add this provider to the provider map
166  mProviders[pKey()] = new QgsProviderMetadata( pKey(), pDesc(), myLib.fileName() );
167 
168  // load database drivers
169  databaseDrivers_t *pDatabaseDrivers = ( databaseDrivers_t * ) cast_to_fptr( myLib.resolve( "databaseDrivers" ) );
170  if ( pDatabaseDrivers )
171  {
172  mDatabaseDrivers = pDatabaseDrivers();
173  }
174 
175  // load directory drivers
176  directoryDrivers_t *pDirectoryDrivers = ( directoryDrivers_t * ) cast_to_fptr( myLib.resolve( "directoryDrivers" ) );
177  if ( pDirectoryDrivers )
178  {
179  mDirectoryDrivers = pDirectoryDrivers();
180  }
181 
182  // load protocol drivers
183  protocolDrivers_t *pProtocolDrivers = ( protocolDrivers_t * ) cast_to_fptr( myLib.resolve( "protocolDrivers" ) );
184  if ( pProtocolDrivers )
185  {
186  mProtocolDrivers = pProtocolDrivers();
187  }
188 
189  // now get vector file filters, if any
190  fileVectorFilters_t *pFileVectorFilters = ( fileVectorFilters_t * ) cast_to_fptr( myLib.resolve( "fileVectorFilters" ) );
191  if ( pFileVectorFilters )
192  {
193  QString fileVectorFilters = pFileVectorFilters();
194 
195  if ( !fileVectorFilters.isEmpty() )
196  mVectorFileFilters += fileVectorFilters;
197 
198  QgsDebugMsg( QString( "Checking %1: ...loaded ok (%2 file filters)" ).arg( myLib.fileName() ).arg( fileVectorFilters.split( ";;" ).count() ) );
199  }
200 
201  // now get raster file filters, if any
202  // this replaces deprecated QgsRasterLayer::buildSupportedRasterFileFilter
204  ( buildsupportedrasterfilefilter_t * ) cast_to_fptr( myLib.resolve( "buildSupportedRasterFileFilter" ) );
205  if ( pBuild )
206  {
208  pBuild( fileRasterFilters );
209 
210  QgsDebugMsg( "raster filters: " + fileRasterFilters );
211  if ( !fileRasterFilters.isEmpty() )
212  mRasterFileFilters += fileRasterFilters;
213 
214  QgsDebugMsg( QString( "Checking %1: ...loaded ok (%2 file filters)" ).arg( myLib.fileName() ).arg( fileRasterFilters.split( ";;" ).count() ) );
215  }
216  }
217 } // QgsProviderRegistry ctor
218 
219 
220 // typedef for the unload dataprovider function
222 
224 {
226 
227  Providers::const_iterator it = mProviders.begin();
228 
229  while ( it != mProviders.end() )
230  {
231  QgsDebugMsg( QString( "cleanup:%1" ).arg( it->first ) );
232  QString lib = it->second->library();
233  QLibrary myLib( lib );
234  if ( myLib.isLoaded() )
235  {
236  cleanupProviderFunction_t* cleanupFunc = ( cleanupProviderFunction_t* ) cast_to_fptr( myLib.resolve( "cleanupProvider" ) );
237  if ( cleanupFunc )
238  cleanupFunc();
239  }
240  ++it;
241  }
242 }
243 
244 
252 static
254  QString const & providerKey )
255 {
256  QgsProviderRegistry::Providers::const_iterator i =
257  metaData.find( providerKey );
258 
259  if ( i != metaData.end() )
260  {
261  return i->second;
262  }
263 
264  return 0x0;
265 } // findMetadata_
266 
267 
268 
269 QString QgsProviderRegistry::library( QString const & providerKey ) const
270 {
271  QgsProviderMetadata * md = findMetadata_( mProviders, providerKey );
272 
273  if ( md )
274  {
275  return md->library();
276  }
277 
278  return QString();
279 }
280 
281 
283 {
284  Providers::const_iterator it = mProviders.begin();
285 
286  if ( mProviders.empty() )
287  return QObject::tr( "No data provider plugins are available. No vector layers can be loaded" );
288 
289  QString list;
290 
291  if ( asHTML )
292  list += "<ol>";
293 
294  while ( it != mProviders.end() )
295  {
296  if ( asHTML )
297  list += "<li>";
298 
299  list += it->second->description();
300 
301  if ( asHTML )
302  list + "<br></li>";
303  else
304  list += "\n";
305 
306  ++it;
307  }
308 
309  if ( asHTML )
310  list += "</ol>";
311 
312  return list;
313 }
314 
315 
317 {
318  mLibraryDirectory = path;
319 }
320 
321 
323 {
324  return mLibraryDirectory;
325 }
326 
327 
328 
329 // typedef for the QgsDataProvider class factory
331 
332 
340 QgsDataProvider *QgsProviderRegistry::provider( QString const & providerKey, QString const & dataSource )
341 {
342  // XXX should I check for and possibly delete any pre-existing providers?
343  // XXX How often will that scenario occur?
344 
345  // load the plugin
346  QString lib = library( providerKey );
347 
348 #ifdef TESTPROVIDERLIB
349  const char *cLib = lib.toUtf8();
350 
351  // test code to help debug provider loading problems
352  // void *handle = dlopen(cLib, RTLD_LAZY);
353  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
354  if ( !handle )
355  {
356  QgsLogger::warning( "Error in dlopen" );
357  }
358  else
359  {
360  QgsDebugMsg( "dlopen suceeded" );
361  dlclose( handle );
362  }
363 
364 #endif
365  // load the data provider
366  QLibrary myLib( lib );
367 
368  QgsDebugMsg( "Library name is " + myLib.fileName() );
369  if ( !myLib.load() )
370  {
371  QgsMessageLog::logMessage( QObject::tr( "Failed to load %1: %2" ).arg( lib ).arg( myLib.errorString() ) );
372  return 0;
373  }
374 
375  classFactoryFunction_t *classFactory = ( classFactoryFunction_t * ) cast_to_fptr( myLib.resolve( "classFactory" ) );
376  if ( !classFactory )
377  {
378  QgsDebugMsg( QString( "Failed to load %1: no classFactory method" ).arg( lib ) );
379  return 0;
380  }
381 
382  QgsDataProvider *dataProvider = classFactory( &dataSource );
383  if ( !dataProvider )
384  {
385  QgsMessageLog::logMessage( QObject::tr( "Unable to instantiate the data provider plugin %1" ).arg( lib ) );
386  myLib.unload();
387  return 0;
388  }
389 
390  QgsDebugMsg( QString( "Instantiated the data provider plugin: %1" ).arg( dataProvider->name() ) );
391  return dataProvider;
392 } // QgsProviderRegistry::setDataProvider
393 
394 int QgsProviderRegistry::providerCapabilities( const QString &providerKey ) const
395 {
396  QLibrary *library = providerLibrary( providerKey );
397  if ( !library )
398  {
400  }
401 
402  dataCapabilities_t * dataCapabilities = ( dataCapabilities_t * ) cast_to_fptr( library->resolve( "dataCapabilities" ) );
403  if ( !dataCapabilities )
404  {
406  }
407 
408  return dataCapabilities();
409 }
410 
411 // This should be QWidget, not QDialog
413 
415  QWidget * parent, Qt::WindowFlags fl )
416 {
417  selectFactoryFunction_t * selectFactory =
418  ( selectFactoryFunction_t * ) cast_to_fptr( function( providerKey, "selectWidget" ) );
419 
420  if ( !selectFactory )
421  return 0;
422 
423  return selectFactory( parent, fl );
424 }
425 
426 #if QT_VERSION >= 0x050000
427 QFunctionPointer QgsProviderRegistry::function( QString const & providerKey,
428  QString const & functionName )
429 {
430  QLibrary myLib( library( providerKey ) );
431 
432  QgsDebugMsg( "Library name is " + myLib.fileName() );
433 
434  if ( myLib.load() )
435  {
436  return myLib.resolve( functionName.toAscii().data() );
437  }
438  else
439  {
440  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
441  return 0;
442  }
443 }
444 #else
445 void *QgsProviderRegistry::function( QString const & providerKey,
446  QString const & functionName )
447 {
448  QLibrary myLib( library( providerKey ) );
449 
450  QgsDebugMsg( "Library name is " + myLib.fileName() );
451 
452  if ( myLib.load() )
453  {
454  return myLib.resolve( functionName.toAscii().data() );
455  }
456  else
457  {
458  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
459  return 0;
460  }
461 }
462 #endif
463 
465 {
466  QLibrary *myLib = new QLibrary( library( providerKey ) );
467 
468  QgsDebugMsg( "Library name is " + myLib->fileName() );
469 
470  if ( myLib->load() )
471  return myLib;
472 
473  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
474 
475  delete myLib;
476 
477  return 0;
478 }
479 
481 {
482  typedef void registerGui_function( QWidget * parent );
483 
484  foreach ( const QString &provider, providerList() )
485  {
486  registerGui_function *registerGui = ( registerGui_function * ) cast_to_fptr( function( provider, "registerGui" ) );
487 
488  if ( !registerGui )
489  continue;
490 
491  registerGui( parent );
492  }
493 }
494 
496 {
497  return mVectorFileFilters;
498 }
499 
501 {
502  return mRasterFileFilters;
503 }
504 
506 {
507  return mDatabaseDrivers;
508 }
509 
511 {
512  return mDirectoryDrivers;
513 }
514 
516 {
517  return mProtocolDrivers;
518 }
519 
521 {
522  QStringList lst;
523  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
524  {
525  lst.append( it->first );
526  }
527  return lst;
528 }
529 
531 {
532  return findMetadata_( mProviders, providerKey );
533 }
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".
int findRev(QChar c, int i, bool cs) const
bool isEmpty() const
virtual void setTitle(const QString &title)=0
set title for the messages
static QgsProviderRegistry * instance(QString pluginPath=QString::null)
Means of accessing canonical single instance.
#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()
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()
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
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()
int count(const T &value) const
void append(const T &value)
QgsDataProvider * provider(const QString &providerKey, const QString &dataSource)
Create an instance of the provider.
QWidget * selectWidget(const QString &providerKey, QWidget *parent=0, Qt::WindowFlags fl=0)
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.
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.
bool isLoaded() const
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)
int count() const
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:323
QString protocolDrivers_t()
Interface for showing messages from QGIS in GUI independent way.
int dataCapabilities_t()
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
const QString & library() const
This returns the library file name.
QByteArray toAscii() const
QString errorString() const
QByteArray toUtf8() const