QGIS API Documentation  2.5.0-Master
 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 
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 
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 // This should be QWidget, not QDialog
375 typedef QWidget * selectFactoryFunction_t( QWidget * parent, Qt::WindowFlags fl );
376 
377 QWidget* QgsProviderRegistry::selectWidget( const QString & providerKey,
378  QWidget * parent, Qt::WindowFlags fl )
379 {
380  selectFactoryFunction_t * selectFactory =
381  ( selectFactoryFunction_t * ) cast_to_fptr( function( providerKey, "selectWidget" ) );
382 
383  if ( !selectFactory )
384  return 0;
385 
386  return selectFactory( parent, fl );
387 }
388 
389 void *QgsProviderRegistry::function( QString const & providerKey,
390  QString const & functionName )
391 {
392  QLibrary myLib( library( providerKey ) );
393 
394  QgsDebugMsg( "Library name is " + myLib.fileName() );
395 
396  if ( myLib.load() )
397  {
398  return myLib.resolve( functionName.toAscii().data() );
399  }
400  else
401  {
402  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
403  return 0;
404  }
405 }
406 
407 QLibrary *QgsProviderRegistry::providerLibrary( QString const & providerKey ) const
408 {
409  QLibrary *myLib = new QLibrary( library( providerKey ) );
410 
411  QgsDebugMsg( "Library name is " + myLib->fileName() );
412 
413  if ( myLib->load() )
414  return myLib;
415 
416  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
417 
418  delete myLib;
419 
420  return 0;
421 }
422 
423 void QgsProviderRegistry::registerGuis( QWidget *parent )
424 {
425  typedef void registerGui_function( QWidget * parent );
426 
427  foreach ( const QString &provider, providerList() )
428  {
429  registerGui_function *registerGui = ( registerGui_function * ) cast_to_fptr( function( provider, "registerGui" ) );
430 
431  if ( !registerGui )
432  continue;
433 
434  registerGui( parent );
435  }
436 }
437 
439 {
440  return mVectorFileFilters;
441 }
442 
444 {
445  return mRasterFileFilters;
446 }
447 
449 {
450  return mDatabaseDrivers;
451 }
452 
454 {
455  return mDirectoryDrivers;
456 }
457 
459 {
460  return mProtocolDrivers;
461 }
462 
464 {
465  QStringList lst;
466  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
467  {
468  lst.append( it->first );
469  }
470  return lst;
471 }
472 
473 const QgsProviderMetadata* QgsProviderRegistry::providerMetadata( const QString& providerKey ) const
474 {
475  return findMetadata_( mProviders, providerKey );
476 }
477 
478 
479 #if 0
481 QgsProviderRegistry::openVector( QString const & dataSource, QString const & providerKey )
482 {
483  return getProvider( providerKey, dataSource );
484 } // QgsProviderRegistry::openVector
485 #endif
QgsDataProvider * classFactoryFunction_t(const QString *)
QString databaseDrivers_t()
QString mRasterFileFilters
file filter string for raster files
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" ...
QString mVectorFileFilters
file filter string for vector files
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:36
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:162
const QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Return metadata of the provider or NULL if not found.
Providers mProviders
associative container of provider metadata handles
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) ...
QString mProtocolDrivers
Available protocol drivers string for vector databases.
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
virtual void setMessage(const QString &message, MessageType msgType)=0
set message, it won't be displayed until
QString mDirectoryDrivers
Available directory drivers string for vector databases.
void setLibraryDirectory(const QDir &path)
Set library directory where to search for plugins.
QDir mLibraryDirectory
directory in which provider plugins are installed
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.
QgsProviderRegistry(QString pluginPath)
ctor private since instance() creates it
std::map< QString, QgsProviderMetadata * > Providers
open the given vector data source
A registry / canonical manager of data providers.
QString mDatabaseDrivers
Available database drivers string for vector databases.
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.
const QString & library() const
this returns the library file name
#define tr(sourceText)