QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 mInstance( pluginPath );
51  return &mInstance;
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  QString lib = it->second->library();
212  QLibrary myLib( lib );
213  if ( myLib.isLoaded() )
214  {
215  cleanupProviderFunction_t* cleanupFunc = ( cleanupProviderFunction_t* ) cast_to_fptr( myLib.resolve( "cleanupProvider" ) );
216  if ( cleanupFunc )
217  cleanupFunc();
218  }
219  ++it;
220  }
221 }
222 
223 
231 static
233  QString const & providerKey )
234 {
235  QgsProviderRegistry::Providers::const_iterator i =
236  metaData.find( providerKey );
237 
238  if ( i != metaData.end() )
239  {
240  return i->second;
241  }
242 
243  return 0x0;
244 } // findMetadata_
245 
246 
247 
248 QString QgsProviderRegistry::library( QString const & providerKey ) const
249 {
250  QgsProviderMetadata * md = findMetadata_( mProviders, providerKey );
251 
252  if ( md )
253  {
254  return md->library();
255  }
256 
257  return QString();
258 }
259 
260 
261 QString QgsProviderRegistry::pluginList( bool asHTML ) const
262 {
263  Providers::const_iterator it = mProviders.begin();
264 
265  if ( mProviders.empty() )
266  return QObject::tr( "No data provider plugins are available. No vector layers can be loaded" );
267 
268  QString list;
269 
270  if ( asHTML )
271  list += "<ol>";
272 
273  while ( it != mProviders.end() )
274  {
275  if ( asHTML )
276  list += "<li>";
277 
278  list += it->second->description();
279 
280  if ( asHTML )
281  list + "<br></li>";
282  else
283  list += "\n";
284 
285  ++it;
286  }
287 
288  if ( asHTML )
289  list += "</ol>";
290 
291  return list;
292 }
293 
294 
296 {
297  mLibraryDirectory = path;
298 }
299 
300 
302 {
303  return mLibraryDirectory;
304 }
305 
306 
307 
308 // typedef for the QgsDataProvider class factory
309 typedef QgsDataProvider * classFactoryFunction_t( const QString * );
310 
311 
319 QgsDataProvider *QgsProviderRegistry::provider( QString const & providerKey, QString const & dataSource )
320 {
321  // XXX should I check for and possibly delete any pre-existing providers?
322  // XXX How often will that scenario occur?
323 
324  // load the plugin
325  QString lib = library( providerKey );
326 
327 #ifdef TESTPROVIDERLIB
328  const char *cLib = lib.toUtf8();
329 
330  // test code to help debug provider loading problems
331  // void *handle = dlopen(cLib, RTLD_LAZY);
332  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
333  if ( !handle )
334  {
335  QgsLogger::warning( "Error in dlopen" );
336  }
337  else
338  {
339  QgsDebugMsg( "dlopen suceeded" );
340  dlclose( handle );
341  }
342 
343 #endif
344  // load the data provider
345  QLibrary myLib( lib );
346 
347  QgsDebugMsg( "Library name is " + myLib.fileName() );
348  if ( !myLib.load() )
349  {
350  QgsMessageLog::logMessage( QObject::tr( "Failed to load %1: %2" ).arg( lib ).arg( myLib.errorString() ) );
351  return 0;
352  }
353 
354  classFactoryFunction_t *classFactory = ( classFactoryFunction_t * ) cast_to_fptr( myLib.resolve( "classFactory" ) );
355  if ( !classFactory )
356  {
357  QgsDebugMsg( QString( "Failed to load %1: no classFactory method" ).arg( lib ) );
358  return 0;
359  }
360 
361  QgsDataProvider *dataProvider = classFactory( &dataSource );
362  if ( !dataProvider )
363  {
364  QgsMessageLog::logMessage( QObject::tr( "Unable to instantiate the data provider plugin %1" ).arg( lib ) );
365  myLib.unload();
366  return 0;
367  }
368 
369  QgsDebugMsg( QString( "Instantiated the data provider plugin: %1" ).arg( dataProvider->name() ) );
370  return dataProvider;
371 } // QgsProviderRegistry::setDataProvider
372 
373 // This should be QWidget, not QDialog
374 typedef QWidget * selectFactoryFunction_t( QWidget * parent, Qt::WFlags fl );
375 
376 QWidget* QgsProviderRegistry::selectWidget( const QString & providerKey,
377  QWidget * parent, Qt::WFlags fl )
378 {
379  selectFactoryFunction_t * selectFactory =
380  ( selectFactoryFunction_t * ) cast_to_fptr( function( providerKey, "selectWidget" ) );
381 
382  if ( !selectFactory )
383  return 0;
384 
385  return selectFactory( parent, fl );
386 }
387 
388 void *QgsProviderRegistry::function( QString const & providerKey,
389  QString const & functionName )
390 {
391  QLibrary myLib( library( providerKey ) );
392 
393  QgsDebugMsg( "Library name is " + myLib.fileName() );
394 
395  if ( myLib.load() )
396  {
397  return myLib.resolve( functionName.toAscii().data() );
398  }
399  else
400  {
401  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
402  return 0;
403  }
404 }
405 
406 QLibrary *QgsProviderRegistry::providerLibrary( QString const & providerKey ) const
407 {
408  QLibrary *myLib = new QLibrary( library( providerKey ) );
409 
410  QgsDebugMsg( "Library name is " + myLib->fileName() );
411 
412  if ( myLib->load() )
413  return myLib;
414 
415  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
416 
417  delete myLib;
418 
419  return 0;
420 }
421 
422 void QgsProviderRegistry::registerGuis( QWidget *parent )
423 {
424  typedef void registerGui_function( QWidget * parent );
425 
426  foreach ( const QString &provider, providerList() )
427  {
428  registerGui_function *registerGui = ( registerGui_function * ) cast_to_fptr( function( provider, "registerGui" ) );
429 
430  if ( !registerGui )
431  continue;
432 
433  registerGui( parent );
434  }
435 }
436 
438 {
439  return mVectorFileFilters;
440 }
441 
443 {
444  return mRasterFileFilters;
445 }
446 
448 {
449  return mDatabaseDrivers;
450 }
451 
453 {
454  return mDirectoryDrivers;
455 }
456 
458 {
459  return mProtocolDrivers;
460 }
461 
463 {
464  QStringList lst;
465  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); ++it )
466  {
467  lst.append( it->first );
468  }
469  return lst;
470 }
471 
472 const QgsProviderMetadata* QgsProviderRegistry::providerMetadata( const QString& providerKey ) const
473 {
474  return findMetadata_( mProviders, providerKey );
475 }
476 
477 
478 #if 0
480 QgsProviderRegistry::openVector( QString const & dataSource, QString const & providerKey )
481 {
482  return getProvider( providerKey, dataSource );
483 } // QgsProviderRegistry::openVector
484 #endif
QWidget * selectFactoryFunction_t(QWidget *parent, Qt::WFlags fl)
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.
virtual QString name() const =0
return a provider name
QString description_t()
QWidget * selectWidget(const QString &providerKey, QWidget *parent=0, Qt::WFlags fl=0)
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.
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:282
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)