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