diff --git a/python/core/auto_generated/qgsprojutils.sip.in b/python/core/auto_generated/qgsprojutils.sip.in index 5b24b957f70a..c505f427679b 100644 --- a/python/core/auto_generated/qgsprojutils.sip.in +++ b/python/core/auto_generated/qgsprojutils.sip.in @@ -29,6 +29,16 @@ Utility functions for working with the proj library. Returns the proj library major version number. %End + static QStringList searchPaths(); +%Docstring +Returns the current list of Proj file search paths. + +.. note:: + + Only available on builds based on Proj >= 6.0. Builds based on + earlier Proj versions will always return an empty list. +%End + }; /************************************************************************ diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp index 023aac5c6bea..b8f17ad74a4c 100644 --- a/src/core/qgsapplication.cpp +++ b/src/core/qgsapplication.cpp @@ -51,6 +51,7 @@ #include "qgslayoutrendercontext.h" #include "qgssqliteutils.h" #include "qgsstyle.h" +#include "qgsprojutils.h" #include "qgsvaliditycheckregistry.h" #include "gps/qgsgpsconnectionregistry.h" @@ -91,6 +92,11 @@ #include // for setting gdal options #include +#if PROJ_VERSION_MAJOR>=6 +#include +#endif + + #define CONN_POOL_MAX_CONCURRENT_CONNS 4 QObject *ABISYM( QgsApplication::mFileOpenEventReceiver ); @@ -295,6 +301,20 @@ void QgsApplication::init( QString profileFolder ) } ABISYM( mSystemEnvVars ) = systemEnvVarMap; +#if PROJ_VERSION_MAJOR>=6 + // append local user-writable folder as a proj search path + QStringList currentProjSearchPaths = QgsProjUtils::searchPaths(); + currentProjSearchPaths.append( qgisSettingsDirPath() + QStringLiteral( "proj" ) ); + const char **newPaths = new const char *[currentProjSearchPaths.length()]; + for ( int i = 0; i < currentProjSearchPaths.count(); ++i ) + { + newPaths[i] = currentProjSearchPaths.at( i ).toUtf8().constData(); + } + proj_context_set_search_paths( nullptr, currentProjSearchPaths.count(), newPaths ); + delete [] newPaths; +#endif + + // allow Qt to search for Qt plugins (e.g. sqldrivers) in our plugin directory QCoreApplication::addLibraryPath( pluginPath() ); diff --git a/src/core/qgsprojutils.cpp b/src/core/qgsprojutils.cpp index eaef05094a0c..9b68c9e37795 100644 --- a/src/core/qgsprojutils.cpp +++ b/src/core/qgsprojutils.cpp @@ -15,7 +15,9 @@ * * ***************************************************************************/ #include "qgsprojutils.h" +#include "qgis.h" #include +#include #if PROJ_VERSION_MAJOR>=6 #include @@ -215,3 +217,32 @@ QStringList QgsProjUtils::nonAvailableGrids( const QString &projDef ) #endif +QStringList QgsProjUtils::searchPaths() +{ +#if PROJ_VERSION_MAJOR >= 6 + const QString path( proj_info().searchpath ); + QStringList paths; +// #ifdef Q_OS_WIN +#if 1 // -- see https://github.com/OSGeo/proj.4/pull/1497 + paths = path.split( ';' ); +#else + paths = path.split( ':' ); +#endif + + QSet existing; + // thin out duplicates from paths -- see https://github.com/OSGeo/proj.4/pull/1498 + QStringList res; + res.reserve( paths.count() ); + for ( const QString &p : qgis::as_const( paths ) ) + { + if ( existing.contains( p ) ) + continue; + + existing.insert( p ); + res << p; + } + return res; +#else + return QStringList(); +#endif +} diff --git a/src/core/qgsprojutils.h b/src/core/qgsprojutils.h index 1a7566cf34f7..42499f24476c 100644 --- a/src/core/qgsprojutils.h +++ b/src/core/qgsprojutils.h @@ -53,6 +53,14 @@ class CORE_EXPORT QgsProjUtils return PROJ_VERSION_MAJOR; } + /** + * Returns the current list of Proj file search paths. + * + * \note Only available on builds based on Proj >= 6.0. Builds based on + * earlier Proj versions will always return an empty list. + */ + static QStringList searchPaths(); + #ifndef SIP_RUN #if PROJ_VERSION_MAJOR >= 6 diff --git a/tests/src/core/testqgsprojutils.cpp b/tests/src/core/testqgsprojutils.cpp index 467579574185..6e39e9fc5099 100644 --- a/tests/src/core/testqgsprojutils.cpp +++ b/tests/src/core/testqgsprojutils.cpp @@ -35,6 +35,7 @@ class TestQgsProjUtils: public QObject void threadSafeContext(); void usesAngularUnits(); void axisOrderIsSwapped(); + void searchPath(); }; @@ -97,5 +98,14 @@ void TestQgsProjUtils::axisOrderIsSwapped() #endif } +void TestQgsProjUtils::searchPath() +{ +#if PROJ_VERSION_MAJOR>=6 + // ensure local user-writable path is present in Proj search paths + const QStringList paths = QgsProjUtils::searchPaths(); + QVERIFY( paths.contains( QgsApplication::qgisSettingsDirPath() + QStringLiteral( "proj" ) ) ); +#endif +} + QGSTEST_MAIN( TestQgsProjUtils ) #include "testqgsprojutils.moc"