From 5511b07e40bb2d11460161c5a9d2624284b6efbe Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 3 May 2017 11:56:40 +1000 Subject: [PATCH] Move memory provider to core This commit introduces basic support for non-library based data providers, and moves the memory provider from a library based provider to a core provider. The memory provider is used so frequently throughout QGIS that it has become integral to QGIS functionality and must be available wherever the QGIS core library is used. The changes here (while not exposed yet to Python) could potentially be built on to allow creation of pure Python data providers. --- doc/CMakeLists.txt | 2 + .../memory/qgsmemoryproviderutils.sip | 34 +++++++++++ src/core/CMakeLists.txt | 9 +++ .../memory/qgsmemoryfeatureiterator.cpp | 4 +- .../memory/qgsmemoryfeatureiterator.h | 4 ++ .../providers/memory/qgsmemoryprovider.cpp | 59 ++++++------------- .../providers/memory/qgsmemoryprovider.h | 10 ++++ .../memory/qgsmemoryproviderutils.cpp | 18 ++++++ .../providers/memory/qgsmemoryproviderutils.h | 38 ++++++++++++ src/core/qgsprovidermetadata.cpp | 11 ++++ src/core/qgsprovidermetadata.h | 55 +++++++++++++---- src/core/qgsproviderregistry.cpp | 40 +++++++++++-- src/core/qgsproviderregistry.h | 1 - src/providers/CMakeLists.txt | 1 - src/providers/memory/CMakeLists.txt | 32 ---------- 15 files changed, 225 insertions(+), 93 deletions(-) create mode 100644 python/core/providers/memory/qgsmemoryproviderutils.sip rename src/{ => core}/providers/memory/qgsmemoryfeatureiterator.cpp (99%) rename src/{ => core}/providers/memory/qgsmemoryfeatureiterator.h (98%) rename src/{ => core}/providers/memory/qgsmemoryprovider.cpp (95%) rename src/{ => core}/providers/memory/qgsmemoryprovider.h (93%) create mode 100644 src/core/providers/memory/qgsmemoryproviderutils.cpp create mode 100644 src/core/providers/memory/qgsmemoryproviderutils.h delete mode 100644 src/providers/memory/CMakeLists.txt diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index c29865b782f..9fc9564780c 100755 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -66,6 +66,8 @@ IF(WITH_APIDOC) ${CMAKE_SOURCE_DIR}/src/core/metadata ${CMAKE_SOURCE_DIR}/src/core/pal ${CMAKE_SOURCE_DIR}/src/core/processing + ${CMAKE_SOURCE_DIR}/src/core/providers + ${CMAKE_SOURCE_DIR}/src/core/providers/memory ${CMAKE_SOURCE_DIR}/src/core/raster ${CMAKE_SOURCE_DIR}/src/core/scalebar ${CMAKE_SOURCE_DIR}/src/core/symbology-ng diff --git a/python/core/providers/memory/qgsmemoryproviderutils.sip b/python/core/providers/memory/qgsmemoryproviderutils.sip new file mode 100644 index 00000000000..74a6cd7d4e2 --- /dev/null +++ b/python/core/providers/memory/qgsmemoryproviderutils.sip @@ -0,0 +1,34 @@ +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/providers/memory/qgsmemoryproviderutils.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ + + + + +class QgsMemoryProviderUtils +{ +%Docstring + Utility functions for use with the memory vector data provider. +.. versionadded:: 3.0 +%End + +%TypeHeaderCode +#include "qgsmemoryproviderutils.h" +%End + public: + +}; + + + +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/providers/memory/qgsmemoryproviderutils.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 296e357cac0..cdbbea53869 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -92,6 +92,9 @@ SET(QGIS_CORE_SRCS processing/qgsprocessingregistry.cpp processing/qgsprocessingutils.cpp + providers/memory/qgsmemoryfeatureiterator.cpp + providers/memory/qgsmemoryprovider.cpp + scalebar/qgsdoubleboxscalebarrenderer.cpp scalebar/qgsnumericscalebarrenderer.cpp scalebar/qgsscalebarrenderer.cpp @@ -618,6 +621,8 @@ SET(QGIS_CORE_MOC_HDRS processing/qgsprocessingprovider.h processing/qgsprocessingregistry.h + providers/memory/qgsmemoryprovider.h + raster/qgsrasterfilewritertask.h raster/qgsrasterlayer.h raster/qgsrasterdataprovider.h @@ -866,6 +871,8 @@ SET(QGIS_CORE_HDRS processing/qgsprocessingcontext.h processing/qgsprocessingutils.h + providers/memory/qgsmemoryfeatureiterator.h + raster/qgsbilinearrasterresampler.h raster/qgsbrightnesscontrastfilter.h raster/qgscliptominmaxenhancement.h @@ -1001,6 +1008,8 @@ INCLUDE_DIRECTORIES( metadata pal processing + providers + providers/memory raster renderer scalebar diff --git a/src/providers/memory/qgsmemoryfeatureiterator.cpp b/src/core/providers/memory/qgsmemoryfeatureiterator.cpp similarity index 99% rename from src/providers/memory/qgsmemoryfeatureiterator.cpp rename to src/core/providers/memory/qgsmemoryfeatureiterator.cpp index 8acc842133c..614060b482c 100644 --- a/src/providers/memory/qgsmemoryfeatureiterator.cpp +++ b/src/core/providers/memory/qgsmemoryfeatureiterator.cpp @@ -21,7 +21,7 @@ #include "qgsmessagelog.h" #include "qgsproject.h" - +///@cond PRIVATE QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryFeatureSource *source, bool ownSource, const QgsFeatureRequest &request ) : QgsAbstractFeatureIteratorFromSource( source, ownSource, request ) @@ -223,3 +223,5 @@ QgsFeatureIterator QgsMemoryFeatureSource::getFeatures( const QgsFeatureRequest { return QgsFeatureIterator( new QgsMemoryFeatureIterator( this, false, request ) ); } + +///@endcond PRIVATE diff --git a/src/providers/memory/qgsmemoryfeatureiterator.h b/src/core/providers/memory/qgsmemoryfeatureiterator.h similarity index 98% rename from src/providers/memory/qgsmemoryfeatureiterator.h rename to src/core/providers/memory/qgsmemoryfeatureiterator.h index c2e883bd959..fe31c238cfb 100644 --- a/src/providers/memory/qgsmemoryfeatureiterator.h +++ b/src/core/providers/memory/qgsmemoryfeatureiterator.h @@ -20,6 +20,8 @@ #include "qgsfields.h" #include "qgsgeometry.h" +///@cond PRIVATE + class QgsMemoryProvider; typedef QMap QgsFeatureMap; @@ -72,4 +74,6 @@ class QgsMemoryFeatureIterator : public QgsAbstractFeatureIteratorFromSource #include +///@cond PRIVATE static const QString TEXT_PROVIDER_KEY = QStringLiteral( "memory" ); static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "Memory provider" ); @@ -190,6 +191,21 @@ QgsMemoryProvider::~QgsMemoryProvider() delete mSpatialIndex; } +QString QgsMemoryProvider::providerKey() +{ + return TEXT_PROVIDER_KEY; +} + +QString QgsMemoryProvider::providerDescription() +{ + return TEXT_PROVIDER_DESCRIPTION; +} + +QgsMemoryProvider *QgsMemoryProvider::createProvider( const QString &uri ) +{ + return new QgsMemoryProvider( uri ); +} + QgsAbstractFeatureSource *QgsMemoryProvider::featureSource() const { return new QgsMemoryFeatureSource( this ); @@ -523,52 +539,15 @@ void QgsMemoryProvider::updateExtent() } } - - -// -------------------------------- - -QString QgsMemoryProvider::name() const +QString QgsMemoryProvider::name() const { return TEXT_PROVIDER_KEY; } -QString QgsMemoryProvider::description() const +QString QgsMemoryProvider::description() const { return TEXT_PROVIDER_DESCRIPTION; } -// -------------------------------- - -/** - * Class factory to return a pointer to a newly created - * QgsMemoryProvider object - */ -QGISEXTERN QgsMemoryProvider *classFactory( const QString *uri ) -{ - return new QgsMemoryProvider( *uri ); -} - -/** Required key function (used to map the plugin to a data store type) - */ -QGISEXTERN QString providerKey() -{ - return TEXT_PROVIDER_KEY; -} - -/** - * Required description function - */ -QGISEXTERN QString description() -{ - return TEXT_PROVIDER_DESCRIPTION; -} - -/** - * Required isProvider function. Used to determine if this shared library - * is a data provider plugin - */ -QGISEXTERN bool isProvider() -{ - return true; -} +///@endcond diff --git a/src/providers/memory/qgsmemoryprovider.h b/src/core/providers/memory/qgsmemoryprovider.h similarity index 93% rename from src/providers/memory/qgsmemoryprovider.h rename to src/core/providers/memory/qgsmemoryprovider.h index 30a5c1f6af4..267a9dcce13 100644 --- a/src/providers/memory/qgsmemoryprovider.h +++ b/src/core/providers/memory/qgsmemoryprovider.h @@ -17,6 +17,7 @@ #include "qgscoordinatereferencesystem.h" #include "qgsfields.h" +///@cond PRIVATE typedef QMap QgsFeatureMap; class QgsSpatialIndex; @@ -32,6 +33,13 @@ class QgsMemoryProvider : public QgsVectorDataProvider virtual ~QgsMemoryProvider(); + //! Returns the memory provider key + static QString providerKey(); + //! Returns the memory provider description + static QString providerDescription(); + + static QgsMemoryProvider *createProvider( const QString &uri ); + /* Implementation of functions from QgsVectorDataProvider */ virtual QgsAbstractFeatureSource *featureSource() const override; @@ -88,3 +96,5 @@ class QgsMemoryProvider : public QgsVectorDataProvider friend class QgsMemoryFeatureSource; }; + +///@endcond diff --git a/src/core/providers/memory/qgsmemoryproviderutils.cpp b/src/core/providers/memory/qgsmemoryproviderutils.cpp new file mode 100644 index 00000000000..e5ae7341dc1 --- /dev/null +++ b/src/core/providers/memory/qgsmemoryproviderutils.cpp @@ -0,0 +1,18 @@ +/*************************************************************************** + qgsmemoryproviderutils.cpp + -------------------------- + begin : May 2017 + copyright : (C) 2017 by Nyall Dawson + email : nyall dot dawson at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsmemoryproviderutils.h" diff --git a/src/core/providers/memory/qgsmemoryproviderutils.h b/src/core/providers/memory/qgsmemoryproviderutils.h new file mode 100644 index 00000000000..261cbf4a58f --- /dev/null +++ b/src/core/providers/memory/qgsmemoryproviderutils.h @@ -0,0 +1,38 @@ +/*************************************************************************** + qgsmemoryproviderutils.h + ------------------------ + begin : May 2017 + copyright : (C) 2017 by Nyall Dawson + email : nyall dot dawson at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMEMORYPROVIDERUTILS_H +#define QGSMEMORYPROVIDERUTILS_H + +#include "qgis_core.h" + +/** + * \class QgsMemoryProviderUtils + * \ingroup core + * Utility functions for use with the memory vector data provider. + * \since QGIS 3.0 + */ +class CORE_EXPORT QgsMemoryProviderUtils +{ + + public: + +}; + +#endif // QGSMEMORYPROVIDERUTILS_H + + diff --git a/src/core/qgsprovidermetadata.cpp b/src/core/qgsprovidermetadata.cpp index ac89a3ae416..59a7769fd6b 100644 --- a/src/core/qgsprovidermetadata.cpp +++ b/src/core/qgsprovidermetadata.cpp @@ -28,6 +28,12 @@ QgsProviderMetadata::QgsProviderMetadata( QString const &_key, , library_( _library ) {} +QgsProviderMetadata::QgsProviderMetadata( const QString &key, const QString &description, QgsProviderMetadata::CreateDataProviderFunction createFunc ) + : key_( key ) + , description_( description ) + , mCreateFunc( createFunc ) +{} + QString QgsProviderMetadata::key() const { return key_; @@ -42,3 +48,8 @@ QString QgsProviderMetadata::library() const { return library_; } + +QgsProviderMetadata::CreateDataProviderFunction QgsProviderMetadata::createFunction() const +{ + return mCreateFunc; +} diff --git a/src/core/qgsprovidermetadata.h b/src/core/qgsprovidermetadata.h index 40e0bdb0127..f2e0d03824b 100644 --- a/src/core/qgsprovidermetadata.h +++ b/src/core/qgsprovidermetadata.h @@ -21,27 +21,48 @@ #include - +#include "qgis.h" #include "qgis_core.h" +#include + +class QgsDataProvider; /** \ingroup core - * Holds data provider key, description, and associated shared library file information. - - The metadata class is used in a lazy load implementation in - QgsProviderRegistry. To save memory, data providers are only actually - loaded via QLibrary calls if they're to be used. (Though they're all - iteratively loaded once to get their metadata information, and then - unloaded when the QgsProviderRegistry is created.) QgsProviderMetadata - supplies enough information to be able to later load the associated shared - library object. - + * Holds data provider key, description, and associated shared library file or function pointer information. + * + * Provider metadata refers either to providers which are loaded via libraries or + * which are native providers that are included in the core QGIS installation + * and accessed through function pointers. + * + * For library based providers, the metadata class is used in a lazy load + * implementation in QgsProviderRegistry. To save memory, data providers + * are only actually loaded via QLibrary calls if they're to be used. (Though they're all + * iteratively loaded once to get their metadata information, and then + * unloaded when the QgsProviderRegistry is created.) QgsProviderMetadata + * supplies enough information to be able to later load the associated shared + * library object. + * */ class CORE_EXPORT QgsProviderMetadata { public: + /** + * Typedef for data provider creation function. + * \since QGIS 3.0 + */ + SIP_SKIP typedef std::function < QgsDataProvider*( const QString & ) > CreateDataProviderFunction; + QgsProviderMetadata( const QString &_key, const QString &_description, const QString &_library ); + /** + * Metadata for provider with direct provider creation function pointer, where + * no library is involved. + * \since QGIS 3.0 + * \note not available in Python bindings + */ + SIP_SKIP QgsProviderMetadata( const QString &key, const QString &description, QgsProviderMetadata::CreateDataProviderFunction createFunc ); + /** This returns the unique key associated with the provider This key string is used for the associative container in QgsProviderRegistry @@ -60,6 +81,14 @@ class CORE_EXPORT QgsProviderMetadata */ QString library() const; + /** + * Returns a pointer to the direct provider creation function, if supported + * by the provider. + * \since QGIS 3.0 + * \note not available in Python bindings + */ + SIP_SKIP CreateDataProviderFunction createFunction() const; + private: /// unique key for data provider @@ -71,7 +100,9 @@ class CORE_EXPORT QgsProviderMetadata /// file path QString library_; -}; // class QgsProviderMetadata + CreateDataProviderFunction mCreateFunc = nullptr; + +}; #endif //QGSPROVIDERMETADATA_H diff --git a/src/core/qgsproviderregistry.cpp b/src/core/qgsproviderregistry.cpp index 4a5b3834b31..023e6c5d15e 100644 --- a/src/core/qgsproviderregistry.cpp +++ b/src/core/qgsproviderregistry.cpp @@ -30,6 +30,7 @@ #include "qgsprovidermetadata.h" #include "qgsvectorlayer.h" #include "qgsproject.h" +#include "providers/memory/qgsmemoryprovider.h" // typedefs for provider plugin functions of interest @@ -75,6 +76,9 @@ QgsProviderRegistry::QgsProviderRegistry( const QString &pluginPath ) void QgsProviderRegistry::init() { + // add standard providers + mProviders[ QgsMemoryProvider::providerKey() ] = new QgsProviderMetadata( QgsMemoryProvider::providerKey(), QgsMemoryProvider::providerDescription(), &QgsMemoryProvider::createProvider ); + mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase ); mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks ); @@ -233,16 +237,20 @@ void QgsProviderRegistry::clean() { QgsDebugMsg( QString( "cleanup:%1" ).arg( it->first ) ); QString lib = it->second->library(); - QLibrary myLib( lib ); - if ( myLib.isLoaded() ) + if ( !lib.isEmpty() ) { - cleanupProviderFunction_t *cleanupFunc = reinterpret_cast< cleanupProviderFunction_t * >( cast_to_fptr( myLib.resolve( "cleanupProvider" ) ) ); - if ( cleanupFunc ) - cleanupFunc(); + QLibrary myLib( lib ); + if ( myLib.isLoaded() ) + { + cleanupProviderFunction_t *cleanupFunc = reinterpret_cast< cleanupProviderFunction_t * >( cast_to_fptr( myLib.resolve( "cleanupProvider" ) ) ); + if ( cleanupFunc ) + cleanupFunc(); + } } delete it->second; ++it; } + mProviders.clear(); } QgsProviderRegistry::~QgsProviderRegistry() @@ -351,6 +359,18 @@ QgsDataProvider *QgsProviderRegistry::provider( QString const &providerKey, QStr // XXX should I check for and possibly delete any pre-existing providers? // XXX How often will that scenario occur? + const QgsProviderMetadata *metadata = providerMetadata( providerKey ); + if ( !metadata ) + { + QgsMessageLog::logMessage( QObject::tr( "Invalid data provider %1" ).arg( providerKey ) ); + return nullptr; + } + + if ( metadata->createFunction() ) + { + return metadata->createFunction()( dataSource ); + } + // load the plugin QString lib = library( providerKey ); @@ -435,6 +455,10 @@ QWidget *QgsProviderRegistry::selectWidget( const QString &providerKey, QFunctionPointer QgsProviderRegistry::function( QString const &providerKey, QString const &functionName ) { + QString lib = library( providerKey ); + if ( lib.isEmpty() ) + return nullptr; + QLibrary myLib( library( providerKey ) ); QgsDebugMsg( "Library name is " + myLib.fileName() ); @@ -452,7 +476,11 @@ QFunctionPointer QgsProviderRegistry::function( QString const &providerKey, QLibrary *QgsProviderRegistry::providerLibrary( QString const &providerKey ) const { - std::unique_ptr< QLibrary > myLib( new QLibrary( library( providerKey ) ) ); + QString lib = library( providerKey ); + if ( lib.isEmpty() ) + return nullptr; + + std::unique_ptr< QLibrary > myLib( new QLibrary( lib ) ); QgsDebugMsg( "Library name is " + myLib->fileName() ); diff --git a/src/core/qgsproviderregistry.h b/src/core/qgsproviderregistry.h index 94efba0f78d..04d7779a380 100644 --- a/src/core/qgsproviderregistry.h +++ b/src/core/qgsproviderregistry.h @@ -52,7 +52,6 @@ class CORE_EXPORT QgsProviderRegistry //! Means of accessing canonical single instance static QgsProviderRegistry *instance( const QString &pluginPath = QString::null ); - //! Virtual dectructor virtual ~QgsProviderRegistry(); //! Return path for the library of the provider diff --git a/src/providers/CMakeLists.txt b/src/providers/CMakeLists.txt index c63c512ec78..95171db24de 100644 --- a/src/providers/CMakeLists.txt +++ b/src/providers/CMakeLists.txt @@ -3,7 +3,6 @@ SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/${QGIS_PLUGIN_SUBDI SET (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/${QGIS_PLUGIN_SUBDIR}) ADD_SUBDIRECTORY(arcgisrest) -ADD_SUBDIRECTORY(memory) ADD_SUBDIRECTORY(ogr) ADD_SUBDIRECTORY(wms) ADD_SUBDIRECTORY(delimitedtext) diff --git a/src/providers/memory/CMakeLists.txt b/src/providers/memory/CMakeLists.txt deleted file mode 100644 index e3e0e42d7c5..00000000000 --- a/src/providers/memory/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ - -SET (MEMORY_SRCS qgsmemoryprovider.cpp qgsmemoryfeatureiterator.cpp) - -INCLUDE_DIRECTORIES( - . - ../../core - ../../core/geometry - ${CMAKE_BINARY_DIR}/src/core -) -INCLUDE_DIRECTORIES(SYSTEM - ${GEOS_INCLUDE_DIR} -) - -QT5_WRAP_CPP(MEMORY_MOC_SRCS qgsmemoryprovider.h) -ADD_LIBRARY(memoryprovider MODULE ${MEMORY_SRCS} ${MEMORY_MOC_SRCS}) - -TARGET_LINK_LIBRARIES(memoryprovider - qgis_core -) - -# clang-tidy -IF(CLANG_TIDY_EXE) - SET_TARGET_PROPERTIES( - memoryprovider PROPERTIES - CXX_CLANG_TIDY "${DO_CLANG_TIDY}" - ) -ENDIF(CLANG_TIDY_EXE) - - -INSTALL (TARGETS memoryprovider - RUNTIME DESTINATION ${QGIS_PLUGIN_DIR} - LIBRARY DESTINATION ${QGIS_PLUGIN_DIR})