From 118c956cff65d37768aefeecd0219d3f5b75c4dc Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Mon, 19 Dec 2022 16:54:27 +0100 Subject: [PATCH] Add SLD export context --- python/core/auto_additions/qgis.py | 15 +++++ python/core/auto_generated/qgis.sip.in | 16 +++++ python/core/auto_generated/qgsmaplayer.sip.in | 30 +++++++++ .../auto_generated/qgssldexportcontext.sip.in | 54 ++++++++++++++++ python/core/core_auto.sip | 1 + src/core/CMakeLists.txt | 2 + src/core/maprenderer/qgsmaprendererjob.cpp | 1 + src/core/qgis.h | 28 ++++++++ src/core/qgsmaplayer.cpp | 41 +++++++++--- src/core/qgsmaplayer.h | 26 +++++++- src/core/qgssldexportcontext.cpp | 54 ++++++++++++++++ src/core/qgssldexportcontext.h | 64 +++++++++++++++++++ 12 files changed, 323 insertions(+), 9 deletions(-) create mode 100644 python/core/auto_generated/qgssldexportcontext.sip.in create mode 100644 src/core/qgssldexportcontext.cpp create mode 100644 src/core/qgssldexportcontext.h diff --git a/python/core/auto_additions/qgis.py b/python/core/auto_additions/qgis.py index aaf3d6d0e67..5778cc894bf 100644 --- a/python/core/auto_additions/qgis.py +++ b/python/core/auto_additions/qgis.py @@ -180,6 +180,21 @@ Qgis.SettingsType.__doc__ = 'Types of settings entries\n\n.. versionadded:: 3.26 # -- Qgis.SettingsType.baseClass = Qgis # monkey patching scoped based enum +Qgis.SldExportOption.NoOptions.__doc__ = "Default SLD export" +Qgis.SldExportOption.Svg.__doc__ = "Export complex styles to separate SVG files for better compatibility with OGC servers" +Qgis.SldExportOption.__doc__ = 'SLD export options\n\n.. versionadded:: 3.30\n\n' + '* ``NoOptions``: ' + Qgis.SldExportOption.NoOptions.__doc__ + '\n' + '* ``Svg``: ' + Qgis.SldExportOption.Svg.__doc__ +# -- +Qgis.SldExportOption.baseClass = Qgis +Qgis.SldExportOptions.baseClass = Qgis +SldExportOptions = Qgis # dirty hack since SIP seems to introduce the flags in module +# monkey patching scoped based enum +Qgis.SldExportVendorExtension.NoVendorExtension.__doc__ = "No vendor extensions" +Qgis.SldExportVendorExtension.GeoServerVendorExtension.__doc__ = "Use GeoServer vendor extensions when required" +Qgis.SldExportVendorExtension.DeegreeVendorExtension.__doc__ = "Use Deegree vendor extensions when required" +Qgis.SldExportVendorExtension.__doc__ = 'SLD export vendor extensions, allow the use of vendor extensions when exporting to SLD.\n\n.. versionadded:: 3.30\n\n' + '* ``NoVendorExtension``: ' + Qgis.SldExportVendorExtension.NoVendorExtension.__doc__ + '\n' + '* ``GeoServerVendorExtension``: ' + Qgis.SldExportVendorExtension.GeoServerVendorExtension.__doc__ + '\n' + '* ``DeegreeVendorExtension``: ' + Qgis.SldExportVendorExtension.DeegreeVendorExtension.__doc__ +# -- +Qgis.SldExportVendorExtension.baseClass = Qgis +# monkey patching scoped based enum Qgis.SettingsOption.SaveFormerValue.__doc__ = "" Qgis.SettingsOption.SaveEnumFlagAsInt.__doc__ = "" Qgis.SettingsOption.__doc__ = 'Settings options\n\n.. versionadded:: 3.26\n\n' + '* ``SaveFormerValue``: ' + Qgis.SettingsOption.SaveFormerValue.__doc__ + '\n' + '* ``SaveEnumFlagAsInt``: ' + Qgis.SettingsOption.SaveEnumFlagAsInt.__doc__ diff --git a/python/core/auto_generated/qgis.sip.in b/python/core/auto_generated/qgis.sip.in index cb60ca6cab3..e3c1d7572f9 100644 --- a/python/core/auto_generated/qgis.sip.in +++ b/python/core/auto_generated/qgis.sip.in @@ -161,6 +161,22 @@ The development version Color }; + enum class SldExportOption + { + NoOptions, + Svg, + }; + typedef QFlags SldExportOptions; + + + enum class SldExportVendorExtension + { + NoVendorExtension, + GeoServerVendorExtension, + DeegreeVendorExtension, + }; + + enum class SettingsOption { SaveFormerValue, diff --git a/python/core/auto_generated/qgsmaplayer.sip.in b/python/core/auto_generated/qgsmaplayer.sip.in index f715f70bad6..3a4e5e2c6f8 100644 --- a/python/core/auto_generated/qgsmaplayer.sip.in +++ b/python/core/auto_generated/qgsmaplayer.sip.in @@ -982,6 +982,18 @@ Export the properties of this layer as SLD style in a QDomDocument during the execution of writeSymbology %End + virtual void exportSldStyleV2( QDomDocument &doc, QString &errorMsg, const QgsSldExportContext &exportContext ) const; +%Docstring +Export the properties of this layer as SLD style in a QDomDocument + +:param doc: the target QDomDocument +:param errorMsg: this QString will be initialized on error + during the execution of writeSymbology +:param exportContext: SLD export context + +.. versionadded:: 3.30 +%End + virtual QString saveDefaultStyle( bool &resultFlag /Out/, StyleCategories categories ); %Docstring Save the properties of this layer as the default style @@ -1040,6 +1052,24 @@ Saves the properties of this layer to an SLD format file. :return: a string with any status or error messages +.. seealso:: :py:func:`loadSldStyle` + +.. seealso:: :py:func:`saveSldStyleV2` +%End + + virtual QString saveSldStyleV2( const QString &uri, bool &resultFlag, const QgsSldExportContext &exportContext ) const; +%Docstring +Saves the properties of this layer to an SLD format file. + +:param uri: uri of destination for exported SLD file. +:param resultFlag: a reference to a flag that will be set to ``False`` if + the SLD file could not be generated +:param exportContext: SLD export context + +:return: a string with any status or error messages + +.. versionadded:: 3.30 + .. seealso:: :py:func:`loadSldStyle` %End diff --git a/python/core/auto_generated/qgssldexportcontext.sip.in b/python/core/auto_generated/qgssldexportcontext.sip.in new file mode 100644 index 00000000000..3b23016098f --- /dev/null +++ b/python/core/auto_generated/qgssldexportcontext.sip.in @@ -0,0 +1,54 @@ +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/qgssldexportcontext.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ + + +class QgsSldExportContext +{ +%Docstring(signature="appended") +/ingroup core +/brief The :py:class:`QgsSldExportContext` class holds SLD export options and other information related to SLD export of a QGIS layer style. + +/since QGIS 3.30 +%End + +%TypeHeaderCode +#include "qgssldexportcontext.h" +%End + public: + + QgsSldExportContext(); + ~QgsSldExportContext(); + QgsSldExportContext( const QgsSldExportContext &other ); + + QgsSldExportContext( const Qgis::SldExportOptions &options, const Qgis::SldExportVendorExtension &vendorExtension, const QString &filePath ); +%Docstring +/brief Create a new QgsSldExportContext +/param options SLD export options +/param vendorExtension SLD export vendor extension +/param filePath SLD export file path +%End + + Qgis::SldExportOptions exportOptions() const; + void setExportOptions( const Qgis::SldExportOptions &exportOptions ); + + Qgis::SldExportVendorExtension vendorExtensions() const; + void setVendorExtensions( const Qgis::SldExportVendorExtension &vendorExtensions ); + + QString exportFilePath() const; + void setExportFilePath( const QString &exportFilePath ); + +}; + + +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/qgssldexportcontext.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ diff --git a/python/core/core_auto.sip b/python/core/core_auto.sip index 671e81cc71f..1154dd0e9bc 100644 --- a/python/core/core_auto.sip +++ b/python/core/core_auto.sip @@ -166,6 +166,7 @@ %Include auto_generated/qgsselectioncontext.sip %Include auto_generated/qgssimplifymethod.sip %Include auto_generated/qgssingleitemmodel.sip +%Include auto_generated/qgssldexportcontext.sip %Include auto_generated/qgssnappingconfig.sip %Include auto_generated/qgssnappingutils.sip %Include auto_generated/qgsspatialindex.sip diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7f107207020..50792f2c674 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -498,6 +498,7 @@ set(QGIS_CORE_SRCS qgsshapegenerator.cpp qgssimplifymethod.cpp qgssingleitemmodel.cpp + qgssldexportcontext.cpp qgssnappingutils.cpp qgsspatialindex.cpp qgsspatialindexkdbush.cpp @@ -1177,6 +1178,7 @@ set(QGIS_CORE_HDRS qgsshapegenerator.h qgssimplifymethod.h qgssingleitemmodel.h + qgssldexportcontext.h qgssnappingconfig.h qgssnappingutils.h qgsspatialindex.h diff --git a/src/core/maprenderer/qgsmaprendererjob.cpp b/src/core/maprenderer/qgsmaprendererjob.cpp index 968709ac9d4..5542bc5333f 100644 --- a/src/core/maprenderer/qgsmaprendererjob.cpp +++ b/src/core/maprenderer/qgsmaprendererjob.cpp @@ -41,6 +41,7 @@ #include "qgssymbollayerutils.h" #include "qgsmaplayertemporalproperties.h" #include "qgsmaplayerelevationproperties.h" +#include "qgsmaplayerstyle.h" #include "qgsvectorlayerrenderer.h" #include "qgsrendereditemresults.h" #include "qgsmaskpaintdevice.h" diff --git a/src/core/qgis.h b/src/core/qgis.h index ea7e5b4630d..8d5062e0d82 100644 --- a/src/core/qgis.h +++ b/src/core/qgis.h @@ -241,6 +241,34 @@ class CORE_EXPORT Qgis }; Q_ENUM( SettingsType ) + /** + * \brief SLD export options + * + * \since QGIS 3.30 + */ + enum class SldExportOption : int + { + NoOptions = 0, //!< Default SLD export + Svg = 1 << 0, //!< Export complex styles to separate SVG files for better compatibility with OGC servers + }; + Q_ENUM( SldExportOption ) + Q_DECLARE_FLAGS( SldExportOptions, SldExportOption ) + Q_FLAG( SldExportOptions ) + + /** + * \brief SLD export vendor extensions, allow the use of vendor extensions when exporting to SLD. + * + * \since QGIS 3.30 + */ + enum class SldExportVendorExtension : int + { + NoVendorExtension = 0, //!< No vendor extensions + GeoServerVendorExtension = 1 << 1, //!< Use GeoServer vendor extensions when required + DeegreeVendorExtension = 1 << 2, //!< Use Deegree vendor extensions when required + }; + Q_ENUM( SldExportVendorExtension ) + + /** * Settings options * \since QGIS 3.26 diff --git a/src/core/qgsmaplayer.cpp b/src/core/qgsmaplayer.cpp index 946fb8e05db..3298595b102 100644 --- a/src/core/qgsmaplayer.cpp +++ b/src/core/qgsmaplayer.cpp @@ -35,6 +35,7 @@ #include "qgsrasterlayer.h" #include "qgsreadwritecontext.h" #include "qgsrectangle.h" +#include "qgssldexportcontext.h" #include "qgsvectorlayer.h" #include "qgsxmlutils.h" #include "qgsstringutils.h" @@ -1756,6 +1757,11 @@ QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag, Style } void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const +{ + return exportSldStyleV2( doc, errorMsg, QgsSldExportContext() ); +} + +void QgsMapLayer::exportSldStyleV2( QDomDocument &doc, QString &errorMsg, const QgsSldExportContext &exportContext ) const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS @@ -1807,6 +1813,12 @@ void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const } QVariantMap props; + + QVariant context; + context.setValue( exportContext ); + + props[ QStringLiteral( "SldExportContext" ) ] = context; + if ( hasScaleBasedVisibility() ) { props[ QStringLiteral( "scaleMinDenom" ) ] = QString::number( mMinScale ); @@ -1835,19 +1847,17 @@ void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const } QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const +{ + return saveSldStyleV2( uri, resultFlag, QgsSldExportContext() ); +} + +QString QgsMapLayer::saveSldStyleV2( const QString &uri, bool &resultFlag, const QgsSldExportContext &exportContext ) const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS const QgsMapLayer *mlayer = qobject_cast( this ); - QString errorMsg; - QDomDocument myDocument; - mlayer->exportSldStyle( myDocument, errorMsg ); - if ( !errorMsg.isNull() ) - { - resultFlag = false; - return errorMsg; - } + // check if the uri is a file or ends with .sld, // which indicates that it should become one QString filename; @@ -1885,6 +1895,20 @@ QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const // now construct the file name for our .sld style file const QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld"; + QString errorMsg; + QDomDocument myDocument; + + QgsSldExportContext context { exportContext }; + context.setExportFilePath( myFileName ); + + mlayer->exportSldStyleV2( myDocument, errorMsg, context ); + + if ( !errorMsg.isNull() ) + { + resultFlag = false; + return errorMsg; + } + QFile myFile( myFileName ); if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) ) { @@ -1899,6 +1923,7 @@ QString QgsMapLayer::saveSldStyle( const QString &uri, bool &resultFlag ) const resultFlag = false; return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename ); + } QString QgsMapLayer::loadSldStyle( const QString &uri, bool &resultFlag ) diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h index 9b8655f5ac3..b95285b1e42 100644 --- a/src/core/qgsmaplayer.h +++ b/src/core/qgsmaplayer.h @@ -37,7 +37,6 @@ #include "qgsmaplayerdependency.h" #include "qgslayermetadata.h" #include "qgsmaplayerserverproperties.h" -#include "qgsmaplayerstyle.h" #include "qgsreadwritecontext.h" #include "qgsdataprovider.h" #include "qgis.h" @@ -52,6 +51,7 @@ class QgsProject; class QgsStyleEntityVisitorInterface; class QgsMapLayerTemporalProperties; class QgsMapLayerElevationProperties; +class QgsSldExportContext; class QDomDocument; class QKeyEvent; @@ -1098,6 +1098,16 @@ class CORE_EXPORT QgsMapLayer : public QObject */ virtual void exportSldStyle( QDomDocument &doc, QString &errorMsg ) const; + /** + * Export the properties of this layer as SLD style in a QDomDocument + * \param doc the target QDomDocument + * \param errorMsg this QString will be initialized on error + * during the execution of writeSymbology + * \param exportContext SLD export context + * \since QGIS 3.30 + */ + virtual void exportSldStyleV2( QDomDocument &doc, QString &errorMsg, const QgsSldExportContext &exportContext ) const; + /** * Save the properties of this layer as the default style * (either as a .qml file on disk or as a @@ -1146,9 +1156,23 @@ class CORE_EXPORT QgsMapLayer : public QObject * the SLD file could not be generated * \returns a string with any status or error messages * \see loadSldStyle() + * \see saveSldStyleV2() */ virtual QString saveSldStyle( const QString &uri, bool &resultFlag ) const; + /** + * Saves the properties of this layer to an SLD format file. + * \param uri uri of destination for exported SLD file. + * \param resultFlag a reference to a flag that will be set to FALSE if + * the SLD file could not be generated + * \param exportContext SLD export context + * \returns a string with any status or error messages + * + * \since QGIS 3.30 + * \see loadSldStyle() + */ + virtual QString saveSldStyleV2( const QString &uri, bool &resultFlag, const QgsSldExportContext &exportContext ) const; + /** * Attempts to style the layer using the formatting from an SLD type file. * \param uri uri of source SLD file diff --git a/src/core/qgssldexportcontext.cpp b/src/core/qgssldexportcontext.cpp new file mode 100644 index 00000000000..89d19649321 --- /dev/null +++ b/src/core/qgssldexportcontext.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + qgssldexportcontext.cpp - QgsSldExportContext + + --------------------- + begin : 21.12.2022 + copyright : (C) 2022 by Alessandro Pasotti + email : elpaso at itopen dot it + *************************************************************************** + * * + * 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 "qgssldexportcontext.h" + +QgsSldExportContext::QgsSldExportContext( const Qgis::SldExportOptions &options, const Qgis::SldExportVendorExtension &vendorExtension, const QString &filePath ) + : mExportOptions( options ) + , mVendorExtensions( vendorExtension ) + , mExportFilePath( filePath ) +{ + +} + +Qgis::SldExportOptions QgsSldExportContext::exportOptions() const +{ + return mExportOptions; +} + +void QgsSldExportContext::setExportOptions( const Qgis::SldExportOptions &exportOptions ) +{ + mExportOptions = exportOptions; +} + +Qgis::SldExportVendorExtension QgsSldExportContext::vendorExtensions() const +{ + return mVendorExtensions; +} + +void QgsSldExportContext::setVendorExtensions( const Qgis::SldExportVendorExtension &vendorExtensions ) +{ + mVendorExtensions = vendorExtensions; +} + +QString QgsSldExportContext::exportFilePath() const +{ + return mExportFilePath; +} + +void QgsSldExportContext::setExportFilePath( const QString &exportFilePath ) +{ + mExportFilePath = exportFilePath; +} diff --git a/src/core/qgssldexportcontext.h b/src/core/qgssldexportcontext.h new file mode 100644 index 00000000000..29fcae270da --- /dev/null +++ b/src/core/qgssldexportcontext.h @@ -0,0 +1,64 @@ +/*************************************************************************** + qgssldexportcontext.h - QgsSldExportContext + + --------------------- + begin : 21.12.2022 + copyright : (C) 2022 by Alessandro Pasotti + email : elpaso at itopen dot it + *************************************************************************** + * * + * 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 QGSSLDEXPORTCONTEXT_H +#define QGSSLDEXPORTCONTEXT_H + +#include "qgis.h" +#include "qgis_core.h" + +/** + * /ingroup core + * /brief The QgsSldExportContext class holds SLD export options and other information related to SLD export of a QGIS layer style. + * + * /since QGIS 3.30 + */ +class CORE_EXPORT QgsSldExportContext +{ + public: + + QgsSldExportContext() = default; + ~QgsSldExportContext() = default; + QgsSldExportContext( const QgsSldExportContext &other ) = default; + QgsSldExportContext &operator=( const QgsSldExportContext &other ) = default; + + /** + * /brief Create a new QgsSldExportContext + * /param options SLD export options + * /param vendorExtension SLD export vendor extension + * /param filePath SLD export file path + */ + QgsSldExportContext( const Qgis::SldExportOptions &options, const Qgis::SldExportVendorExtension &vendorExtension, const QString &filePath ); + + Qgis::SldExportOptions exportOptions() const; + void setExportOptions( const Qgis::SldExportOptions &exportOptions ); + + Qgis::SldExportVendorExtension vendorExtensions() const; + void setVendorExtensions( const Qgis::SldExportVendorExtension &vendorExtensions ); + + QString exportFilePath() const; + void setExportFilePath( const QString &exportFilePath ); + + private: + + Qgis::SldExportOptions mExportOptions = Qgis::SldExportOption::NoOptions; + Qgis::SldExportVendorExtension mVendorExtensions = Qgis::SldExportVendorExtension::NoVendorExtension; + QString mExportFilePath; + +}; + +Q_DECLARE_METATYPE( QgsSldExportContext ); + +#endif // QGSSLDEXPORTCONTEXT_H