Quantum GIS API Documentation
1.7.4
|
00001 /*************************************************************************** 00002 qgsproviderregistry.cpp - Singleton class for 00003 registering data providers. 00004 ------------------- 00005 begin : Sat Jan 10 2004 00006 copyright : (C) 2004 by Gary E.Sherman 00007 email : sherman at mrcc.com 00008 ***************************************************************************/ 00009 00010 /*************************************************************************** 00011 * * 00012 * This program is free software; you can redistribute it and/or modify * 00013 * it under the terms of the GNU General Public License as published by * 00014 * the Free Software Foundation; either version 2 of the License, or * 00015 * (at your option) any later version. * 00016 * * 00017 ***************************************************************************/ 00018 /* $Id$ */ 00019 00020 #include "qgsproviderregistry.h" 00021 00022 #include <iostream> 00023 00024 #include <QString> 00025 #include <QDir> 00026 #include <QLibrary> 00027 00028 00029 #include "qgis.h" 00030 #include "qgsdataprovider.h" 00031 #include "qgslogger.h" 00032 #include "qgsmessageoutput.h" 00033 #include "qgsprovidermetadata.h" 00034 00035 00036 // typedefs for provider plugin functions of interest 00037 typedef QString providerkey_t(); 00038 typedef QString description_t(); 00039 typedef bool isprovider_t(); 00040 typedef QString fileVectorFilters_t(); 00041 typedef QString databaseDrivers_t(); 00042 typedef QString directoryDrivers_t(); 00043 typedef QString protocolDrivers_t(); 00044 00045 QgsProviderRegistry *QgsProviderRegistry::_instance = 0; 00046 00047 QgsProviderRegistry *QgsProviderRegistry::instance( QString pluginPath ) 00048 { 00049 if ( _instance == 0 ) 00050 { 00051 _instance = new QgsProviderRegistry( pluginPath ); 00052 } 00053 00054 return _instance; 00055 00056 } // QgsProviderRegistry::instance 00057 00058 00059 00060 QgsProviderRegistry::QgsProviderRegistry( QString pluginPath ) 00061 { 00062 // At startup, examine the libs in the qgis/lib dir and store those that 00063 // are a provider shared lib 00064 // check all libs in the current plugin directory and get name and descriptions 00065 //TODO figure out how to register and identify data source plugin for a specific 00066 //TODO layer type 00067 /* char **argv = qApp->argv(); 00068 QString appDir = argv[0]; 00069 int bin = appDir.findRev("/bin", -1, false); 00070 QString baseDir = appDir.left(bin); 00071 QString mLibraryDirectory = baseDir + "/lib"; */ 00072 mLibraryDirectory = pluginPath; 00073 00074 mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase ); 00075 mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks ); 00076 00077 #ifdef WIN32 00078 mLibraryDirectory.setNameFilters( QStringList( "*.dll" ) ); 00079 #else 00080 mLibraryDirectory.setNameFilters( QStringList( "*.so" ) ); 00081 #endif 00082 00083 QgsDebugMsg( QString( "Checking %1 for provider plugins" ).arg( mLibraryDirectory.path() ) ); 00084 00085 if ( mLibraryDirectory.count() == 0 ) 00086 { 00087 QString msg = QObject::tr( "No QGIS data provider plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() ); 00088 msg += QObject::tr( "No vector layers can be loaded. Check your QGIS installation" ); 00089 00090 QgsMessageOutput* output = QgsMessageOutput::createMessageOutput(); 00091 output->setTitle( QObject::tr( "No Data Providers" ) ); 00092 output->setMessage( msg, QgsMessageOutput::MessageText ); 00093 output->showMessage(); 00094 } 00095 else 00096 { 00097 const QFileInfoList list = mLibraryDirectory.entryInfoList(); 00098 QListIterator<QFileInfo> it( list ); 00099 QFileInfo fi; 00100 00101 while ( it.hasNext() ) 00102 { 00103 fi = it.next(); 00104 00105 QLibrary *myLib = new QLibrary( fi.filePath() ); 00106 00107 bool loaded = myLib->load(); 00108 //we will build up a debug message and print on one line to avoid terminal spam 00109 QString myMessage = "Checking " + myLib->fileName() + " : " ; 00110 00111 if ( loaded ) 00112 { 00113 // get the description and the key for the provider plugin 00114 isprovider_t *isProvider = ( isprovider_t * ) cast_to_fptr( myLib->resolve( "isProvider" ) ); 00115 00116 //MH: Added a further test to detect non-provider plugins linked to provider plugins. 00117 //Only pure provider plugins have 'type' not defined 00118 isprovider_t *hasType = ( isprovider_t * ) cast_to_fptr( myLib->resolve( "type" ) ); 00119 00120 if ( !hasType && isProvider ) 00121 { 00122 // check to see if this is a provider plugin 00123 if ( isProvider() ) 00124 { 00125 // looks like a provider. get the key and description 00126 description_t *pDesc = ( description_t * ) cast_to_fptr( myLib->resolve( "description" ) ); 00127 providerkey_t *pKey = ( providerkey_t * ) cast_to_fptr( myLib->resolve( "providerKey" ) ); 00128 if ( pDesc && pKey ) 00129 { 00130 // add this provider to the provider map 00131 mProviders[pKey()] = 00132 new QgsProviderMetadata( pKey(), pDesc(), myLib->fileName() ); 00133 //myMessage += "Loaded " + QString(pDesc()) + " ok"; 00134 00135 // now get vector file filters, if any 00136 fileVectorFilters_t *pFileVectorFilters = 00137 ( fileVectorFilters_t * ) cast_to_fptr( myLib->resolve( "fileVectorFilters" ) ); 00138 //load database drivers 00139 databaseDrivers_t *pDatabaseDrivers = 00140 ( databaseDrivers_t * ) cast_to_fptr( myLib->resolve( "databaseDrivers" ) ); 00141 if ( pDatabaseDrivers ) 00142 { 00143 mDatabaseDrivers = pDatabaseDrivers(); 00144 } 00145 //load directory drivers 00146 directoryDrivers_t *pDirectoryDrivers = 00147 ( directoryDrivers_t * ) cast_to_fptr( myLib->resolve( "directoryDrivers" ) ); 00148 if ( pDirectoryDrivers ) 00149 { 00150 mDirectoryDrivers = pDirectoryDrivers(); 00151 } 00152 //load protocol drivers 00153 protocolDrivers_t *pProtocolDrivers = 00154 ( protocolDrivers_t * ) cast_to_fptr( myLib->resolve( "protocolDrivers" ) ); 00155 if ( pProtocolDrivers ) 00156 { 00157 mProtocolDrivers = pProtocolDrivers(); 00158 } 00159 00160 if ( pFileVectorFilters ) 00161 { 00162 QString vectorFileFilters = pFileVectorFilters(); 00163 00164 // now get vector file filters, if any 00165 fileVectorFilters_t *pVectorFileFilters = 00166 ( fileVectorFilters_t * ) cast_to_fptr( myLib->resolve( "fileVectorFilters" ) ); 00167 00168 if ( pVectorFileFilters ) 00169 { 00170 QString fileVectorFilters = pVectorFileFilters(); 00171 00172 if ( ! fileVectorFilters.isEmpty() ) 00173 { 00174 mVectorFileFilters += fileVectorFilters; 00175 myMessage += QString( "... loaded ok (and with %1 file filters)" ). 00176 arg( fileVectorFilters.split( ";;" ).count() ); 00177 } 00178 else 00179 { 00180 //myMessage += ", but it has no vector file filters for " + QString(pKey()); 00181 myMessage += "... loaded ok (0 file filters)"; 00182 } 00183 } 00184 } 00185 else 00186 { 00187 //myMessage += ", but unable to invoke fileVectorFilters()"; 00188 myMessage += "... loaded ok (null file filters)"; 00189 } 00190 } 00191 else 00192 { 00193 //myMessage += ", but unable to find one of the required provider functions (providerKey() or description()) in "; 00194 myMessage += "...not usable"; 00195 00196 } 00197 } 00198 else 00199 { 00200 //myMessage += ", but this is not a valid provider, skipping."; 00201 myMessage += "..invalid"; 00202 } 00203 } 00204 else 00205 { 00206 //myMessage += ", but this is not a valid provider or has no type, skipping."; 00207 myMessage += "..invalid (no type)"; 00208 } 00209 } 00210 else 00211 { 00212 myMessage += "...invalid (lib not loadable): "; 00213 myMessage += myLib->errorString(); 00214 } 00215 00216 QgsDebugMsg( myMessage ); 00217 00218 delete myLib; 00219 } 00220 } 00221 00222 } // QgsProviderRegistry ctor 00223 00224 00225 QgsProviderRegistry::~QgsProviderRegistry() 00226 { 00227 } 00228 00229 00237 static 00238 QgsProviderMetadata * findMetadata_( QgsProviderRegistry::Providers const & metaData, 00239 QString const & providerKey ) 00240 { 00241 QgsProviderRegistry::Providers::const_iterator i = 00242 metaData.find( providerKey ); 00243 00244 if ( i != metaData.end() ) 00245 { 00246 return i->second; 00247 } 00248 00249 return 0x0; 00250 } // findMetadata_ 00251 00252 00253 00254 QString QgsProviderRegistry::library( QString const & providerKey ) const 00255 { 00256 QgsProviderMetadata * md = findMetadata_( mProviders, providerKey ); 00257 00258 if ( md ) 00259 { 00260 return md->library(); 00261 } 00262 00263 return QString(); 00264 } 00265 00266 00267 QString QgsProviderRegistry::pluginList( bool asHTML ) const 00268 { 00269 Providers::const_iterator it = mProviders.begin(); 00270 QString list; 00271 00272 if ( mProviders.empty() ) 00273 { 00274 list = QObject::tr( "No data provider plugins are available. No vector layers can be loaded" ); 00275 } 00276 else 00277 { 00278 if ( asHTML ) 00279 { 00280 list += "<ol>"; 00281 } 00282 while ( it != mProviders.end() ) 00283 { 00284 QgsProviderMetadata *mp = ( *it ).second; 00285 00286 if ( asHTML ) 00287 { 00288 list += "<li>" + mp->description() + "<br>"; 00289 } 00290 else 00291 { 00292 list += mp->description() + "\n"; 00293 } 00294 00295 it++; 00296 } 00297 if ( asHTML ) 00298 { 00299 list += "</ol>"; 00300 } 00301 } 00302 00303 return list; 00304 } 00305 00306 00307 void QgsProviderRegistry::setLibraryDirectory( QDir const & path ) 00308 { 00309 mLibraryDirectory = path; 00310 } 00311 00312 00313 QDir const & QgsProviderRegistry::libraryDirectory() const 00314 { 00315 return mLibraryDirectory; 00316 } 00317 00318 00319 00320 // typedef for the QgsDataProvider class factory 00321 typedef QgsDataProvider * classFactoryFunction_t( const QString * ); 00322 00323 00324 00332 QgsDataProvider* QgsProviderRegistry::getProvider( QString const & providerKey, 00333 QString const & dataSource ) 00334 { 00335 // XXX should I check for and possibly delete any pre-existing providers? 00336 // XXX How often will that scenario occur? 00337 00338 // load the plugin 00339 QString lib = library( providerKey ); 00340 00341 #ifdef TESTPROVIDERLIB 00342 const char *cLib = lib.toUtf8(); 00343 00344 // test code to help debug provider loading problems 00345 // void *handle = dlopen(cLib, RTLD_LAZY); 00346 void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL ); 00347 if ( !handle ) 00348 { 00349 QgsLogger::warning( "Error in dlopen" ); 00350 } 00351 else 00352 { 00353 QgsDebugMsg( "dlopen suceeded" ); 00354 dlclose( handle ); 00355 } 00356 00357 #endif 00358 00359 // load the data provider 00360 QLibrary* myLib = new QLibrary( lib ); 00361 00362 QgsDebugMsg( "Library name is " + myLib->fileName() ); 00363 00364 bool loaded = myLib->load(); 00365 00366 if ( loaded ) 00367 { 00368 QgsDebugMsg( "Loaded data provider library" ); 00369 QgsDebugMsg( "Attempting to resolve the classFactory function" ); 00370 00371 classFactoryFunction_t * classFactory = 00372 ( classFactoryFunction_t * ) cast_to_fptr( myLib->resolve( "classFactory" ) ); 00373 00374 if ( classFactory ) 00375 { 00376 QgsDebugMsg( "Getting pointer to a dataProvider object from the library" ); 00377 00378 //XXX - This was a dynamic cast but that kills the Windows 00379 // version big-time with an abnormal termination error 00380 // QgsDataProvider* dataProvider = (QgsDataProvider*) 00381 // (classFactory((const char*)(dataSource.utf8()))); 00382 00383 QgsDataProvider * dataProvider = ( *classFactory )( &dataSource ); 00384 00385 if ( dataProvider ) 00386 { 00387 QgsDebugMsg( "Instantiated the data provider plugin" ); 00388 QgsDebugMsg( "provider name: " + dataProvider->name() ); 00389 00390 if ( dataProvider->isValid() ) 00391 { 00392 delete myLib; 00393 return dataProvider; 00394 } 00395 else 00396 { // this is likely because the dataSource is invalid, and isn't 00397 // necessarily a reflection on the data provider itself 00398 QgsDebugMsg( "Invalid data provider" ); 00399 00400 myLib->unload(); 00401 delete myLib; 00402 return 0; 00403 } 00404 } 00405 else 00406 { 00407 QgsLogger::warning( "Unable to instantiate the data provider plugin" ); 00408 00409 myLib->unload(); 00410 delete myLib; 00411 return 0; 00412 } 00413 } 00414 } 00415 else 00416 { 00417 QgsLogger::warning( "Failed to load " + lib ); 00418 delete myLib; 00419 return 0; 00420 } 00421 00422 QgsDebugMsg( "exiting" ); 00423 00424 return 0; // factory didn't exist 00425 00426 } // QgsProviderRegistry::setDataProvider 00427 00428 QString QgsProviderRegistry::fileVectorFilters() const 00429 { 00430 return mVectorFileFilters; 00431 } 00432 00433 QString QgsProviderRegistry::databaseDrivers() const 00434 { 00435 return mDatabaseDrivers; 00436 } 00437 00438 QString QgsProviderRegistry::directoryDrivers() const 00439 { 00440 return mDirectoryDrivers; 00441 } 00442 00443 QString QgsProviderRegistry::protocolDrivers() const 00444 { 00445 return mProtocolDrivers; 00446 } 00447 00448 00449 QStringList QgsProviderRegistry::providerList() const 00450 { 00451 QStringList lst; 00452 for ( Providers::const_iterator it = mProviders.begin(); it != mProviders.end(); it++ ) 00453 { 00454 lst.append( it->first ); 00455 } 00456 return lst; 00457 } 00458 00459 00460 const QgsProviderMetadata* QgsProviderRegistry::providerMetadata( const QString& providerKey ) const 00461 { 00462 return findMetadata_( mProviders, providerKey ); 00463 } 00464 00465 00466 /* 00467 QgsDataProvider * 00468 QgsProviderRegistry::openVector( QString const & dataSource, QString const & providerKey ) 00469 { 00470 return getProvider( providerKey, dataSource ); 00471 } // QgsProviderRegistry::openVector 00472 */