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