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