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