QGIS API Documentation  2.7.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 
33 
34 // typedefs for provider plugin functions of interest
35 typedef QString providerkey_t();
36 typedef QString description_t();
37 typedef bool isprovider_t();
38 typedef QString fileVectorFilters_t();
39 typedef void buildsupportedrasterfilefilter_t( QString & theFileFiltersString );
40 typedef QString databaseDrivers_t();
41 typedef QString directoryDrivers_t();
42 typedef QString protocolDrivers_t();
43 //typedef int dataCapabilities_t();
44 //typedef QgsDataItem * dataItem_t(QString);
45 
46 
47 
49 {
50  static QgsProviderRegistry* sInstance( new QgsProviderRegistry( pluginPath ) );
51  return sInstance;
52 } // QgsProviderRegistry::instance
53 
54 
55 
56 QgsProviderRegistry::QgsProviderRegistry( QString pluginPath )
57 {
58  // At startup, examine the libs in the qgis/lib dir and store those that
59  // are a provider shared lib
60  // check all libs in the current plugin directory and get name and descriptions
61  //TODO figure out how to register and identify data source plugin for a specific
62  //TODO layer type
63 #if 0
64  char **argv = qApp->argv();
65  QString appDir = argv[0];
66  int bin = appDir.findRev( "/bin", -1, false );
67  QString baseDir = appDir.left( bin );
68  QString mLibraryDirectory = baseDir + "/lib";
69 #endif
70  mLibraryDirectory = pluginPath;
71  mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
72  mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
73 
74 #if defined(WIN32) || defined(__CYGWIN__)
75  mLibraryDirectory.setNameFilters( QStringList( "*.dll" ) );
76 #elif ANDROID
77  mLibraryDirectory.setNameFilters( QStringList( "*provider.so" ) );
78 #else
79  mLibraryDirectory.setNameFilters( QStringList( "*.so" ) );
80 #endif
81 
82  QgsDebugMsg( QString( "Checking %1 for provider plugins" ).arg( mLibraryDirectory.path() ) );
83 
84  if ( mLibraryDirectory.count() == 0 )
85  {
86  QString msg = QObject::tr( "No QGIS data provider plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() );
87  msg += QObject::tr( "No vector layers can be loaded. Check your QGIS installation" );
88 
90  output->setTitle( QObject::tr( "No Data Providers" ) );
92  output->showMessage();
93  return;
94  }
95 
96  QListIterator<QFileInfo> it( mLibraryDirectory.entryInfoList() );
97  while ( it.hasNext() )
98  {
99  QFileInfo fi( it.next() );
100 
101  QLibrary myLib( fi.filePath() );
102  if ( !myLib.load() )
103  {
104  QgsDebugMsg( QString( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName() ).arg( myLib.errorString() ) );
105  continue;
106  }
107 
108  //MH: Added a further test to detect non-provider plugins linked to provider plugins.
109  //Only pure provider plugins have 'type' not defined
110  isprovider_t *hasType = ( isprovider_t * ) cast_to_fptr( myLib.resolve( "type" ) );
111  if ( hasType )
112  {
113  QgsDebugMsg( QString( "Checking %1: ...invalid (has type method)" ).arg( myLib.fileName() ) );
114  continue;
115  }
116 
117  // get the description and the key for the provider plugin
118  isprovider_t *isProvider = ( isprovider_t * ) cast_to_fptr( myLib.resolve( "isProvider" ) );
119  if ( !isProvider )
120  {
121  QgsDebugMsg( QString( "Checking %1: ...invalid (no isProvider method)" ).arg( myLib.fileName() ) );
122  continue;
123  }
124 
125  // check to see if this is a provider plugin
126  if ( !isProvider() )
127  {
128  QgsDebugMsg( QString( "Checking %1: ...invalid (not a provider)" ).arg( myLib.fileName() ) );
129  continue;
130  }
131 
132  // looks like a provider. get the key and description
133  description_t *pDesc = ( description_t * ) cast_to_fptr( myLib.resolve( "description" ) );
134  if ( !pDesc )
135  {
136  QgsDebugMsg( QString( "Checking %1: ...invalid (no description method)" ).arg( myLib.fileName() ) );
137  continue;
138  }
139 
140  providerkey_t *pKey = ( providerkey_t * ) cast_to_fptr( myLib.resolve( "providerKey" ) );
141  if ( !pKey )
142  {
143  QgsDebugMsg( QString( "Checking %1: ...invalid (no providerKey method)" ).arg( myLib.fileName() ) );
144  continue;
145  }
146 
147  // add this provider to the provider map
148  mProviders[pKey()] = new QgsProviderMetadata( pKey(), pDesc(), myLib.fileName() );
149 
150  // load database drivers
151  databaseDrivers_t *pDatabaseDrivers = ( databaseDrivers_t * ) cast_to_fptr( myLib.resolve( "databaseDrivers" ) );
152  if ( pDatabaseDrivers )
153  {
154  mDatabaseDrivers = pDatabaseDrivers();
155  }
156 
157  // load directory drivers
158  directoryDrivers_t *pDirectoryDrivers = ( directoryDrivers_t * ) cast_to_fptr( myLib.resolve( "directoryDrivers" ) );
159  if ( pDirectoryDrivers )
160  {
161  mDirectoryDrivers = pDirectoryDrivers();
162  }
163 
164  // load protocol drivers
165  protocolDrivers_t *pProtocolDrivers = ( protocolDrivers_t * ) cast_to_fptr( myLib.resolve( "protocolDrivers" ) );
166  if ( pProtocolDrivers )
167  {
168  mProtocolDrivers = pProtocolDrivers();
169  }
170 
171  // now get vector file filters, if any
172  fileVectorFilters_t *pFileVectorFilters = ( fileVectorFilters_t * ) cast_to_fptr( myLib.resolve( "fileVectorFilters" ) );
173  if ( pFileVectorFilters )
174  {
175  QString fileVectorFilters = pFileVectorFilters();
176 
177  if ( !fileVectorFilters.isEmpty() )
178  mVectorFileFilters += fileVectorFilters;
179 
180  QgsDebugMsg( QString( "Checking %1: ...loaded ok (%2 file filters)" ).arg( myLib.fileName() ).arg( fileVectorFilters.split( ";;" ).count() ) );
181  }
182 
183  // now get raster file filters, if any
184  // this replaces deprecated QgsRasterLayer::buildSupportedRasterFileFilter
186  ( buildsupportedrasterfilefilter_t * ) cast_to_fptr( myLib.resolve( "buildSupportedRasterFileFilter" ) );
187  if ( pBuild )
188  {
189  QString fileRasterFilters;
190  pBuild( fileRasterFilters );
191 
192  QgsDebugMsg( "raster filters: " + fileRasterFilters );
193  if ( !fileRasterFilters.isEmpty() )
194  mRasterFileFilters += fileRasterFilters;
195 
196  QgsDebugMsg( QString( "Checking %1: ...loaded ok (%2 file filters)" ).arg( myLib.fileName() ).arg( fileRasterFilters.split( ";;" ).count() ) );
197  }
198  }
199 } // QgsProviderRegistry ctor
200 
201 
202 // typedef for the unload dataprovider function
204 
206 {
207  Providers::const_iterator it = mProviders.begin();
208 
209  while ( it != mProviders.end() )
210  {
211  QgsDebugMsg( QString( "cleanup: %1" ).arg( it->first ) );
212  QString lib = it->second->library();
213  QLibrary myLib( lib );
214  if ( myLib.isLoaded() )
215  {
216  cleanupProviderFunction_t* cleanupFunc = ( cleanupProviderFunction_t* ) cast_to_fptr( myLib.resolve( "cleanupProvider" ) );
217  if ( cleanupFunc )
218  cleanupFunc();
219  }
220  ++it;
221  }
222 }
223 
224 
232 static
234  QString const & providerKey )
235 {
236  QgsProviderRegistry::Providers::const_iterator i =
237  metaData.find( providerKey );
238 
239  if ( i != metaData.end() )
240  {
241  return i->second;
242  }
243 
244  return 0x0;
245 } // findMetadata_
246 
247 
248 
249 QString QgsProviderRegistry::library( QString const & providerKey ) const
250 {
251  QgsProviderMetadata * md = findMetadata_( mProviders, providerKey );
252 
253  if ( md )
254  {
255  return md->library();
256  }
257 
258  return QString();
259 }
260 
261 
262 QString QgsProviderRegistry::pluginList( bool asHTML ) const
263 {
264  Providers::const_iterator it = mProviders.begin();
265 
266  if ( mProviders.empty() )
267  return QObject::tr( "No data provider plugins are available. No vector layers can be loaded" );
268 
269  QString list;
270 
271  if ( asHTML )
272  list += "<ol>";
273 
274  while ( it != mProviders.end() )
275  {
276  if ( asHTML )
277  list += "<li>";
278 
279  list += it->second->description();
280 
281  if ( asHTML )
282  list + "<br></li>";
283  else
284  list += "\n";
285 
286  ++it;
287  }
288 
289  if ( asHTML )
290  list += "</ol>";
291 
292  return list;
293 }
294 
295 
297 {
298  mLibraryDirectory = path;
299 }
300 
301 
303 {
304  return mLibraryDirectory;
305 }
306 
307 
308 
309 // typedef for the QgsDataProvider class factory
310 typedef QgsDataProvider * classFactoryFunction_t( const QString * );
311 
312 
320 QgsDataProvider *QgsProviderRegistry::provider( QString const & providerKey, QString const & dataSource )
321 {
322  // XXX should I check for and possibly delete any pre-existing providers?
323  // XXX How often will that scenario occur?
324 
325  // load the plugin
326  QString lib = library( providerKey );
327 
328 #ifdef TESTPROVIDERLIB
329  const char *cLib = lib.toUtf8();
330 
331  // test code to help debug provider loading problems
332  // void *handle = dlopen(cLib, RTLD_LAZY);
333  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
334  if ( !handle )
335  {
336  QgsLogger::warning( "Error in dlopen" );
337  }
338  else
339  {
340  QgsDebugMsg( "dlopen suceeded" );
341  dlclose( handle );
342  }
343 
344 #endif
345  // load the data provider
346  QLibrary myLib( lib );
347 
348  QgsDebugMsg( "Library name is " + myLib.fileName() );
349  if ( !myLib.load() )
350  {
351  QgsMessageLog::logMessage( QObject::tr( "Failed to load %1: %2" ).arg( lib ).arg( myLib.errorString() ) );
352  return 0;
353  }
354 
355  classFactoryFunction_t *classFactory = ( classFactoryFunction_t * ) cast_to_fptr( myLib.resolve( "classFactory" ) );
356  if ( !classFactory )
357  {
358  QgsDebugMsg( QString( "Failed to load %1: no classFactory method" ).arg( lib ) );
359  return 0;
360  }
361 
362  QgsDataProvider *dataProvider = classFactory( &dataSource );
363  if ( !dataProvider )
364  {
365  QgsMessageLog::logMessage( QObject::tr( "Unable to instantiate the data provider plugin %1" ).arg( lib ) );
366  myLib.unload();
367  return 0;
368  }
369 
370  QgsDebugMsg( QString( "Instantiated the data provider plugin: %1" ).arg( dataProvider->name() ) );
371  return dataProvider;
372 } // QgsProviderRegistry::setDataProvider
373 
374 int QgsProviderRegistry::providerCapabilities( const QString &providerKey ) const
375 {
376  QLibrary *library = providerLibrary( providerKey );
377  if ( !library )
378  {
380  }
381 
382  dataCapabilities_t * dataCapabilities = ( dataCapabilities_t * ) cast_to_fptr( library->resolve( "dataCapabilities" ) );
383  if ( !dataCapabilities )
384  {
386  }
387 
388  return dataCapabilities();
389 }
390 
391 // This should be QWidget, not QDialog
392 typedef QWidget * selectFactoryFunction_t( QWidget * parent, Qt::WindowFlags fl );
393 
394 QWidget* QgsProviderRegistry::selectWidget( const QString & providerKey,
395  QWidget * parent, Qt::WindowFlags fl )
396 {
397  selectFactoryFunction_t * selectFactory =
398  ( selectFactoryFunction_t * ) cast_to_fptr( function( providerKey, "selectWidget" ) );
399 
400  if ( !selectFactory )
401  return 0;
402 
403  return selectFactory( parent, fl );
404 }
405 
406 #if QT_VERSION >= 0x050000
407 QFunctionPointer QgsProviderRegistry::function( QString const & providerKey,
408  QString const & functionName )
409 {
410  QLibrary myLib( library( providerKey ) );
411 
412  QgsDebugMsg( "Library name is " + myLib.fileName() );
413 
414  if ( myLib.load() )
415  {
416  return myLib.resolve( functionName.toAscii().data() );
417  }
418  else
419  {
420  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
421  return 0;
422  }
423 }
424 #else
425 void *QgsProviderRegistry::function( QString const & providerKey,
426  QString const & functionName )
427 {
428  QLibrary myLib( library( providerKey ) );
429 
430  QgsDebugMsg( "Library name is " + myLib.fileName() );
431 
432  if ( myLib.load() )
433  {
434  return myLib.resolve( functionName.toAscii().data() );
435  }
436  else
437  {
438  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
439  return 0;
440  }
441 }
442 #endif
443 
444 QLibrary *QgsProviderRegistry::providerLibrary( QString const & providerKey ) const
445 {
446  QLibrary *myLib = new QLibrary( library( providerKey ) );
447 
448  QgsDebugMsg( "Library name is " + myLib->fileName() );
449 
450  if ( myLib->load() )
451  return myLib;
452 
453  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
454 
455  delete myLib;
456 
457  return 0;
458 }
459 
460 void QgsProviderRegistry::registerGuis( QWidget *parent )
461 {
462  typedef void registerGui_function( QWidget * parent );
463 
464  foreach ( const QString &provider, providerList() )
465  {
466  registerGui_function *registerGui = ( registerGui_function * ) cast_to_fptr( function( provider, "registerGui" ) );
467 
468  if ( !registerGui )
469  continue;
470 
471  registerGui( parent );
472  }
473 }
474 
476 {
477  return mVectorFileFilters;
478 }
479 
481 {
482  return mRasterFileFilters;
483 }
484 
486 {
487  return mDatabaseDrivers;
488 }
489 
491 {
492  return mDirectoryDrivers;
493 }
494 
496 {
497  return mProtocolDrivers;
498 }
499 
501 {
502  QStringList lst;
503  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
504  {
505  lst.append( it->first );
506  }
507  return lst;
508 }
509 
510 const QgsProviderMetadata* QgsProviderRegistry::providerMetadata( const QString& providerKey ) const
511 {
512  return findMetadata_( mProviders, providerKey );
513 }
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.
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.
void * function(const QString &providerKey, const QString &functionName)
Get pointer to provider function.
void(*)() cast_to_fptr(void *p)
Definition: qgis.h:301
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)