Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator 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 /* $Id$ */
19 
20 #include "qgsproviderregistry.h"
21 
22 #include <iostream>
23 
24 #include <QString>
25 #include <QDir>
26 #include <QLibrary>
27 
28 
29 #include "qgis.h"
30 #include "qgsdataprovider.h"
31 #include "qgslogger.h"
32 #include "qgsmessageoutput.h"
33 #include "qgsprovidermetadata.h"
34 
35 
36 // typedefs for provider plugin functions of interest
37 typedef QString providerkey_t();
38 typedef QString description_t();
39 typedef bool isprovider_t();
40 typedef QString fileVectorFilters_t();
41 typedef QString databaseDrivers_t();
42 typedef QString directoryDrivers_t();
43 typedef QString protocolDrivers_t();
44 
46 
48 {
49  if ( _instance == 0 )
50  {
51  _instance = new QgsProviderRegistry( pluginPath );
52  }
53 
54  return _instance;
55 
56 } // QgsProviderRegistry::instance
57 
58 
59 
61 {
62  // At startup, examine the libs in the qgis/lib dir and store those that
63  // are a provider shared lib
64  // check all libs in the current plugin directory and get name and descriptions
65  //TODO figure out how to register and identify data source plugin for a specific
66  //TODO layer type
67  /* char **argv = qApp->argv();
68  QString appDir = argv[0];
69  int bin = appDir.findRev("/bin", -1, false);
70  QString baseDir = appDir.left(bin);
71  QString mLibraryDirectory = baseDir + "/lib"; */
72  mLibraryDirectory = pluginPath;
73 
74  mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
75  mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
76 
77 #ifdef WIN32
78  mLibraryDirectory.setNameFilters( QStringList( "*.dll" ) );
79 #else
80  mLibraryDirectory.setNameFilters( QStringList( "*.so" ) );
81 #endif
82 
83  QgsDebugMsg( QString( "Checking %1 for provider plugins" ).arg( mLibraryDirectory.path() ) );
84 
85  if ( mLibraryDirectory.count() == 0 )
86  {
87  QString msg = QObject::tr( "No QGIS data provider plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() );
88  msg += QObject::tr( "No vector layers can be loaded. Check your QGIS installation" );
89 
91  output->setTitle( QObject::tr( "No Data Providers" ) );
93  output->showMessage();
94  }
95  else
96  {
97  const QFileInfoList list = mLibraryDirectory.entryInfoList();
98  QListIterator<QFileInfo> it( list );
99  QFileInfo fi;
100 
101  while ( it.hasNext() )
102  {
103  fi = it.next();
104 
105  QLibrary *myLib = new QLibrary( fi.filePath() );
106 
107  bool loaded = myLib->load();
108  //we will build up a debug message and print on one line to avoid terminal spam
109  QString myMessage = "Checking " + myLib->fileName() + " : " ;
110 
111  if ( loaded )
112  {
113  // get the description and the key for the provider plugin
114  isprovider_t *isProvider = ( isprovider_t * ) cast_to_fptr( myLib->resolve( "isProvider" ) );
115 
116  //MH: Added a further test to detect non-provider plugins linked to provider plugins.
117  //Only pure provider plugins have 'type' not defined
118  isprovider_t *hasType = ( isprovider_t * ) cast_to_fptr( myLib->resolve( "type" ) );
119 
120  if ( !hasType && isProvider )
121  {
122  // check to see if this is a provider plugin
123  if ( isProvider() )
124  {
125  // looks like a provider. get the key and description
126  description_t *pDesc = ( description_t * ) cast_to_fptr( myLib->resolve( "description" ) );
127  providerkey_t *pKey = ( providerkey_t * ) cast_to_fptr( myLib->resolve( "providerKey" ) );
128  if ( pDesc && pKey )
129  {
130  // add this provider to the provider map
131  mProviders[pKey()] =
132  new QgsProviderMetadata( pKey(), pDesc(), myLib->fileName() );
133  //myMessage += "Loaded " + QString(pDesc()) + " ok";
134 
135  // now get vector file filters, if any
136  fileVectorFilters_t *pFileVectorFilters =
137  ( fileVectorFilters_t * ) cast_to_fptr( myLib->resolve( "fileVectorFilters" ) );
138  //load database drivers
139  databaseDrivers_t *pDatabaseDrivers =
140  ( databaseDrivers_t * ) cast_to_fptr( myLib->resolve( "databaseDrivers" ) );
141  if ( pDatabaseDrivers )
142  {
143  mDatabaseDrivers = pDatabaseDrivers();
144  }
145  //load directory drivers
146  directoryDrivers_t *pDirectoryDrivers =
147  ( directoryDrivers_t * ) cast_to_fptr( myLib->resolve( "directoryDrivers" ) );
148  if ( pDirectoryDrivers )
149  {
150  mDirectoryDrivers = pDirectoryDrivers();
151  }
152  //load protocol drivers
153  protocolDrivers_t *pProtocolDrivers =
154  ( protocolDrivers_t * ) cast_to_fptr( myLib->resolve( "protocolDrivers" ) );
155  if ( pProtocolDrivers )
156  {
157  mProtocolDrivers = pProtocolDrivers();
158  }
159 
160  if ( pFileVectorFilters )
161  {
162  QString vectorFileFilters = pFileVectorFilters();
163 
164  // now get vector file filters, if any
165  fileVectorFilters_t *pVectorFileFilters =
166  ( fileVectorFilters_t * ) cast_to_fptr( myLib->resolve( "fileVectorFilters" ) );
167 
168  if ( pVectorFileFilters )
169  {
170  QString fileVectorFilters = pVectorFileFilters();
171 
172  if ( ! fileVectorFilters.isEmpty() )
173  {
175  myMessage += QString( "... loaded ok (and with %1 file filters)" ).
176  arg( fileVectorFilters.split( ";;" ).count() );
177  }
178  else
179  {
180  //myMessage += ", but it has no vector file filters for " + QString(pKey());
181  myMessage += "... loaded ok (0 file filters)";
182  }
183  }
184  }
185  else
186  {
187  //myMessage += ", but unable to invoke fileVectorFilters()";
188  myMessage += "... loaded ok (null file filters)";
189  }
190  }
191  else
192  {
193  //myMessage += ", but unable to find one of the required provider functions (providerKey() or description()) in ";
194  myMessage += "...not usable";
195 
196  }
197  }
198  else
199  {
200  //myMessage += ", but this is not a valid provider, skipping.";
201  myMessage += "..invalid";
202  }
203  }
204  else
205  {
206  //myMessage += ", but this is not a valid provider or has no type, skipping.";
207  myMessage += "..invalid (no type)";
208  }
209  }
210  else
211  {
212  myMessage += "...invalid (lib not loadable): ";
213  myMessage += myLib->errorString();
214  }
215 
216  QgsDebugMsg( myMessage );
217 
218  delete myLib;
219  }
220  }
221 
222 } // QgsProviderRegistry ctor
223 
224 
226 {
227 }
228 
229 
237 static
239  QString const & providerKey )
240 {
241  QgsProviderRegistry::Providers::const_iterator i =
242  metaData.find( providerKey );
243 
244  if ( i != metaData.end() )
245  {
246  return i->second;
247  }
248 
249  return 0x0;
250 } // findMetadata_
251 
252 
253 
254 QString QgsProviderRegistry::library( QString const & providerKey ) const
255 {
256  QgsProviderMetadata * md = findMetadata_( mProviders, providerKey );
257 
258  if ( md )
259  {
260  return md->library();
261  }
262 
263  return QString();
264 }
265 
266 
267 QString QgsProviderRegistry::pluginList( bool asHTML ) const
268 {
269  Providers::const_iterator it = mProviders.begin();
270  QString list;
271 
272  if ( mProviders.empty() )
273  {
274  list = QObject::tr( "No data provider plugins are available. No vector layers can be loaded" );
275  }
276  else
277  {
278  if ( asHTML )
279  {
280  list += "<ol>";
281  }
282  while ( it != mProviders.end() )
283  {
284  QgsProviderMetadata *mp = ( *it ).second;
285 
286  if ( asHTML )
287  {
288  list += "<li>" + mp->description() + "<br>";
289  }
290  else
291  {
292  list += mp->description() + "\n";
293  }
294 
295  it++;
296  }
297  if ( asHTML )
298  {
299  list += "</ol>";
300  }
301  }
302 
303  return list;
304 }
305 
306 
308 {
309  mLibraryDirectory = path;
310 }
311 
312 
314 {
315  return mLibraryDirectory;
316 }
317 
318 
319 
320 // typedef for the QgsDataProvider class factory
321 typedef QgsDataProvider * classFactoryFunction_t( const QString * );
322 
323 
324 
332 QgsDataProvider* QgsProviderRegistry::getProvider( QString const & providerKey,
333  QString const & dataSource )
334 {
335  // XXX should I check for and possibly delete any pre-existing providers?
336  // XXX How often will that scenario occur?
337 
338  // load the plugin
339  QString lib = library( providerKey );
340 
341 #ifdef TESTPROVIDERLIB
342  const char *cLib = lib.toUtf8();
343 
344  // test code to help debug provider loading problems
345  // void *handle = dlopen(cLib, RTLD_LAZY);
346  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
347  if ( !handle )
348  {
349  QgsLogger::warning( "Error in dlopen" );
350  }
351  else
352  {
353  QgsDebugMsg( "dlopen suceeded" );
354  dlclose( handle );
355  }
356 
357 #endif
358 
359  // load the data provider
360  QLibrary* myLib = new QLibrary( lib );
361 
362  QgsDebugMsg( "Library name is " + myLib->fileName() );
363 
364  bool loaded = myLib->load();
365 
366  if ( loaded )
367  {
368  QgsDebugMsg( "Loaded data provider library" );
369  QgsDebugMsg( "Attempting to resolve the classFactory function" );
370 
371  classFactoryFunction_t * classFactory =
372  ( classFactoryFunction_t * ) cast_to_fptr( myLib->resolve( "classFactory" ) );
373 
374  if ( classFactory )
375  {
376  QgsDebugMsg( "Getting pointer to a dataProvider object from the library" );
377 
378  //XXX - This was a dynamic cast but that kills the Windows
379  // version big-time with an abnormal termination error
380  // QgsDataProvider* dataProvider = (QgsDataProvider*)
381  // (classFactory((const char*)(dataSource.utf8())));
382 
383  QgsDataProvider * dataProvider = ( *classFactory )( &dataSource );
384 
385  if ( dataProvider )
386  {
387  QgsDebugMsg( "Instantiated the data provider plugin" );
388  QgsDebugMsg( "provider name: " + dataProvider->name() );
389 
390  if ( dataProvider->isValid() )
391  {
392  delete myLib;
393  return dataProvider;
394  }
395  else
396  { // this is likely because the dataSource is invalid, and isn't
397  // necessarily a reflection on the data provider itself
398  QgsDebugMsg( "Invalid data provider" );
399 
400  myLib->unload();
401  delete myLib;
402  return 0;
403  }
404  }
405  else
406  {
407  QgsLogger::warning( "Unable to instantiate the data provider plugin" );
408 
409  myLib->unload();
410  delete myLib;
411  return 0;
412  }
413  }
414  }
415  else
416  {
417  QgsLogger::warning( "Failed to load " + lib );
418  delete myLib;
419  return 0;
420  }
421 
422  QgsDebugMsg( "exiting" );
423 
424  return 0; // factory didn't exist
425 
426 } // QgsProviderRegistry::setDataProvider
427 
429 {
430  return mVectorFileFilters;
431 }
432 
434 {
435  return mDatabaseDrivers;
436 }
437 
439 {
440  return mDirectoryDrivers;
441 }
442 
444 {
445  return mProtocolDrivers;
446 }
447 
448 
450 {
451  QStringList lst;
452  for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); it++ )
453  {
454  lst.append( it->first );
455  }
456  return lst;
457 }
458 
459 
460 const QgsProviderMetadata* QgsProviderRegistry::providerMetadata( const QString& providerKey ) const
461 {
462  return findMetadata_( mProviders, providerKey );
463 }
464 
465 
466 /*
467 QgsDataProvider *
468 QgsProviderRegistry::openVector( QString const & dataSource, QString const & providerKey )
469 {
470  return getProvider( providerKey, dataSource );
471 } // QgsProviderRegistry::openVector
472 */