QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator 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
36 typedef QString providerkey_t();
37 typedef QString description_t();
38 typedef bool isprovider_t();
39 typedef QString fileVectorFilters_t();
40 typedef void buildsupportedrasterfilefilter_t( QString & theFileFiltersString );
41 typedef QString databaseDrivers_t();
42 typedef QString directoryDrivers_t();
43 typedef QString protocolDrivers_t();
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(WIN32) || 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  QListIterator<QFileInfo> it( mLibraryDirectory.entryInfoList() );
98  while ( it.hasNext() )
99  {
100  QFileInfo fi( it.next() );
101 
102  QLibrary myLib( fi.filePath() );
103  if ( !myLib.load() )
104  {
105  QgsDebugMsg( QString( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName() ).arg( myLib.errorString() ) );
106  continue;
107  }
108 
109  //MH: Added a further test to detect non-provider plugins linked to provider plugins.
110  //Only pure provider plugins have 'type' not defined
111  isprovider_t *hasType = ( isprovider_t * ) cast_to_fptr( myLib.resolve( "type" ) );
112  if ( hasType )
113  {
114  QgsDebugMsg( QString( "Checking %1: ...invalid (has type method)" ).arg( myLib.fileName() ) );
115  continue;
116  }
117 
118  // get the description and the key for the provider plugin
119  isprovider_t *isProvider = ( isprovider_t * ) cast_to_fptr( myLib.resolve( "isProvider" ) );
120  if ( !isProvider )
121  {
122  QgsDebugMsg( QString( "Checking %1: ...invalid (no isProvider method)" ).arg( myLib.fileName() ) );
123  continue;
124  }
125 
126  // check to see if this is a provider plugin
127  if ( !isProvider() )
128  {
129  QgsDebugMsg( QString( "Checking %1: ...invalid (not a provider)" ).arg( myLib.fileName() ) );
130  continue;
131  }
132 
133  // looks like a provider. get the key and description
134  description_t *pDesc = ( description_t * ) cast_to_fptr( myLib.resolve( "description" ) );
135  if ( !pDesc )
136  {
137  QgsDebugMsg( QString( "Checking %1: ...invalid (no description method)" ).arg( myLib.fileName() ) );
138  continue;
139  }
140 
141  providerkey_t *pKey = ( providerkey_t * ) cast_to_fptr( myLib.resolve( "providerKey" ) );
142  if ( !pKey )
143  {
144  QgsDebugMsg( QString( "Checking %1: ...invalid (no providerKey method)" ).arg( myLib.fileName() ) );
145  continue;
146  }
147 
148  // add this provider to the provider map
149  mProviders[pKey()] = new QgsProviderMetadata( pKey(), pDesc(), myLib.fileName() );
150 
151  // load database drivers
152  databaseDrivers_t *pDatabaseDrivers = ( databaseDrivers_t * ) cast_to_fptr( myLib.resolve( "databaseDrivers" ) );
153  if ( pDatabaseDrivers )
154  {
155  mDatabaseDrivers = pDatabaseDrivers();
156  }
157 
158  // load directory drivers
159  directoryDrivers_t *pDirectoryDrivers = ( directoryDrivers_t * ) cast_to_fptr( myLib.resolve( "directoryDrivers" ) );
160  if ( pDirectoryDrivers )
161  {
162  mDirectoryDrivers = pDirectoryDrivers();
163  }
164 
165  // load protocol drivers
166  protocolDrivers_t *pProtocolDrivers = ( protocolDrivers_t * ) cast_to_fptr( myLib.resolve( "protocolDrivers" ) );
167  if ( pProtocolDrivers )
168  {
169  mProtocolDrivers = pProtocolDrivers();
170  }
171 
172  // now get vector file filters, if any
173  fileVectorFilters_t *pFileVectorFilters = ( fileVectorFilters_t * ) cast_to_fptr( myLib.resolve( "fileVectorFilters" ) );
174  if ( pFileVectorFilters )
175  {
176  QString fileVectorFilters = pFileVectorFilters();
177 
178  if ( !fileVectorFilters.isEmpty() )
179  mVectorFileFilters += fileVectorFilters;
180 
181  QgsDebugMsg( QString( "Checking %1: ...loaded ok (%2 file filters)" ).arg( myLib.fileName() ).arg( fileVectorFilters.split( ";;" ).count() ) );
182  }
183 
184  // now get raster file filters, if any
185  // this replaces deprecated QgsRasterLayer::buildSupportedRasterFileFilter
187  ( buildsupportedrasterfilefilter_t * ) cast_to_fptr( myLib.resolve( "buildSupportedRasterFileFilter" ) );
188  if ( pBuild )
189  {
190  QString fileRasterFilters;
191  pBuild( fileRasterFilters );
192 
193  QgsDebugMsg( "raster filters: " + fileRasterFilters );
194  if ( !fileRasterFilters.isEmpty() )
195  mRasterFileFilters += fileRasterFilters;
196 
197  QgsDebugMsg( QString( "Checking %1: ...loaded ok (%2 file filters)" ).arg( myLib.fileName() ).arg( fileRasterFilters.split( ";;" ).count() ) );
198  }
199  }
200 } // QgsProviderRegistry ctor
201 
202 
203 // typedef for the unload dataprovider function
205 
207 {
209 
210  Providers::const_iterator it = mProviders.begin();
211 
212  while ( it != mProviders.end() )
213  {
214  QgsDebugMsg( QString( "cleanup:%1" ).arg( it->first ) );
215  QString lib = it->second->library();
216  QLibrary myLib( lib );
217  if ( myLib.isLoaded() )
218  {
219  cleanupProviderFunction_t* cleanupFunc = ( cleanupProviderFunction_t* ) cast_to_fptr( myLib.resolve( "cleanupProvider" ) );
220  if ( cleanupFunc )
221  cleanupFunc();
222  }
223  ++it;
224  }
225 }
226 
227 
235 static
237  QString const & providerKey )
238 {
239  QgsProviderRegistry::Providers::const_iterator i =
240  metaData.find( providerKey );
241 
242  if ( i != metaData.end() )
243  {
244  return i->second;
245  }
246 
247  return 0x0;
248 } // findMetadata_
249 
250 
251 
252 QString QgsProviderRegistry::library( QString const & providerKey ) const
253 {
254  QgsProviderMetadata * md = findMetadata_( mProviders, providerKey );
255 
256  if ( md )
257  {
258  return md->library();
259  }
260 
261  return QString();
262 }
263 
264 
265 QString QgsProviderRegistry::pluginList( bool asHTML ) const
266 {
267  Providers::const_iterator it = mProviders.begin();
268 
269  if ( mProviders.empty() )
270  return QObject::tr( "No data provider plugins are available. No vector layers can be loaded" );
271 
272  QString list;
273 
274  if ( asHTML )
275  list += "<ol>";
276 
277  while ( it != mProviders.end() )
278  {
279  if ( asHTML )
280  list += "<li>";
281 
282  list += it->second->description();
283 
284  if ( asHTML )
285  list + "<br></li>";
286  else
287  list += "\n";
288 
289  ++it;
290  }
291 
292  if ( asHTML )
293  list += "</ol>";
294 
295  return list;
296 }
297 
298 
300 {
301  mLibraryDirectory = path;
302 }
303 
304 
306 {
307  return mLibraryDirectory;
308 }
309 
310 
311 
312 // typedef for the QgsDataProvider class factory
313 typedef QgsDataProvider * classFactoryFunction_t( const QString * );
314 
315 
323 QgsDataProvider *QgsProviderRegistry::provider( QString const & providerKey, QString const & dataSource )
324 {
325  // XXX should I check for and possibly delete any pre-existing providers?
326  // XXX How often will that scenario occur?
327 
328  // load the plugin
329  QString lib = library( providerKey );
330 
331 #ifdef TESTPROVIDERLIB
332  const char *cLib = lib.toUtf8();
333 
334  // test code to help debug provider loading problems
335  // void *handle = dlopen(cLib, RTLD_LAZY);
336  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
337  if ( !handle )
338  {
339  QgsLogger::warning( "Error in dlopen" );
340  }
341  else
342  {
343  QgsDebugMsg( "dlopen suceeded" );
344  dlclose( handle );
345  }
346 
347 #endif
348  // load the data provider
349  QLibrary myLib( lib );
350 
351  QgsDebugMsg( "Library name is " + myLib.fileName() );
352  if ( !myLib.load() )
353  {
354  QgsMessageLog::logMessage( QObject::tr( "Failed to load %1: %2" ).arg( lib ).arg( myLib.errorString() ) );
355  return 0;
356  }
357 
358  classFactoryFunction_t *classFactory = ( classFactoryFunction_t * ) cast_to_fptr( myLib.resolve( "classFactory" ) );
359  if ( !classFactory )
360  {
361  QgsDebugMsg( QString( "Failed to load %1: no classFactory method" ).arg( lib ) );
362  return 0;
363  }
364 
365  QgsDataProvider *dataProvider = classFactory( &dataSource );
366  if ( !dataProvider )
367  {
368  QgsMessageLog::logMessage( QObject::tr( "Unable to instantiate the data provider plugin %1" ).arg( lib ) );
369  myLib.unload();
370  return 0;
371  }
372 
373  QgsDebugMsg( QString( "Instantiated the data provider plugin: %1" ).arg( dataProvider->name() ) );
374  return dataProvider;
375 } // QgsProviderRegistry::setDataProvider
376 
377 int QgsProviderRegistry::providerCapabilities( const QString &providerKey ) const
378 {
379  QLibrary *library = providerLibrary( providerKey );
380  if ( !library )
381  {
383  }
384 
385  dataCapabilities_t * dataCapabilities = ( dataCapabilities_t * ) cast_to_fptr( library->resolve( "dataCapabilities" ) );
386  if ( !dataCapabilities )
387  {
389  }
390 
391  return dataCapabilities();
392 }
393 
394 // This should be QWidget, not QDialog
395 typedef QWidget * selectFactoryFunction_t( QWidget * parent, Qt::WindowFlags fl );
396 
397 QWidget* QgsProviderRegistry::selectWidget( const QString & providerKey,
398  QWidget * parent, Qt::WindowFlags fl )
399 {
400  selectFactoryFunction_t * selectFactory =
401  ( selectFactoryFunction_t * ) cast_to_fptr( function( providerKey, "selectWidget" ) );
402 
403  if ( !selectFactory )
404  return 0;
405 
406  return selectFactory( parent, fl );
407 }
408 
409 #if QT_VERSION >= 0x050000
410 QFunctionPointer QgsProviderRegistry::function( QString const & providerKey,
411  QString const & functionName )
412 {
413  QLibrary myLib( library( providerKey ) );
414 
415  QgsDebugMsg( "Library name is " + myLib.fileName() );
416 
417  if ( myLib.load() )
418  {
419  return myLib.resolve( functionName.toAscii().data() );
420  }
421  else
422  {
423  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
424  return 0;
425  }
426 }
427 #else
428 void *QgsProviderRegistry::function( QString const & providerKey,
429  QString const & functionName )
430 {
431  QLibrary myLib( library( providerKey ) );
432 
433  QgsDebugMsg( "Library name is " + myLib.fileName() );
434 
435  if ( myLib.load() )
436  {
437  return myLib.resolve( functionName.toAscii().data() );
438  }
439  else
440  {
441  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
442  return 0;
443  }
444 }
445 #endif
446 
447 QLibrary *QgsProviderRegistry::providerLibrary( QString const & providerKey ) const
448 {
449  QLibrary *myLib = new QLibrary( library( providerKey ) );
450 
451  QgsDebugMsg( "Library name is " + myLib->fileName() );
452 
453  if ( myLib->load() )
454  return myLib;
455 
456  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
457 
458  delete myLib;
459 
460  return 0;
461 }
462 
463 void QgsProviderRegistry::registerGuis( QWidget *parent )
464 {
465  typedef void registerGui_function( QWidget * parent );
466 
467  foreach ( const QString &provider, providerList() )
468  {
469  registerGui_function *registerGui = ( registerGui_function * ) cast_to_fptr( function( provider, "registerGui" ) );
470 
471  if ( !registerGui )
472  continue;
473 
474  registerGui( parent );
475  }
476 }
477 
479 {
480  return mVectorFileFilters;
481 }
482 
484 {
485  return mRasterFileFilters;
486 }
487 
489 {
490  return mDatabaseDrivers;
491 }
492 
494 {
495  return mDirectoryDrivers;
496 }
497 
499 {
500  return mProtocolDrivers;
501 }
502 
504 {
505  QStringList lst;
506  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
507  {
508  lst.append( it->first );
509  }
510  return lst;
511 }
512 
513 const QgsProviderMetadata* QgsProviderRegistry::providerMetadata( const QString& providerKey ) const
514 {
515  return findMetadata_( mProviders, providerKey );
516 }
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" ...
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.
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) ...
Abstract base class for spatial data provider implementations.
void removeAllMapLayers()
Remove all registered layers.
virtual ~QgsProviderRegistry()
Virtual dectructor.
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.
bool isprovider_t()
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)
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
void buildsupportedrasterfilefilter_t(QString &theFileFiltersString)
virtual QString fileRasterFilters() const
return raster file filter string
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
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 * function(const QString &providerKey, const QString &functionName)
Get pointer to provider function.
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()
const QString & library() const
this returns the library file name
#define tr(sourceText)