mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-05 00:09:32 -04:00
Revert "Allowing storing GPGK raster layer styles to DB"
This commit is contained in:
parent
3642c9cc40
commit
9d8a722568
@ -3660,15 +3660,6 @@ Qgis.DatabaseProviderConnectionCapability2.baseClass = Qgis
|
||||
Qgis.DatabaseProviderConnectionCapabilities2.baseClass = Qgis
|
||||
DatabaseProviderConnectionCapabilities2 = Qgis # dirty hack since SIP seems to introduce the flags in module
|
||||
# monkey patching scoped based enum
|
||||
Qgis.ProviderStyleStorageCapability.SaveToDatabase.__doc__ = ""
|
||||
Qgis.ProviderStyleStorageCapability.LoadFromDatabase.__doc__ = ""
|
||||
Qgis.ProviderStyleStorageCapability.DeleteFromDatabase.__doc__ = ""
|
||||
Qgis.ProviderStyleStorageCapability.__doc__ = "The StorageCapability enum represents the style storage operations supported by the provider.\n\n.. versionadded:: 3.34\n\n" + '* ``SaveToDatabase``: ' + Qgis.ProviderStyleStorageCapability.SaveToDatabase.__doc__ + '\n' + '* ``LoadFromDatabase``: ' + Qgis.ProviderStyleStorageCapability.LoadFromDatabase.__doc__ + '\n' + '* ``DeleteFromDatabase``: ' + Qgis.ProviderStyleStorageCapability.DeleteFromDatabase.__doc__
|
||||
# --
|
||||
Qgis.ProviderStyleStorageCapability.baseClass = Qgis
|
||||
Qgis.ProviderStyleStorageCapabilities.baseClass = Qgis
|
||||
ProviderStyleStorageCapabilities = Qgis # dirty hack since SIP seems to introduce the flags in module
|
||||
# monkey patching scoped based enum
|
||||
Qgis.UserProfileSelectionPolicy.LastProfile.__doc__ = "Open the last closed profile (only mode supported prior to QGIS 3.32)"
|
||||
Qgis.UserProfileSelectionPolicy.DefaultProfile.__doc__ = "Open a specific profile"
|
||||
Qgis.UserProfileSelectionPolicy.AskUser.__doc__ = "Let the user choose which profile to open"
|
||||
|
@ -467,13 +467,6 @@ String sequence used for separating components of sublayers strings.
|
||||
.. seealso:: :py:func:`subLayers`
|
||||
|
||||
.. versionadded:: 3.12
|
||||
%End
|
||||
|
||||
virtual Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const;
|
||||
%Docstring
|
||||
Returns the style storage capabilities.
|
||||
|
||||
.. versionadded:: 3.34
|
||||
%End
|
||||
|
||||
signals:
|
||||
|
@ -2121,15 +2121,6 @@ The development version
|
||||
typedef QFlags<Qgis::DatabaseProviderConnectionCapability2> DatabaseProviderConnectionCapabilities2;
|
||||
|
||||
|
||||
enum class ProviderStyleStorageCapability
|
||||
{
|
||||
SaveToDatabase,
|
||||
LoadFromDatabase,
|
||||
DeleteFromDatabase
|
||||
};
|
||||
typedef QFlags<Qgis::ProviderStyleStorageCapability> ProviderStyleStorageCapabilities;
|
||||
|
||||
|
||||
enum class UserProfileSelectionPolicy
|
||||
{
|
||||
LastProfile,
|
||||
|
@ -728,74 +728,6 @@ Read all custom properties from layer. Properties are stored in a map and saved
|
||||
.. versionadded:: 3.14
|
||||
%End
|
||||
|
||||
virtual int listStylesInDatabase( QStringList &ids /Out/, QStringList &names /Out/,
|
||||
QStringList &descriptions /Out/, QString &msgError /Out/ );
|
||||
%Docstring
|
||||
Lists all the style in db split into related to the layer and not related to
|
||||
|
||||
:param ids: the list in which will be stored the style db ids
|
||||
:param names: the list in which will be stored the style names
|
||||
|
||||
:return: - the number of styles related to current layer (-1 on not implemented)
|
||||
- descriptions: the list in which will be stored the style descriptions
|
||||
- msgError: will be set to a descriptive error message if any occurs
|
||||
|
||||
.. note::
|
||||
|
||||
Since QGIS 3.2 Styles related to the layer are ordered with the default style first then by update time for Postgres, MySQL and Spatialite.
|
||||
%End
|
||||
|
||||
virtual QString getStyleFromDatabase( const QString &styleId, QString &msgError /Out/ );
|
||||
%Docstring
|
||||
Returns the named style corresponding to style id provided
|
||||
%End
|
||||
|
||||
virtual bool deleteStyleFromDatabase( const QString &styleId, QString &msgError /Out/ );
|
||||
%Docstring
|
||||
Deletes a style from the database
|
||||
|
||||
:param styleId: the provider's layer_styles table id of the style to delete
|
||||
|
||||
:return: - ``True`` in case of success
|
||||
- msgError: will be set to a descriptive error message if any occurs
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
virtual void saveStyleToDatabase( const QString &name, const QString &description,
|
||||
bool useAsDefault, const QString &uiFileContent,
|
||||
QString &msgError /Out/,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );
|
||||
%Docstring
|
||||
Saves named and sld style of the layer to the style table in the db.
|
||||
|
||||
:param name: Style name
|
||||
:param description: A description of the style
|
||||
:param useAsDefault: Set to ``True`` if style should be used as the default style for the layer
|
||||
:param uiFileContent:
|
||||
:param msgError: will be set to a descriptive error message if any occurs
|
||||
:param categories: the style categories to be saved.
|
||||
|
||||
.. note::
|
||||
|
||||
Prior to QGIS 3.24, this method would show a message box warning when a
|
||||
style with the same ``styleName`` already existed to confirm replacing the style with the user.
|
||||
Since 3.24, calling this method will ALWAYS overwrite any existing style with the same name.
|
||||
Use :py:func:`QgsProviderRegistry.styleExists()` to test in advance if a style already exists and handle this appropriately
|
||||
in your client code.
|
||||
%End
|
||||
|
||||
virtual QString loadNamedStyle( const QString &theURI, bool &resultFlag /Out/, bool loadFromLocalDb,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );
|
||||
%Docstring
|
||||
Loads a named style from file/local db/datasource db
|
||||
|
||||
:param theURI: the URI of the style or the URI of the layer
|
||||
:param resultFlag: will be set to ``True`` if a named style is correctly loaded
|
||||
:param loadFromLocalDb: if ``True`` forces to load from local db instead of datasource one
|
||||
:param categories: the style categories to be loaded.
|
||||
%End
|
||||
|
||||
|
||||
|
||||
void removeCustomProperty( const QString &key );
|
||||
|
@ -541,6 +541,18 @@ Clear recorded errors
|
||||
QStringList errors() const;
|
||||
%Docstring
|
||||
Gets recorded errors
|
||||
%End
|
||||
|
||||
virtual bool isSaveAndLoadStyleToDatabaseSupported() const;
|
||||
%Docstring
|
||||
It returns ``False`` by default.
|
||||
Must be implemented by providers that support saving and loading styles to db returning ``True``
|
||||
%End
|
||||
|
||||
virtual bool isDeleteStyleFromDatabaseSupported() const;
|
||||
%Docstring
|
||||
It returns ``False`` by default.
|
||||
Must be implemented by providers that support delete styles from db returning ``True``
|
||||
%End
|
||||
|
||||
virtual QgsFeatureRenderer *createRenderer( const QVariantMap &configuration = QVariantMap() ) const /Factory/;
|
||||
|
@ -939,6 +939,81 @@ Writes vector layer specific state to project file Dom node.
|
||||
Resolves references to other layers (kept as layer IDs after reading XML) into layer objects.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
virtual void saveStyleToDatabase( const QString &name, const QString &description,
|
||||
bool useAsDefault, const QString &uiFileContent,
|
||||
QString &msgError /Out/,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );
|
||||
%Docstring
|
||||
Saves named and sld style of the layer to the style table in the db.
|
||||
|
||||
:param name: Style name
|
||||
:param description: A description of the style
|
||||
:param useAsDefault: Set to ``True`` if style should be used as the default style for the layer
|
||||
:param uiFileContent:
|
||||
:param msgError: will be set to a descriptive error message if any occurs
|
||||
:param categories: the style categories to be saved.
|
||||
|
||||
.. note::
|
||||
|
||||
Prior to QGIS 3.24, this method would show a message box warning when a
|
||||
style with the same ``styleName`` already existed to confirm replacing the style with the user.
|
||||
Since 3.24, calling this method will ALWAYS overwrite any existing style with the same name.
|
||||
Use :py:func:`QgsProviderRegistry.styleExists()` to test in advance if a style already exists and handle this appropriately
|
||||
in your client code.
|
||||
%End
|
||||
|
||||
virtual int listStylesInDatabase( QStringList &ids /Out/, QStringList &names /Out/,
|
||||
QStringList &descriptions /Out/, QString &msgError /Out/ );
|
||||
%Docstring
|
||||
Lists all the style in db split into related to the layer and not related to
|
||||
|
||||
:param ids: the list in which will be stored the style db ids
|
||||
:param names: the list in which will be stored the style names
|
||||
|
||||
:return: - the number of styles related to current layer (-1 on not implemented)
|
||||
- descriptions: the list in which will be stored the style descriptions
|
||||
- msgError: will be set to a descriptive error message if any occurs
|
||||
|
||||
.. note::
|
||||
|
||||
Since QGIS 3.2 Styles related to the layer are ordered with the default style first then by update time for Postgres, MySQL and Spatialite.
|
||||
%End
|
||||
|
||||
virtual QString getStyleFromDatabase( const QString &styleId, QString &msgError /Out/ );
|
||||
%Docstring
|
||||
Returns the named style corresponding to style id provided
|
||||
%End
|
||||
|
||||
virtual bool deleteStyleFromDatabase( const QString &styleId, QString &msgError /Out/ );
|
||||
%Docstring
|
||||
Deletes a style from the database
|
||||
|
||||
:param styleId: the provider's layer_styles table id of the style to delete
|
||||
|
||||
:return: - ``True`` in case of success
|
||||
- msgError: will be set to a descriptive error message if any occurs
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
virtual QString loadNamedStyle( const QString &theURI, bool &resultFlag /Out/, bool loadFromLocalDb,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );
|
||||
%Docstring
|
||||
Loads a named style from file/local db/datasource db
|
||||
|
||||
:param theURI: the URI of the style or the URI of the layer
|
||||
:param resultFlag: will be set to ``True`` if a named style is correctly loaded
|
||||
:param loadFromLocalDb: if ``True`` forces to load from local db instead of datasource one
|
||||
:param categories: the style categories to be loaded.
|
||||
%End
|
||||
|
||||
virtual QString loadNamedStyle( const QString &theURI, bool &resultFlag /Out/,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories ) ${SIP_FINAL};
|
||||
%Docstring
|
||||
Calls loadNamedStyle( theURI, resultFlag, ``False`` );
|
||||
Retained for backward compatibility
|
||||
%End
|
||||
|
||||
bool loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key = QString() );
|
||||
|
@ -27,7 +27,6 @@ Base class for "layer properties" dialogs, containing common utilities for handl
|
||||
%End
|
||||
public:
|
||||
|
||||
|
||||
QgsLayerPropertiesDialog( QgsMapLayer *layer, QgsMapCanvas *canvas, const QString &settingsKey, QWidget *parent /TransferThis/ = 0, Qt::WindowFlags fl = Qt::WindowFlags(), QgsSettings *settings = 0 );
|
||||
%Docstring
|
||||
Constructor for QgsLayerPropertiesDialog.
|
||||
@ -50,27 +49,6 @@ This must be called in order for the standard metadata loading/saving functional
|
||||
virtual void addPropertiesPageFactory( const QgsMapLayerConfigWidgetFactory *factory );
|
||||
%Docstring
|
||||
Adds properties page from a ``factory``.
|
||||
%End
|
||||
|
||||
void saveDefaultStyle();
|
||||
%Docstring
|
||||
Saves the default style when appropriate button is pressed
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
void loadStyle();
|
||||
%Docstring
|
||||
Triggers a dialog to load a saved style
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
void saveStyleAs();
|
||||
%Docstring
|
||||
Saves a style when appriate button is pressed
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
@ -52,6 +52,21 @@ Saves the default style when appropriate button is pressed
|
||||
use :py:func:`~QgsRasterLayerProperties.saveStyleAsDefault` instead
|
||||
%End
|
||||
|
||||
void loadStyle() /Deprecated/;
|
||||
%Docstring
|
||||
Loads a saved style when appropriate button is pressed
|
||||
|
||||
.. deprecated::
|
||||
use :py:func:`~QgsRasterLayerProperties.loadStyleFromFile` instead.
|
||||
%End
|
||||
|
||||
void saveStyleAs();
|
||||
%Docstring
|
||||
Saves a style when appriate button is pressed
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
protected slots:
|
||||
virtual void optionsStackedWidget_CurrentChanged( int index ) ${SIP_FINAL};
|
||||
|
||||
|
@ -25,6 +25,34 @@ class QgsVectorLayerProperties : QgsLayerPropertiesDialog
|
||||
virtual bool eventFilter( QObject *obj, QEvent *ev );
|
||||
|
||||
|
||||
void loadDefaultStyle();
|
||||
%Docstring
|
||||
Loads the default style when appropriate button is pressed
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
void saveDefaultStyle();
|
||||
%Docstring
|
||||
Saves the default style when appropriate button is pressed
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
void loadStyle();
|
||||
%Docstring
|
||||
Loads a saved style when appropriate button is pressed
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
void saveStyleAs();
|
||||
%Docstring
|
||||
Saves a style when appriate button is pressed
|
||||
|
||||
.. versionadded:: 3.30
|
||||
%End
|
||||
|
||||
protected slots:
|
||||
void optionsStackedWidget_CurrentChanged( int index ) final;
|
||||
virtual void syncToLayer() ${SIP_FINAL};
|
||||
|
@ -4202,18 +4202,6 @@ GDALRasterBandH QgsGdalProvider::getBand( int bandNo ) const
|
||||
return GDALGetRasterBand( mGdalDataset, bandNo );
|
||||
}
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities QgsGdalProvider::styleStorageCapabilities() const
|
||||
{
|
||||
Qgis::ProviderStyleStorageCapabilities storageCapabilities;
|
||||
if ( isValid() && mDriverName == QLatin1String( "GPKG" ) )
|
||||
{
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::SaveToDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::LoadFromDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::DeleteFromDatabase;
|
||||
}
|
||||
return storageCapabilities;
|
||||
}
|
||||
|
||||
// pyramids resampling
|
||||
|
||||
// see http://www.gdal.org/gdaladdo.html
|
||||
@ -4552,95 +4540,6 @@ QList<Qgis::LayerType> QgsGdalProviderMetadata::supportedLayerTypes() const
|
||||
return { Qgis::LayerType::Raster };
|
||||
}
|
||||
|
||||
int QgsGdalProviderMetadata::listStyles( const QString &uri, QStringList &ids, QStringList &names,
|
||||
QStringList &descriptions, QString &errCause )
|
||||
{
|
||||
gdal::dataset_unique_ptr ds;
|
||||
ds.reset( QgsGdalProviderBase::gdalOpen( uri, GDAL_OF_READONLY ) );
|
||||
if ( !ds )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( uri );
|
||||
return -1;
|
||||
}
|
||||
QVariantMap uriParts = QgsGdalProviderBase::decodeGdalUri( uri );
|
||||
QString layerName = uriParts["layerName"].toString();
|
||||
return QgsOgrUtils::listStyles( ds.get(), layerName, "", ids, names, descriptions, errCause );
|
||||
}
|
||||
|
||||
bool QgsGdalProviderMetadata::styleExists( const QString &uri, const QString &styleId, QString &errCause )
|
||||
{
|
||||
gdal::dataset_unique_ptr ds;
|
||||
ds.reset( QgsGdalProviderBase::gdalOpen( uri, GDAL_OF_READONLY ) );
|
||||
if ( !ds )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( uri );
|
||||
return false;
|
||||
}
|
||||
QVariantMap uriParts = QgsGdalProviderBase::decodeGdalUri( uri );
|
||||
QString layerName = uriParts["layerName"] .toString();
|
||||
return QgsOgrUtils::styleExists( ds.get(), layerName, "", styleId, errCause );
|
||||
}
|
||||
|
||||
QString QgsGdalProviderMetadata::getStyleById( const QString &uri, const QString &styleId, QString &errCause )
|
||||
{
|
||||
gdal::dataset_unique_ptr ds;
|
||||
ds.reset( QgsGdalProviderBase::gdalOpen( uri, GDAL_OF_READONLY ) );
|
||||
if ( !ds )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( uri );
|
||||
return QString();
|
||||
}
|
||||
return QgsOgrUtils::getStyleById( ds.get(), styleId, errCause );
|
||||
}
|
||||
|
||||
bool QgsGdalProviderMetadata::deleteStyleById( const QString &uri, const QString &styleId, QString &errCause )
|
||||
{
|
||||
gdal::dataset_unique_ptr ds;
|
||||
ds.reset( QgsGdalProviderBase::gdalOpen( uri, GDAL_OF_READONLY ) );
|
||||
if ( !ds )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( uri );
|
||||
return false;
|
||||
}
|
||||
return QgsOgrUtils::deleteStyleById( ds.get(), styleId, errCause );
|
||||
}
|
||||
|
||||
bool QgsGdalProviderMetadata::saveStyle( const QString &uri, const QString &qmlStyle, const QString &sldStyle,
|
||||
const QString &styleName, const QString &styleDescription,
|
||||
const QString &uiFileContent, bool useAsDefault, QString &errCause )
|
||||
{
|
||||
gdal::dataset_unique_ptr ds;
|
||||
ds.reset( QgsGdalProviderBase::gdalOpen( uri, GDAL_OF_UPDATE ) );
|
||||
if ( !ds )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( uri );
|
||||
return false;
|
||||
}
|
||||
QVariantMap uriParts = QgsGdalProviderBase::decodeGdalUri( uri );
|
||||
QString layerName = uriParts["layerName"].toString();
|
||||
return QgsOgrUtils::saveStyle( ds.get(), layerName, "", qmlStyle, sldStyle, styleName, styleDescription, uiFileContent, useAsDefault, errCause );
|
||||
}
|
||||
|
||||
QString QgsGdalProviderMetadata::loadStyle( const QString &uri, QString &errCause )
|
||||
{
|
||||
QString name;
|
||||
return loadStoredStyle( uri, name, errCause );
|
||||
}
|
||||
|
||||
QString QgsGdalProviderMetadata::loadStoredStyle( const QString &uri, QString &styleName, QString &errCause )
|
||||
{
|
||||
gdal::dataset_unique_ptr ds;
|
||||
ds.reset( QgsGdalProviderBase::gdalOpen( uri, GDAL_OF_READONLY ) );
|
||||
if ( !ds )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( uri );
|
||||
return QString();
|
||||
}
|
||||
QVariantMap uriParts = QgsGdalProviderBase::decodeGdalUri( uri );
|
||||
QString layerName = uriParts["layerName"].toString();
|
||||
return QgsOgrUtils::loadStoredStyle( ds.get(), layerName, "", styleName, errCause );
|
||||
}
|
||||
|
||||
QgsGdalProviderMetadata::QgsGdalProviderMetadata():
|
||||
QgsProviderMetadata( PROVIDER_KEY, PROVIDER_DESCRIPTION )
|
||||
{
|
||||
|
@ -218,8 +218,6 @@ class QgsGdalProvider final: public QgsRasterDataProvider, QgsGdalProviderBase
|
||||
bool setZoomedOutResamplingMethod( ResamplingMethod method ) override { mZoomedOutResamplingMethod = method; return true; }
|
||||
bool setMaxOversampling( double factor ) override { mMaxOversampling = factor; return true; }
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const override;
|
||||
|
||||
private:
|
||||
QgsGdalProvider( const QgsGdalProvider &other );
|
||||
QgsGdalProvider &operator=( const QgsGdalProvider & ) = delete;
|
||||
@ -404,17 +402,6 @@ class QgsGdalProviderMetadata final: public QgsProviderMetadata
|
||||
QList< QgsProviderSublayerDetails > querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags = Qgis::SublayerQueryFlags(), QgsFeedback *feedback = nullptr ) const override;
|
||||
QStringList sidecarFilesForUri( const QString &uri ) const override;
|
||||
QList< Qgis::LayerType > supportedLayerTypes() const override;
|
||||
|
||||
int listStyles( const QString &uri, QStringList &ids, QStringList &names,
|
||||
QStringList &descriptions, QString &errCause ) override;
|
||||
bool styleExists( const QString &uri, const QString &styleId, QString &errCause SIP_OUT ) override;
|
||||
QString getStyleById( const QString &uri, const QString &styleId, QString &errCause ) override;
|
||||
bool deleteStyleById( const QString &uri, const QString &styleId, QString &errCause ) override;
|
||||
bool saveStyle( const QString &uri, const QString &qmlStyle, const QString &sldStyle,
|
||||
const QString &styleName, const QString &styleDescription,
|
||||
const QString &uiFileContent, bool useAsDefault, QString &errCause ) override;
|
||||
QString loadStyle( const QString &uri, QString &errCause ) override;
|
||||
QString loadStoredStyle( const QString &uri, QString &styleName, QString &errCause ) override;
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
@ -4083,16 +4083,17 @@ bool QgsOgrProvider::leaveUpdateMode()
|
||||
return true;
|
||||
}
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities QgsOgrProvider::styleStorageCapabilities() const
|
||||
bool QgsOgrProvider::isSaveAndLoadStyleToDatabaseSupported() const
|
||||
{
|
||||
Qgis::ProviderStyleStorageCapabilities storageCapabilities;
|
||||
if ( isValid() && ( mGDALDriverName == QLatin1String( "GPKG" ) || mGDALDriverName == QLatin1String( "SQLite" ) ) )
|
||||
{
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::SaveToDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::LoadFromDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::DeleteFromDatabase;
|
||||
}
|
||||
return storageCapabilities;
|
||||
// We could potentially extend support for styling to other drivers
|
||||
// with multiple layer support.
|
||||
return mGDALDriverName == QLatin1String( "GPKG" ) ||
|
||||
mGDALDriverName == QLatin1String( "SQLite" );
|
||||
}
|
||||
|
||||
bool QgsOgrProvider::isDeleteStyleFromDatabaseSupported() const
|
||||
{
|
||||
return isSaveAndLoadStyleToDatabaseSupported();
|
||||
}
|
||||
|
||||
QString QgsOgrProvider::fileVectorFilters() const
|
||||
|
@ -115,7 +115,8 @@ class QgsOgrProvider final: public QgsVectorDataProvider
|
||||
void setEncoding( const QString &e ) override;
|
||||
bool enterUpdateMode() override { return _enterUpdateMode(); }
|
||||
bool leaveUpdateMode() override;
|
||||
Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const override;
|
||||
bool isSaveAndLoadStyleToDatabaseSupported() const override;
|
||||
bool isDeleteStyleFromDatabaseSupported() const override;
|
||||
QString fileVectorFilters() const override;
|
||||
bool isValid() const override;
|
||||
QVariant minimumValue( int index ) const override;
|
||||
|
@ -339,7 +339,7 @@ QList<QgsDataItemProvider *> QgsOgrProviderMetadata::dataItemProviders() const
|
||||
return providers;
|
||||
}
|
||||
|
||||
static QgsOgrLayerUniquePtr LoadDataSourceAndLayer( const QString &uri, bool updateMode, QString &filePath, QString &errCause )
|
||||
static QgsOgrLayerUniquePtr LoadDataSourceAndLayer( const QString &uri, QString &errCause )
|
||||
{
|
||||
bool isSubLayer;
|
||||
int layerIndex;
|
||||
@ -347,87 +347,344 @@ static QgsOgrLayerUniquePtr LoadDataSourceAndLayer( const QString &uri, bool upd
|
||||
QString subsetString;
|
||||
OGRwkbGeometryType ogrGeometryType;
|
||||
QStringList openOptions;
|
||||
filePath = QgsOgrProviderUtils::analyzeURI( uri,
|
||||
isSubLayer,
|
||||
layerIndex,
|
||||
layerName,
|
||||
subsetString,
|
||||
ogrGeometryType,
|
||||
openOptions );
|
||||
QString filePath = QgsOgrProviderUtils::analyzeURI( uri,
|
||||
isSubLayer,
|
||||
layerIndex,
|
||||
layerName,
|
||||
subsetString,
|
||||
ogrGeometryType,
|
||||
openOptions );
|
||||
|
||||
if ( updateMode )
|
||||
if ( !layerName.isEmpty() )
|
||||
{
|
||||
if ( !layerName.isEmpty() )
|
||||
{
|
||||
return QgsOgrProviderUtils::getLayer( filePath, true, QStringList(), layerName, errCause, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
return QgsOgrProviderUtils::getLayer( filePath, true, QStringList(), layerIndex, errCause, true );
|
||||
}
|
||||
return QgsOgrProviderUtils::getLayer( filePath, true, QStringList(), layerName, errCause, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !layerName.isEmpty() )
|
||||
{
|
||||
return QgsOgrProviderUtils::getLayer( filePath, layerName, errCause );
|
||||
}
|
||||
else
|
||||
{
|
||||
return QgsOgrProviderUtils::getLayer( filePath, layerIndex, errCause );
|
||||
}
|
||||
return QgsOgrProviderUtils::getLayer( filePath, true, QStringList(), layerIndex, errCause, true );
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsOgrProviderMetadata::styleExists( const QString &uri, const QString &styleId, QString &errorCause )
|
||||
{
|
||||
QString filePath;
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, false, filePath, errorCause );
|
||||
errorCause.clear();
|
||||
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, errorCause );
|
||||
if ( !userLayer )
|
||||
return false;
|
||||
|
||||
QRecursiveMutex *mutex = nullptr;
|
||||
|
||||
OGRLayerH hUserLayer = userLayer->getHandleAndMutex( mutex );
|
||||
GDALDatasetH hDS = userLayer->getDatasetHandleAndMutex( mutex );
|
||||
QMutexLocker locker( mutex );
|
||||
QString layerName = QString( OGR_L_GetName( hUserLayer ) );
|
||||
QString geomColumn = QString( OGR_L_GetGeometryColumn( hUserLayer ) );
|
||||
|
||||
return QgsOgrUtils::styleExists( hDS, layerName, geomColumn, styleId, errorCause );
|
||||
// check if layer_styles table exists
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
if ( !hLayer )
|
||||
return false;
|
||||
|
||||
const QString realStyleId = styleId.isEmpty() ? QString( OGR_L_GetName( hUserLayer ) ) : styleId;
|
||||
|
||||
const QString checkQuery = QStringLiteral( "f_table_schema=''"
|
||||
" AND f_table_name=%1"
|
||||
" AND f_geometry_column=%2"
|
||||
" AND styleName=%3" )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( QString( OGR_L_GetName( hUserLayer ) ) ),
|
||||
QgsOgrProviderUtils::quotedValue( QString( OGR_L_GetGeometryColumn( hUserLayer ) ) ),
|
||||
QgsOgrProviderUtils::quotedValue( realStyleId ) );
|
||||
OGR_L_SetAttributeFilter( hLayer, checkQuery.toUtf8().constData() );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetNextFeature( hLayer ) );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
|
||||
if ( hFeature )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsOgrProviderMetadata::saveStyle(
|
||||
const QString &uri, const QString &qmlStyle, const QString &sldStyle,
|
||||
const QString &styleName, const QString &styleDescription,
|
||||
const QString &uiFileContent, bool useAsDefault, QString &errCause )
|
||||
{
|
||||
QString filePath;
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, true, filePath, errCause );
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, errCause );
|
||||
if ( !userLayer )
|
||||
return false;
|
||||
|
||||
QRecursiveMutex *mutex = nullptr;
|
||||
|
||||
OGRLayerH hUserLayer = userLayer->getHandleAndMutex( mutex );
|
||||
GDALDatasetH hDS = userLayer->getDatasetHandleAndMutex( mutex );
|
||||
QMutexLocker locker( mutex );
|
||||
QString layerName = QString( OGR_L_GetName( hUserLayer ) );
|
||||
QString geomColumn = QString( OGR_L_GetGeometryColumn( hUserLayer ) );
|
||||
|
||||
return QgsOgrUtils::saveStyle( hDS, layerName, geomColumn, qmlStyle, sldStyle, styleName, styleDescription, uiFileContent, useAsDefault, errCause );
|
||||
// check if layer_styles table already exist
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
if ( !hLayer )
|
||||
{
|
||||
// if not create it
|
||||
// Note: we use the same schema as in the SpatiaLite and postgres providers
|
||||
//for cross interoperability
|
||||
|
||||
char **options = nullptr;
|
||||
// TODO: might need change if other drivers than GPKG / SQLite
|
||||
options = CSLSetNameValue( options, "FID", "id" );
|
||||
hLayer = GDALDatasetCreateLayer( hDS, "layer_styles", nullptr, wkbNone, options );
|
||||
QgsOgrProviderUtils::invalidateCachedDatasets( QString::fromUtf8( GDALGetDescription( hDS ) ) );
|
||||
CSLDestroy( options );
|
||||
if ( !hLayer )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to save layer style. It's not possible to create the destination table on the database." );
|
||||
return false;
|
||||
}
|
||||
bool ok = true;
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "f_table_catalog", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 256 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "f_table_schema", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 256 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "f_table_name", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 256 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "f_geometry_column", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 256 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "styleName", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 30 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "styleQML", OFTString ) );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "styleSLD", OFTString ) );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "useAsDefault", OFTInteger ) );
|
||||
OGR_Fld_SetSubType( fld.get(), OFSTBoolean );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "description", OFTString ) );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "owner", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 30 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "ui", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 30 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "update_time", OFTDateTime ) );
|
||||
OGR_Fld_SetDefault( fld.get(), "CURRENT_TIMESTAMP" );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
if ( !ok )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to save layer style. It's not possible to create the destination table on the database." );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QString realStyleName =
|
||||
styleName.isEmpty() ? QString( OGR_L_GetName( hUserLayer ) ) : styleName;
|
||||
|
||||
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
|
||||
|
||||
if ( useAsDefault )
|
||||
{
|
||||
QString oldDefaultQuery = QStringLiteral( "useAsDefault = 1 AND f_table_schema=''"
|
||||
" AND f_table_name=%1"
|
||||
" AND f_geometry_column=%2" )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( QString( OGR_L_GetName( hUserLayer ) ) ) )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( QString( OGR_L_GetGeometryColumn( hUserLayer ) ) ) );
|
||||
OGR_L_SetAttributeFilter( hLayer, oldDefaultQuery.toUtf8().constData() );
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetNextFeature( hLayer ) );
|
||||
if ( hFeature )
|
||||
{
|
||||
OGR_F_SetFieldInteger( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "useAsDefault" ),
|
||||
0 );
|
||||
bool ok = OGR_L_SetFeature( hLayer, hFeature.get() ) == 0;
|
||||
if ( !ok )
|
||||
{
|
||||
QgsDebugError( QStringLiteral( "Could not unset previous useAsDefault style" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString checkQuery = QStringLiteral( "f_table_schema=''"
|
||||
" AND f_table_name=%1"
|
||||
" AND f_geometry_column=%2"
|
||||
" AND styleName=%3" )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( QString( OGR_L_GetName( hUserLayer ) ) ) )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( QString( OGR_L_GetGeometryColumn( hUserLayer ) ) ) )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( realStyleName ) );
|
||||
OGR_L_SetAttributeFilter( hLayer, checkQuery.toUtf8().constData() );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetNextFeature( hLayer ) );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
bool bNew = true;
|
||||
|
||||
if ( hFeature )
|
||||
{
|
||||
bNew = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
hFeature.reset( OGR_F_Create( hLayerDefn ) );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_table_catalog" ),
|
||||
"" );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_table_schema" ),
|
||||
"" );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_table_name" ),
|
||||
OGR_L_GetName( hUserLayer ) );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_geometry_column" ),
|
||||
OGR_L_GetGeometryColumn( hUserLayer ) );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleName" ),
|
||||
realStyleName.toUtf8().constData() );
|
||||
if ( !uiFileContent.isEmpty() )
|
||||
{
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "ui" ),
|
||||
uiFileContent.toUtf8().constData() );
|
||||
}
|
||||
}
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleQML" ),
|
||||
qmlStyle.toUtf8().constData() );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleSLD" ),
|
||||
sldStyle.toUtf8().constData() );
|
||||
OGR_F_SetFieldInteger( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "useAsDefault" ),
|
||||
useAsDefault ? 1 : 0 );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "description" ),
|
||||
( styleDescription.isEmpty() ? QDateTime::currentDateTime().toString() : styleDescription ).toUtf8().constData() );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "owner" ),
|
||||
"" );
|
||||
|
||||
bool bFeatureOK;
|
||||
if ( bNew )
|
||||
bFeatureOK = OGR_L_CreateFeature( hLayer, hFeature.get() ) == OGRERR_NONE;
|
||||
else
|
||||
bFeatureOK = OGR_L_SetFeature( hLayer, hFeature.get() ) == OGRERR_NONE;
|
||||
|
||||
if ( !bFeatureOK )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Error updating style" ) );
|
||||
errCause = QObject::tr( "Error looking for style. The query was logged" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsOgrProviderMetadata::deleteStyleById( const QString &uri, const QString &styleId, QString &errCause )
|
||||
{
|
||||
QString filePath;
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, false, filePath, errCause );
|
||||
QgsDataSourceUri dsUri( uri );
|
||||
bool deleted;
|
||||
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, errCause );
|
||||
if ( !userLayer )
|
||||
return false;
|
||||
|
||||
QRecursiveMutex *mutex = nullptr;
|
||||
GDALDatasetH hDS = userLayer->getDatasetHandleAndMutex( mutex );
|
||||
QMutexLocker locker( mutex );
|
||||
|
||||
return QgsOgrUtils::deleteStyleById( hDS, styleId, errCause );
|
||||
// check if layer_styles table already exist
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
if ( !hLayer )
|
||||
{
|
||||
errCause = QObject::tr( "Connection to database failed: %1" ).arg( dsUri.uri() );
|
||||
deleted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( OGR_L_DeleteFeature( hLayer, styleId.toInt() ) != OGRERR_NONE )
|
||||
{
|
||||
errCause = QObject::tr( "Error executing the delete query." );
|
||||
deleted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
deleted = true;
|
||||
}
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
static
|
||||
bool LoadDataSourceLayerStylesAndLayer( const QString &uri,
|
||||
QgsOgrLayerUniquePtr &layerStyles,
|
||||
QgsOgrLayerUniquePtr &userLayer,
|
||||
QString &errCause )
|
||||
{
|
||||
bool isSubLayer;
|
||||
int layerIndex;
|
||||
QString layerName;
|
||||
QString subsetString;
|
||||
OGRwkbGeometryType ogrGeometryType;
|
||||
QStringList openOptions;
|
||||
QString filePath = QgsOgrProviderUtils::analyzeURI( uri,
|
||||
isSubLayer,
|
||||
layerIndex,
|
||||
layerName,
|
||||
subsetString,
|
||||
ogrGeometryType,
|
||||
openOptions );
|
||||
|
||||
layerStyles =
|
||||
QgsOgrProviderUtils::getLayer( filePath, "layer_styles", errCause );
|
||||
userLayer = nullptr;
|
||||
if ( !layerStyles )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot find layer_styles layer" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !layerName.isEmpty() )
|
||||
{
|
||||
userLayer = QgsOgrProviderUtils::getLayer( filePath, layerName, errCause );
|
||||
}
|
||||
else
|
||||
{
|
||||
userLayer = QgsOgrProviderUtils::getLayer( filePath, layerIndex, errCause );
|
||||
}
|
||||
if ( !userLayer )
|
||||
{
|
||||
layerStyles.reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString QgsOgrProviderMetadata::loadStyle( const QString &uri, QString &errCause )
|
||||
{
|
||||
QString name;
|
||||
@ -436,53 +693,230 @@ QString QgsOgrProviderMetadata::loadStyle( const QString &uri, QString &errCause
|
||||
|
||||
QString QgsOgrProviderMetadata::loadStoredStyle( const QString &uri, QString &styleName, QString &errCause )
|
||||
{
|
||||
QString filePath;
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, false, filePath, errCause );
|
||||
if ( !userLayer )
|
||||
QgsOgrLayerUniquePtr layerStyles;
|
||||
QgsOgrLayerUniquePtr userLayer;
|
||||
if ( !LoadDataSourceLayerStylesAndLayer( uri, layerStyles, userLayer, errCause ) )
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QRecursiveMutex *mutex = nullptr;
|
||||
OGRLayerH hUserLayer = userLayer->getHandleAndMutex( mutex );
|
||||
GDALDatasetH hDS = userLayer->getDatasetHandleAndMutex( mutex );
|
||||
QMutexLocker lock( mutex );
|
||||
QString layerName = QString( OGR_L_GetName( hUserLayer ) );
|
||||
QString geomColumn = QString( OGR_L_GetGeometryColumn( hUserLayer ) );
|
||||
QRecursiveMutex *mutex1 = nullptr;
|
||||
QRecursiveMutex *mutex2 = nullptr;
|
||||
|
||||
return QgsOgrUtils::loadStoredStyle( hDS, layerName, geomColumn, styleName, errCause );
|
||||
OGRLayerH hLayer = layerStyles->getHandleAndMutex( mutex1 );
|
||||
OGRLayerH hUserLayer = userLayer->getHandleAndMutex( mutex2 );
|
||||
QMutexLocker lock1( mutex1 );
|
||||
QMutexLocker lock2( mutex2 );
|
||||
|
||||
QString selectQmlQuery = QStringLiteral( "f_table_schema=''"
|
||||
" AND f_table_name=%1"
|
||||
" AND f_geometry_column=%2"
|
||||
" ORDER BY CASE WHEN useAsDefault THEN 1 ELSE 2 END"
|
||||
",update_time DESC LIMIT 1" )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( QString( OGR_L_GetName( hUserLayer ) ) ) )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( QString( OGR_L_GetGeometryColumn( hUserLayer ) ) ) );
|
||||
OGR_L_SetAttributeFilter( hLayer, selectQmlQuery.toUtf8().constData() );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
|
||||
QString styleQML;
|
||||
qlonglong moreRecentTimestamp = 0;
|
||||
while ( true )
|
||||
{
|
||||
gdal::ogr_feature_unique_ptr hFeat( OGR_L_GetNextFeature( hLayer ) );
|
||||
if ( !hFeat )
|
||||
break;
|
||||
if ( OGR_F_GetFieldAsInteger( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "useAsDefault" ) ) )
|
||||
{
|
||||
styleQML = QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "styleQML" ) ) );
|
||||
styleName = QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "styleName" ) ) );
|
||||
break;
|
||||
}
|
||||
|
||||
int year, month, day, hour, minute, second, TZ;
|
||||
OGR_F_GetFieldAsDateTime( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "update_time" ),
|
||||
&year, &month, &day, &hour, &minute, &second, &TZ );
|
||||
qlonglong ts = second + minute * 60 + hour * 3600 + day * 24 * 3600 +
|
||||
static_cast<qlonglong>( month ) * 31 * 24 * 3600 + static_cast<qlonglong>( year ) * 12 * 31 * 24 * 3600;
|
||||
if ( ts > moreRecentTimestamp )
|
||||
{
|
||||
moreRecentTimestamp = ts;
|
||||
styleQML = QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "styleQML" ) ) );
|
||||
styleName = QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "styleName" ) ) );
|
||||
}
|
||||
}
|
||||
OGR_L_ResetReading( hLayer );
|
||||
|
||||
return styleQML;
|
||||
}
|
||||
|
||||
int QgsOgrProviderMetadata::listStyles(
|
||||
const QString &uri, QStringList &ids, QStringList &names,
|
||||
QStringList &descriptions, QString &errCause )
|
||||
{
|
||||
QString filePath;
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, false, filePath, errCause );
|
||||
bool isSubLayer;
|
||||
int layerIndex;
|
||||
QString layerName;
|
||||
QString subsetString;
|
||||
OGRwkbGeometryType ogrGeometryType;
|
||||
QStringList openOptions;
|
||||
QString filePath = QgsOgrProviderUtils::analyzeURI( uri,
|
||||
isSubLayer,
|
||||
layerIndex,
|
||||
layerName,
|
||||
subsetString,
|
||||
ogrGeometryType,
|
||||
openOptions );
|
||||
|
||||
QgsOgrLayerUniquePtr userLayer;
|
||||
if ( !layerName.isEmpty() )
|
||||
{
|
||||
userLayer = QgsOgrProviderUtils::getLayer( filePath, layerName, errCause );
|
||||
}
|
||||
else
|
||||
{
|
||||
userLayer = QgsOgrProviderUtils::getLayer( filePath, layerIndex, errCause );
|
||||
}
|
||||
if ( !userLayer )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
QRecursiveMutex *mutex = nullptr;
|
||||
OGRLayerH hUserLayer = userLayer->getHandleAndMutex( mutex );
|
||||
GDALDatasetH hDS = userLayer->getDatasetHandleAndMutex( mutex );
|
||||
Q_UNUSED( hDS );
|
||||
QMutexLocker locker( mutex );
|
||||
QString layerName = QString( OGR_L_GetName( hUserLayer ) );
|
||||
QString geomColumn = QString( OGR_L_GetGeometryColumn( hUserLayer ) );
|
||||
QgsOgrLayerUniquePtr layerStyles =
|
||||
QgsOgrProviderUtils::getLayer( filePath, "layer_styles", errCause );
|
||||
if ( !layerStyles )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "No styles available on DB" ) );
|
||||
errCause = QObject::tr( "No styles available on DB" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return QgsOgrUtils::listStyles( hDS, layerName, geomColumn, ids, names, descriptions, errCause );
|
||||
QRecursiveMutex *mutex1 = nullptr;
|
||||
QRecursiveMutex *mutex2 = nullptr;
|
||||
|
||||
OGRLayerH hLayer = layerStyles->getHandleAndMutex( mutex1 );
|
||||
QMutexLocker lock1( mutex1 );
|
||||
OGRLayerH hUserLayer = userLayer->getHandleAndMutex( mutex2 );
|
||||
QMutexLocker lock2( mutex2 );
|
||||
|
||||
if ( OGR_L_GetFeatureCount( hLayer, TRUE ) == 0 )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "No styles available on DB" ) );
|
||||
errCause = QObject::tr( "No styles available on DB" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
|
||||
|
||||
OGR_L_ResetReading( hLayer );
|
||||
|
||||
QList<qlonglong> listTimestamp;
|
||||
QMap<int, QString> mapIdToStyleName;
|
||||
QMap<int, QString> mapIdToDescription;
|
||||
QMap<qlonglong, QList<int> > mapTimestampToId;
|
||||
int numberOfRelatedStyles = 0;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetNextFeature( hLayer ) );
|
||||
if ( !hFeature )
|
||||
break;
|
||||
|
||||
QString tableName( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_table_name" ) ) ) );
|
||||
QString geometryColumn( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_geometry_column" ) ) ) );
|
||||
QString styleName( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleName" ) ) ) );
|
||||
QString description( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "description" ) ) ) );
|
||||
int fid = static_cast<int>( OGR_F_GetFID( hFeature.get() ) );
|
||||
if ( tableName == QString::fromUtf8( OGR_L_GetName( hUserLayer ) ) &&
|
||||
geometryColumn == QString::fromUtf8( OGR_L_GetGeometryColumn( hUserLayer ) ) )
|
||||
{
|
||||
// Append first all related styles
|
||||
QString id( QString::number( fid ) );
|
||||
ids.append( id );
|
||||
names.append( styleName );
|
||||
descriptions.append( description );
|
||||
++ numberOfRelatedStyles;
|
||||
}
|
||||
else
|
||||
{
|
||||
int year, month, day, hour, minute, second, TZ;
|
||||
OGR_F_GetFieldAsDateTime( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn, "update_time" ),
|
||||
&year, &month, &day, &hour, &minute, &second, &TZ );
|
||||
const qlonglong ts = second + minute * 60 + hour * 3600 + day * 24 * 3600 +
|
||||
static_cast<qlonglong>( month ) * 31 * 24 * 3600 + static_cast<qlonglong>( year ) * 12 * 31 * 24 * 3600;
|
||||
|
||||
listTimestamp.append( ts );
|
||||
mapIdToStyleName[fid] = styleName;
|
||||
mapIdToDescription[fid] = description;
|
||||
mapTimestampToId[ts].append( fid );
|
||||
}
|
||||
}
|
||||
|
||||
std::sort( listTimestamp.begin(), listTimestamp.end() );
|
||||
// Sort from most recent to least recent
|
||||
for ( int i = listTimestamp.size() - 1; i >= 0; i-- )
|
||||
{
|
||||
const QList<int> &listId = mapTimestampToId[listTimestamp[i]];
|
||||
for ( int j = 0; j < listId.size(); j++ )
|
||||
{
|
||||
int fid = listId[j];
|
||||
QString id( QString::number( fid ) );
|
||||
ids.append( id );
|
||||
names.append( mapIdToStyleName[fid] );
|
||||
descriptions.append( mapIdToDescription[fid] );
|
||||
}
|
||||
}
|
||||
|
||||
return numberOfRelatedStyles;
|
||||
}
|
||||
|
||||
QString QgsOgrProviderMetadata::getStyleById( const QString &uri, const QString &styleId, QString &errCause )
|
||||
{
|
||||
QString filePath;
|
||||
QgsOgrLayerUniquePtr userLayer = LoadDataSourceAndLayer( uri, false, filePath, errCause );
|
||||
if ( !userLayer )
|
||||
QgsOgrLayerUniquePtr layerStyles;
|
||||
QgsOgrLayerUniquePtr userLayer;
|
||||
if ( !LoadDataSourceLayerStylesAndLayer( uri, layerStyles, userLayer, errCause ) )
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QRecursiveMutex *mutex = nullptr;
|
||||
GDALDatasetH hDS = userLayer->getDatasetHandleAndMutex( mutex );
|
||||
QMutexLocker locker( mutex );
|
||||
QRecursiveMutex *mutex1 = nullptr;
|
||||
|
||||
return QgsOgrUtils::getStyleById( hDS, styleId, errCause );
|
||||
OGRLayerH hLayer = layerStyles->getHandleAndMutex( mutex1 );
|
||||
QMutexLocker lock1( mutex1 );
|
||||
|
||||
bool ok;
|
||||
int id = styleId.toInt( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
errCause = QObject::tr( "Invalid style identifier" );
|
||||
return QString();
|
||||
}
|
||||
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetFeature( hLayer, id ) );
|
||||
if ( !hFeature )
|
||||
{
|
||||
errCause = QObject::tr( "No style corresponding to style identifier" );
|
||||
return QString();
|
||||
}
|
||||
|
||||
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
|
||||
QString styleQML( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleQML" ) ) ) );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
|
||||
return styleQML;
|
||||
}
|
||||
|
||||
bool QgsOgrProviderMetadata::saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage )
|
||||
|
@ -134,8 +134,3 @@ QString QgsDataProvider::sublayerSeparator()
|
||||
{
|
||||
return SUBLAYER_SEPARATOR;
|
||||
}
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities QgsDataProvider::styleStorageCapabilities() const
|
||||
{
|
||||
return Qgis::ProviderStyleStorageCapabilities();
|
||||
}
|
||||
|
@ -633,13 +633,6 @@ class CORE_EXPORT QgsDataProvider : public QObject
|
||||
*/
|
||||
static QString sublayerSeparator();
|
||||
|
||||
/**
|
||||
* Returns the style storage capabilities.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
virtual Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const;
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
|
@ -3690,21 +3690,6 @@ class CORE_EXPORT Qgis
|
||||
Q_DECLARE_FLAGS( DatabaseProviderConnectionCapabilities2, DatabaseProviderConnectionCapability2 )
|
||||
Q_FLAG( DatabaseProviderConnectionCapabilities2 )
|
||||
|
||||
/**
|
||||
* The StorageCapability enum represents the style storage operations supported by the provider.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
enum class ProviderStyleStorageCapability
|
||||
{
|
||||
SaveToDatabase = 1 << 1,
|
||||
LoadFromDatabase = 1 << 2,
|
||||
DeleteFromDatabase = 1 << 3
|
||||
};
|
||||
Q_ENUM( ProviderStyleStorageCapability );
|
||||
Q_DECLARE_FLAGS( ProviderStyleStorageCapabilities, ProviderStyleStorageCapability )
|
||||
Q_FLAG( ProviderStyleStorageCapabilities )
|
||||
|
||||
/**
|
||||
* User profile selection policy.
|
||||
*
|
||||
|
@ -1365,7 +1365,7 @@ QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag, QgsMa
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return loadNamedStyle( uri, resultFlag, false, categories );
|
||||
return loadNamedProperty( uri, PropertyType::Style, resultFlag, categories );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag, StyleCategories categories )
|
||||
@ -2350,90 +2350,6 @@ void QgsMapLayer::removeCustomProperty( const QString &key )
|
||||
}
|
||||
}
|
||||
|
||||
int QgsMapLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return QgsProviderRegistry::instance()->listStyles( mProviderKey, mDataSource, ids, names, descriptions, msgError );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::getStyleFromDatabase( const QString &styleId, QString &msgError )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return QgsProviderRegistry::instance()->getStyleById( mProviderKey, mDataSource, styleId, msgError );
|
||||
}
|
||||
|
||||
bool QgsMapLayer::deleteStyleFromDatabase( const QString &styleId, QString &msgError )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return QgsProviderRegistry::instance()->deleteStyleById( mProviderKey, mDataSource, styleId, msgError );
|
||||
}
|
||||
|
||||
void QgsMapLayer::saveStyleToDatabase( const QString &name, const QString &description,
|
||||
bool useAsDefault, const QString &uiFileContent, QString &msgError, QgsMapLayer::StyleCategories categories )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
QString sldStyle, qmlStyle;
|
||||
QDomDocument qmlDocument, sldDocument;
|
||||
QgsReadWriteContext context;
|
||||
exportNamedStyle( qmlDocument, msgError, context, categories );
|
||||
if ( !msgError.isNull() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
qmlStyle = qmlDocument.toString();
|
||||
|
||||
this->exportSldStyle( sldDocument, msgError );
|
||||
if ( !msgError.isNull() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
sldStyle = sldDocument.toString();
|
||||
|
||||
QgsProviderRegistry::instance()->saveStyle( mProviderKey,
|
||||
mDataSource, qmlStyle, sldStyle, name,
|
||||
description, uiFileContent, useAsDefault, msgError );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB, QgsMapLayer::StyleCategories categories )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
QString returnMessage;
|
||||
QString qml, errorMsg;
|
||||
QString styleName;
|
||||
if ( !loadFromLocalDB && dataProvider() && dataProvider()->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
|
||||
{
|
||||
qml = QgsProviderRegistry::instance()->loadStoredStyle( mProviderKey, mDataSource, styleName, errorMsg );
|
||||
}
|
||||
|
||||
// Style was successfully loaded from provider storage
|
||||
if ( !qml.isEmpty() )
|
||||
{
|
||||
QDomDocument myDocument( QStringLiteral( "qgis" ) );
|
||||
myDocument.setContent( qml );
|
||||
resultFlag = importNamedStyle( myDocument, errorMsg );
|
||||
returnMessage = QObject::tr( "Loaded from Provider" );
|
||||
}
|
||||
else
|
||||
{
|
||||
returnMessage = loadNamedProperty( theURI, PropertyType::Style, resultFlag, categories );
|
||||
}
|
||||
|
||||
if ( ! styleName.isEmpty() )
|
||||
{
|
||||
styleManager()->renameStyle( styleManager()->currentStyle(), styleName );
|
||||
}
|
||||
|
||||
if ( resultFlag )
|
||||
emit styleLoaded( categories );
|
||||
|
||||
return returnMessage;
|
||||
}
|
||||
|
||||
QgsError QgsMapLayer::error() const
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
@ -722,63 +722,6 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
*/
|
||||
const QgsObjectCustomProperties &customProperties() const;
|
||||
|
||||
/**
|
||||
* Lists all the style in db split into related to the layer and not related to
|
||||
* \param ids the list in which will be stored the style db ids
|
||||
* \param names the list in which will be stored the style names
|
||||
* \param descriptions the list in which will be stored the style descriptions
|
||||
* \param msgError will be set to a descriptive error message if any occurs
|
||||
* \returns the number of styles related to current layer (-1 on not implemented)
|
||||
* \note Since QGIS 3.2 Styles related to the layer are ordered with the default style first then by update time for Postgres, MySQL and Spatialite.
|
||||
*/
|
||||
virtual int listStylesInDatabase( QStringList &ids SIP_OUT, QStringList &names SIP_OUT,
|
||||
QStringList &descriptions SIP_OUT, QString &msgError SIP_OUT );
|
||||
|
||||
/**
|
||||
* Returns the named style corresponding to style id provided
|
||||
*/
|
||||
virtual QString getStyleFromDatabase( const QString &styleId, QString &msgError SIP_OUT );
|
||||
|
||||
/**
|
||||
* Deletes a style from the database
|
||||
* \param styleId the provider's layer_styles table id of the style to delete
|
||||
* \param msgError will be set to a descriptive error message if any occurs
|
||||
* \returns TRUE in case of success
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual bool deleteStyleFromDatabase( const QString &styleId, QString &msgError SIP_OUT );
|
||||
|
||||
/**
|
||||
* Saves named and sld style of the layer to the style table in the db.
|
||||
* \param name Style name
|
||||
* \param description A description of the style
|
||||
* \param useAsDefault Set to TRUE if style should be used as the default style for the layer
|
||||
* \param uiFileContent
|
||||
* \param msgError will be set to a descriptive error message if any occurs
|
||||
* \param categories the style categories to be saved.
|
||||
*
|
||||
*
|
||||
* \note Prior to QGIS 3.24, this method would show a message box warning when a
|
||||
* style with the same \a styleName already existed to confirm replacing the style with the user.
|
||||
* Since 3.24, calling this method will ALWAYS overwrite any existing style with the same name.
|
||||
* Use QgsProviderRegistry::styleExists() to test in advance if a style already exists and handle this appropriately
|
||||
* in your client code.
|
||||
*/
|
||||
virtual void saveStyleToDatabase( const QString &name, const QString &description,
|
||||
bool useAsDefault, const QString &uiFileContent,
|
||||
QString &msgError SIP_OUT,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );
|
||||
|
||||
/**
|
||||
* Loads a named style from file/local db/datasource db
|
||||
* \param theURI the URI of the style or the URI of the layer
|
||||
* \param resultFlag will be set to TRUE if a named style is correctly loaded
|
||||
* \param loadFromLocalDb if TRUE forces to load from local db instead of datasource one
|
||||
* \param categories the style categories to be loaded.
|
||||
*/
|
||||
virtual QString loadNamedStyle( const QString &theURI, bool &resultFlag SIP_OUT, bool loadFromLocalDb,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
|
@ -2666,428 +2666,3 @@ gdal::relationship_unique_ptr QgsOgrUtils::convertRelationship( const QgsWeakRel
|
||||
return relationH;
|
||||
}
|
||||
#endif
|
||||
|
||||
int QgsOgrUtils::listStyles( GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause )
|
||||
{
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
if ( !hLayer )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "No styles available on DB" ) );
|
||||
errCause = QObject::tr( "No styles available on DB" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( OGR_L_GetFeatureCount( hLayer, TRUE ) == 0 )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "No styles available on DB" ) );
|
||||
errCause = QObject::tr( "No styles available on DB" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
|
||||
|
||||
OGR_L_ResetReading( hLayer );
|
||||
|
||||
QList<qlonglong> listTimestamp;
|
||||
QMap<int, QString> mapIdToStyleName;
|
||||
QMap<int, QString> mapIdToDescription;
|
||||
QMap<qlonglong, QList<int> > mapTimestampToId;
|
||||
int numberOfRelatedStyles = 0;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetNextFeature( hLayer ) );
|
||||
if ( !hFeature )
|
||||
break;
|
||||
|
||||
QString tableName( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_table_name" ) ) ) );
|
||||
QString geometryColumn( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_geometry_column" ) ) ) );
|
||||
QString styleName( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleName" ) ) ) );
|
||||
QString description( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "description" ) ) ) );
|
||||
int fid = static_cast<int>( OGR_F_GetFID( hFeature.get() ) );
|
||||
if ( tableName == layerName &&
|
||||
geometryColumn == geomColumn )
|
||||
{
|
||||
// Append first all related styles
|
||||
QString id( QString::number( fid ) );
|
||||
ids.append( id );
|
||||
names.append( styleName );
|
||||
descriptions.append( description );
|
||||
++ numberOfRelatedStyles;
|
||||
}
|
||||
else
|
||||
{
|
||||
int year, month, day, hour, minute, second, TZ;
|
||||
OGR_F_GetFieldAsDateTime( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn, "update_time" ),
|
||||
&year, &month, &day, &hour, &minute, &second, &TZ );
|
||||
const qlonglong ts = second + minute * 60 + hour * 3600 + day * 24 * 3600 +
|
||||
static_cast<qlonglong>( month ) * 31 * 24 * 3600 + static_cast<qlonglong>( year ) * 12 * 31 * 24 * 3600;
|
||||
|
||||
listTimestamp.append( ts );
|
||||
mapIdToStyleName[fid] = styleName;
|
||||
mapIdToDescription[fid] = description;
|
||||
mapTimestampToId[ts].append( fid );
|
||||
}
|
||||
}
|
||||
|
||||
std::sort( listTimestamp.begin(), listTimestamp.end() );
|
||||
// Sort from most recent to least recent
|
||||
for ( int i = listTimestamp.size() - 1; i >= 0; i-- )
|
||||
{
|
||||
const QList<int> &listId = mapTimestampToId[listTimestamp[i]];
|
||||
for ( int j = 0; j < listId.size(); j++ )
|
||||
{
|
||||
int fid = listId[j];
|
||||
QString id( QString::number( fid ) );
|
||||
ids.append( id );
|
||||
names.append( mapIdToStyleName[fid] );
|
||||
descriptions.append( mapIdToDescription[fid] );
|
||||
}
|
||||
}
|
||||
|
||||
return numberOfRelatedStyles;
|
||||
}
|
||||
|
||||
bool QgsOgrUtils::styleExists( GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, const QString &styleId, QString &errorCause )
|
||||
{
|
||||
errorCause.clear();
|
||||
|
||||
// check if layer_styles table exists
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
if ( !hLayer )
|
||||
return false;
|
||||
|
||||
const QString realStyleId = styleId.isEmpty() ? layerName : styleId;
|
||||
|
||||
const QString checkQuery = QStringLiteral( "f_table_schema=''"
|
||||
" AND f_table_name=%1"
|
||||
" AND f_geometry_column=%2"
|
||||
" AND styleName=%3" )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( layerName ),
|
||||
QgsOgrProviderUtils::quotedValue( geomColumn ),
|
||||
QgsOgrProviderUtils::quotedValue( realStyleId ) );
|
||||
OGR_L_SetAttributeFilter( hLayer, checkQuery.toUtf8().constData() );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetNextFeature( hLayer ) );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
|
||||
if ( hFeature )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString QgsOgrUtils::getStyleById( GDALDatasetH hDS, const QString &styleId, QString &errCause )
|
||||
{
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
if ( !hLayer )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "No styles available on DB" ) );
|
||||
errCause = QObject::tr( "No styles available on DB" );
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int id = styleId.toInt( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
errCause = QObject::tr( "Invalid style identifier" );
|
||||
return QString();
|
||||
}
|
||||
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetFeature( hLayer, id ) );
|
||||
if ( !hFeature )
|
||||
{
|
||||
errCause = QObject::tr( "No style corresponding to style identifier" );
|
||||
return QString();
|
||||
}
|
||||
|
||||
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
|
||||
QString styleQML( QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleQML" ) ) ) );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
|
||||
return styleQML;
|
||||
}
|
||||
|
||||
bool QgsOgrUtils::deleteStyleById( GDALDatasetH hDS, const QString &styleId, QString &errCause )
|
||||
{
|
||||
bool deleted;
|
||||
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
|
||||
// check if layer_styles table already exist
|
||||
if ( !hLayer )
|
||||
{
|
||||
errCause = QObject::tr( "Connection to database failed" );
|
||||
deleted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( OGR_L_DeleteFeature( hLayer, styleId.toInt() ) != OGRERR_NONE )
|
||||
{
|
||||
errCause = QObject::tr( "Error executing the delete query." );
|
||||
deleted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
deleted = true;
|
||||
}
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
QString QgsOgrUtils::loadStoredStyle( GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, QString &styleName, QString &errCause )
|
||||
{
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
if ( !hLayer )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "No styles available on DB" ) );
|
||||
errCause = QObject::tr( "No styles available on DB" );
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString selectQmlQuery = QStringLiteral( "f_table_schema=''"
|
||||
" AND f_table_name=%1"
|
||||
" AND f_geometry_column=%2"
|
||||
" ORDER BY CASE WHEN useAsDefault THEN 1 ELSE 2 END"
|
||||
",update_time DESC LIMIT 1" )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( layerName ) )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( geomColumn ) );
|
||||
OGR_L_SetAttributeFilter( hLayer, selectQmlQuery.toUtf8().constData() );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
|
||||
QString styleQML;
|
||||
qlonglong moreRecentTimestamp = 0;
|
||||
while ( true )
|
||||
{
|
||||
gdal::ogr_feature_unique_ptr hFeat( OGR_L_GetNextFeature( hLayer ) );
|
||||
if ( !hFeat )
|
||||
break;
|
||||
if ( OGR_F_GetFieldAsInteger( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "useAsDefault" ) ) )
|
||||
{
|
||||
styleQML = QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "styleQML" ) ) );
|
||||
styleName = QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "styleName" ) ) );
|
||||
break;
|
||||
}
|
||||
|
||||
int year, month, day, hour, minute, second, TZ;
|
||||
OGR_F_GetFieldAsDateTime( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "update_time" ),
|
||||
&year, &month, &day, &hour, &minute, &second, &TZ );
|
||||
qlonglong ts = second + minute * 60 + hour * 3600 + day * 24 * 3600 +
|
||||
static_cast<qlonglong>( month ) * 31 * 24 * 3600 + static_cast<qlonglong>( year ) * 12 * 31 * 24 * 3600;
|
||||
if ( ts > moreRecentTimestamp )
|
||||
{
|
||||
moreRecentTimestamp = ts;
|
||||
styleQML = QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "styleQML" ) ) );
|
||||
styleName = QString::fromUtf8(
|
||||
OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn, "styleName" ) ) );
|
||||
}
|
||||
}
|
||||
OGR_L_ResetReading( hLayer );
|
||||
|
||||
return styleQML;
|
||||
}
|
||||
|
||||
bool QgsOgrUtils::saveStyle(
|
||||
GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, const QString &qmlStyle, const QString &sldStyle,
|
||||
const QString &styleName, const QString &styleDescription,
|
||||
const QString &uiFileContent, bool useAsDefault, QString &errCause
|
||||
)
|
||||
{
|
||||
// check if layer_styles table already exist
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS, "layer_styles" );
|
||||
if ( !hLayer )
|
||||
{
|
||||
// if not create it
|
||||
// Note: we use the same schema as in the SpatiaLite and postgres providers
|
||||
//for cross interoperability
|
||||
|
||||
char **options = nullptr;
|
||||
// TODO: might need change if other drivers than GPKG / SQLite
|
||||
options = CSLSetNameValue( options, "FID", "id" );
|
||||
hLayer = GDALDatasetCreateLayer( hDS, "layer_styles", nullptr, wkbNone, options );
|
||||
QgsOgrProviderUtils::invalidateCachedDatasets( QString::fromUtf8( GDALGetDescription( hDS ) ) );
|
||||
CSLDestroy( options );
|
||||
if ( !hLayer )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to save layer style. It's not possible to create the destination table on the database." );
|
||||
return false;
|
||||
}
|
||||
bool ok = true;
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "f_table_catalog", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 256 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "f_table_schema", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 256 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "f_table_name", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 256 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "f_geometry_column", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 256 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "styleName", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 30 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "styleQML", OFTString ) );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "styleSLD", OFTString ) );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "useAsDefault", OFTInteger ) );
|
||||
OGR_Fld_SetSubType( fld.get(), OFSTBoolean );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "description", OFTString ) );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "owner", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 30 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "ui", OFTString ) );
|
||||
OGR_Fld_SetWidth( fld.get(), 30 );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
{
|
||||
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( "update_time", OFTDateTime ) );
|
||||
OGR_Fld_SetDefault( fld.get(), "CURRENT_TIMESTAMP" );
|
||||
ok &= OGR_L_CreateField( hLayer, fld.get(), true ) == OGRERR_NONE;
|
||||
}
|
||||
if ( !ok )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to save layer style. It's not possible to create the destination table on the database." );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QString realStyleName =
|
||||
styleName.isEmpty() ? layerName : styleName;
|
||||
|
||||
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
|
||||
|
||||
if ( useAsDefault )
|
||||
{
|
||||
QString oldDefaultQuery = QStringLiteral( "useAsDefault = 1 AND f_table_schema=''"
|
||||
" AND f_table_name=%1"
|
||||
" AND f_geometry_column=%2" )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( layerName ) )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( geomColumn ) );
|
||||
OGR_L_SetAttributeFilter( hLayer, oldDefaultQuery.toUtf8().constData() );
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetNextFeature( hLayer ) );
|
||||
if ( hFeature )
|
||||
{
|
||||
OGR_F_SetFieldInteger( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "useAsDefault" ),
|
||||
0 );
|
||||
bool ok = OGR_L_SetFeature( hLayer, hFeature.get() ) == 0;
|
||||
if ( !ok )
|
||||
{
|
||||
QgsDebugError( QStringLiteral( "Could not unset previous useAsDefault style" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString checkQuery = QStringLiteral( "f_table_schema=''"
|
||||
" AND f_table_name=%1"
|
||||
" AND f_geometry_column=%2"
|
||||
" AND styleName=%3" )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( layerName ) )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( geomColumn ) )
|
||||
.arg( QgsOgrProviderUtils::quotedValue( realStyleName ) );
|
||||
OGR_L_SetAttributeFilter( hLayer, checkQuery.toUtf8().constData() );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
gdal::ogr_feature_unique_ptr hFeature( OGR_L_GetNextFeature( hLayer ) );
|
||||
OGR_L_ResetReading( hLayer );
|
||||
bool bNew = true;
|
||||
|
||||
if ( hFeature )
|
||||
{
|
||||
bNew = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
hFeature.reset( OGR_F_Create( hLayerDefn ) );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_table_catalog" ),
|
||||
"" );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_table_schema" ),
|
||||
"" );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_table_name" ),
|
||||
layerName.toUtf8().constData() );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "f_geometry_column" ),
|
||||
geomColumn.toUtf8().constData() );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleName" ),
|
||||
realStyleName.toUtf8().constData() );
|
||||
if ( !uiFileContent.isEmpty() )
|
||||
{
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "ui" ),
|
||||
uiFileContent.toUtf8().constData() );
|
||||
}
|
||||
}
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleQML" ),
|
||||
qmlStyle.toUtf8().constData() );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "styleSLD" ),
|
||||
sldStyle.toUtf8().constData() );
|
||||
OGR_F_SetFieldInteger( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "useAsDefault" ),
|
||||
useAsDefault ? 1 : 0 );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "description" ),
|
||||
( styleDescription.isEmpty() ? QDateTime::currentDateTime().toString() : styleDescription ).toUtf8().constData() );
|
||||
OGR_F_SetFieldString( hFeature.get(),
|
||||
OGR_FD_GetFieldIndex( hLayerDefn, "owner" ),
|
||||
"" );
|
||||
|
||||
bool bFeatureOK;
|
||||
if ( bNew )
|
||||
bFeatureOK = OGR_L_CreateFeature( hLayer, hFeature.get() ) == OGRERR_NONE;
|
||||
else
|
||||
bFeatureOK = OGR_L_SetFeature( hLayer, hFeature.get() ) == OGRERR_NONE;
|
||||
|
||||
if ( !bFeatureOK )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Error updating style" ) );
|
||||
errCause = QObject::tr( "Error looking for style. The query was logged" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -484,53 +484,6 @@ class CORE_EXPORT QgsOgrUtils
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper function for listing styles in ogr/gdal database datasources.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
static int listStyles( GDALDatasetH hDS, const QString &layerName,
|
||||
const QString &geomColumn, QStringList &ids, QStringList &names,
|
||||
QStringList &descriptions, QString &errCause );
|
||||
|
||||
/**
|
||||
* Helper function for checking whether a style exists in ogr/gdal database datasources.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
static bool styleExists( GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, const QString &styleId, QString &errorCause );
|
||||
|
||||
/**
|
||||
* Helper function for getting a style by ID from ogr/gdal database datasources.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
static QString getStyleById( GDALDatasetH hDS, const QString &styleId, QString &errCause );
|
||||
|
||||
/**
|
||||
* Helper function for saving a style to ogr/gdal database datasources.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
static bool saveStyle( GDALDatasetH hDS, const QString &layerName,
|
||||
const QString &geomColumn, const QString &qmlStyle, const QString &sldStyle,
|
||||
const QString &styleName, const QString &styleDescription,
|
||||
const QString &uiFileContent, bool useAsDefault, QString &errCause
|
||||
);
|
||||
|
||||
/**
|
||||
* Helper function for deleting a style by id from ogr/gdal database datasources.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
static bool deleteStyleById( GDALDatasetH hDS, const QString &styleId, QString &errCause );
|
||||
|
||||
/**
|
||||
* Helper function for loading a stored styles in ogr/gdal database datasources.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
static QString loadStoredStyle( GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, QString &styleName, QString &errCause );
|
||||
};
|
||||
|
||||
#endif // QGSOGRUTILS_H
|
||||
|
@ -850,6 +850,20 @@ QStringList QgsVectorDataProvider::errors() const
|
||||
return mErrors;
|
||||
}
|
||||
|
||||
bool QgsVectorDataProvider::isSaveAndLoadStyleToDatabaseSupported() const
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsVectorDataProvider::isDeleteStyleFromDatabaseSupported() const
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QgsFeatureRenderer *QgsVectorDataProvider::createRenderer( const QVariantMap & ) const
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
@ -532,6 +532,18 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
|
||||
*/
|
||||
QStringList errors() const;
|
||||
|
||||
/**
|
||||
* It returns FALSE by default.
|
||||
* Must be implemented by providers that support saving and loading styles to db returning TRUE
|
||||
*/
|
||||
virtual bool isSaveAndLoadStyleToDatabaseSupported() const;
|
||||
|
||||
/**
|
||||
* It returns FALSE by default.
|
||||
* Must be implemented by providers that support delete styles from db returning TRUE
|
||||
*/
|
||||
virtual bool isDeleteStyleFromDatabaseSupported() const;
|
||||
|
||||
/**
|
||||
* Creates a new vector layer feature renderer, using provider backend specific information.
|
||||
*
|
||||
|
@ -1957,7 +1957,7 @@ QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
|
||||
if ( resultFlag )
|
||||
{
|
||||
// Try to load all stored styles from DB
|
||||
if ( mLoadAllStoredStyle && mDataProvider && mDataProvider->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
|
||||
if ( mLoadAllStoredStyle && mDataProvider && mDataProvider->isSaveAndLoadStyleToDatabaseSupported() )
|
||||
{
|
||||
QStringList ids, names, descriptions;
|
||||
QString errorMessage;
|
||||
@ -5793,6 +5793,61 @@ void QgsVectorLayer::setWeakRelations( const QList<QgsWeakRelation> &relations )
|
||||
mWeakRelations = relations;
|
||||
}
|
||||
|
||||
int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return QgsProviderRegistry::instance()->listStyles( mProviderKey, mDataSource, ids, names, descriptions, msgError );
|
||||
}
|
||||
|
||||
QString QgsVectorLayer::getStyleFromDatabase( const QString &styleId, QString &msgError )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return QgsProviderRegistry::instance()->getStyleById( mProviderKey, mDataSource, styleId, msgError );
|
||||
}
|
||||
|
||||
bool QgsVectorLayer::deleteStyleFromDatabase( const QString &styleId, QString &msgError )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return QgsProviderRegistry::instance()->deleteStyleById( mProviderKey, mDataSource, styleId, msgError );
|
||||
}
|
||||
|
||||
void QgsVectorLayer::saveStyleToDatabase( const QString &name, const QString &description,
|
||||
bool useAsDefault, const QString &uiFileContent, QString &msgError, QgsMapLayer::StyleCategories categories )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
QString sldStyle, qmlStyle;
|
||||
QDomDocument qmlDocument, sldDocument;
|
||||
QgsReadWriteContext context;
|
||||
exportNamedStyle( qmlDocument, msgError, context, categories );
|
||||
if ( !msgError.isNull() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
qmlStyle = qmlDocument.toString();
|
||||
|
||||
this->exportSldStyle( sldDocument, msgError );
|
||||
if ( !msgError.isNull() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
sldStyle = sldDocument.toString();
|
||||
|
||||
QgsProviderRegistry::instance()->saveStyle( mProviderKey,
|
||||
mDataSource, qmlStyle, sldStyle, name,
|
||||
description, uiFileContent, useAsDefault, msgError );
|
||||
}
|
||||
|
||||
QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, QgsMapLayer::StyleCategories categories )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
return loadNamedStyle( theURI, resultFlag, false, categories );
|
||||
}
|
||||
|
||||
bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
@ -5863,6 +5918,43 @@ QgsAuxiliaryLayer *QgsVectorLayer::auxiliaryLayer()
|
||||
return mAuxiliaryLayer.get();
|
||||
}
|
||||
|
||||
QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB, QgsMapLayer::StyleCategories categories )
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
||||
QgsDataSourceUri dsUri( theURI );
|
||||
QString returnMessage;
|
||||
QString qml, errorMsg;
|
||||
QString styleName;
|
||||
if ( !loadFromLocalDB && mDataProvider && mDataProvider->isSaveAndLoadStyleToDatabaseSupported() )
|
||||
{
|
||||
qml = QgsProviderRegistry::instance()->loadStoredStyle( mProviderKey, mDataSource, styleName, errorMsg );
|
||||
}
|
||||
|
||||
// Style was successfully loaded from provider storage
|
||||
if ( !qml.isEmpty() )
|
||||
{
|
||||
QDomDocument myDocument( QStringLiteral( "qgis" ) );
|
||||
myDocument.setContent( qml );
|
||||
resultFlag = importNamedStyle( myDocument, errorMsg );
|
||||
returnMessage = QObject::tr( "Loaded from Provider" );
|
||||
}
|
||||
else
|
||||
{
|
||||
returnMessage = QgsMapLayer::loadNamedStyle( theURI, resultFlag, categories );
|
||||
}
|
||||
|
||||
if ( ! styleName.isEmpty() )
|
||||
{
|
||||
styleManager()->renameStyle( styleManager()->currentStyle(), styleName );
|
||||
}
|
||||
|
||||
if ( resultFlag )
|
||||
emit styleLoaded( categories );
|
||||
|
||||
return returnMessage;
|
||||
}
|
||||
|
||||
QSet<QgsMapLayerDependency> QgsVectorLayer::dependencies() const
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
|
@ -1023,6 +1023,70 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
|
||||
*/
|
||||
void resolveReferences( QgsProject *project ) FINAL;
|
||||
|
||||
/**
|
||||
* Saves named and sld style of the layer to the style table in the db.
|
||||
* \param name Style name
|
||||
* \param description A description of the style
|
||||
* \param useAsDefault Set to TRUE if style should be used as the default style for the layer
|
||||
* \param uiFileContent
|
||||
* \param msgError will be set to a descriptive error message if any occurs
|
||||
* \param categories the style categories to be saved.
|
||||
*
|
||||
*
|
||||
* \note Prior to QGIS 3.24, this method would show a message box warning when a
|
||||
* style with the same \a styleName already existed to confirm replacing the style with the user.
|
||||
* Since 3.24, calling this method will ALWAYS overwrite any existing style with the same name.
|
||||
* Use QgsProviderRegistry::styleExists() to test in advance if a style already exists and handle this appropriately
|
||||
* in your client code.
|
||||
*/
|
||||
virtual void saveStyleToDatabase( const QString &name, const QString &description,
|
||||
bool useAsDefault, const QString &uiFileContent,
|
||||
QString &msgError SIP_OUT,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );
|
||||
|
||||
/**
|
||||
* Lists all the style in db split into related to the layer and not related to
|
||||
* \param ids the list in which will be stored the style db ids
|
||||
* \param names the list in which will be stored the style names
|
||||
* \param descriptions the list in which will be stored the style descriptions
|
||||
* \param msgError will be set to a descriptive error message if any occurs
|
||||
* \returns the number of styles related to current layer (-1 on not implemented)
|
||||
* \note Since QGIS 3.2 Styles related to the layer are ordered with the default style first then by update time for Postgres, MySQL and Spatialite.
|
||||
*/
|
||||
virtual int listStylesInDatabase( QStringList &ids SIP_OUT, QStringList &names SIP_OUT,
|
||||
QStringList &descriptions SIP_OUT, QString &msgError SIP_OUT );
|
||||
|
||||
/**
|
||||
* Returns the named style corresponding to style id provided
|
||||
*/
|
||||
virtual QString getStyleFromDatabase( const QString &styleId, QString &msgError SIP_OUT );
|
||||
|
||||
/**
|
||||
* Deletes a style from the database
|
||||
* \param styleId the provider's layer_styles table id of the style to delete
|
||||
* \param msgError will be set to a descriptive error message if any occurs
|
||||
* \returns TRUE in case of success
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual bool deleteStyleFromDatabase( const QString &styleId, QString &msgError SIP_OUT );
|
||||
|
||||
/**
|
||||
* Loads a named style from file/local db/datasource db
|
||||
* \param theURI the URI of the style or the URI of the layer
|
||||
* \param resultFlag will be set to TRUE if a named style is correctly loaded
|
||||
* \param loadFromLocalDb if TRUE forces to load from local db instead of datasource one
|
||||
* \param categories the style categories to be loaded.
|
||||
*/
|
||||
virtual QString loadNamedStyle( const QString &theURI, bool &resultFlag SIP_OUT, bool loadFromLocalDb,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );
|
||||
|
||||
/**
|
||||
* Calls loadNamedStyle( theURI, resultFlag, FALSE );
|
||||
* Retained for backward compatibility
|
||||
*/
|
||||
QString loadNamedStyle( const QString &theURI, bool &resultFlag SIP_OUT,
|
||||
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories ) FINAL;
|
||||
|
||||
/**
|
||||
* Loads the auxiliary layer for this vector layer. If there's no
|
||||
* corresponding table in the database, then nothing happens and FALSE is
|
||||
|
@ -39,6 +39,7 @@ set(QGIS_GUI_SRCS
|
||||
vector/qgssourcefieldsproperties.cpp
|
||||
vector/qgsvectorlayerlegendwidget.cpp
|
||||
vector/qgsvectorlayerproperties.cpp
|
||||
vector/qgsvectorlayersavestyledialog.cpp
|
||||
vector/qgswmsdimensiondialog.cpp
|
||||
|
||||
symbology/qgs25drendererwidget.cpp
|
||||
@ -621,7 +622,6 @@ set(QGIS_GUI_SRCS
|
||||
qgsmaplayerconfigwidgetfactory.cpp
|
||||
qgsmaplayerloadstyledialog.cpp
|
||||
qgsmaplayerrefreshsettingswidget.cpp
|
||||
qgsmaplayersavestyledialog.cpp
|
||||
qgsmaplayerstylecategoriesmodel.cpp
|
||||
qgsmaplayerstyleguiutils.cpp
|
||||
qgsmaplayerstylemanagerwidget.cpp
|
||||
@ -897,7 +897,6 @@ set(QGIS_GUI_HDRS
|
||||
qgsmaplayercombobox.h
|
||||
qgsmaplayerconfigwidget.h
|
||||
qgsmaplayerconfigwidgetfactory.h
|
||||
qgsmaplayersavestyledialog.h
|
||||
qgsmaplayerloadstyledialog.h
|
||||
qgsmaplayerrefreshsettingswidget.h
|
||||
qgsmaplayerstylecategoriesmodel.h
|
||||
@ -1432,6 +1431,7 @@ set(QGIS_GUI_HDRS
|
||||
vector/qgssourcefieldsproperties.h
|
||||
vector/qgsvectorlayerlegendwidget.h
|
||||
vector/qgsvectorlayerproperties.h
|
||||
vector/qgsvectorlayersavestyledialog.h
|
||||
vector/qgswmsdimensiondialog.h
|
||||
|
||||
symbology/characterwidget.h
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
class QgsMapLayer;
|
||||
class QgsMapCanvas;
|
||||
class QgsMeshLayer;
|
||||
class QgsRendererMeshPropertiesWidget;
|
||||
class QgsMeshLayer3DRendererWidget;
|
||||
class QgsMeshStaticDatasetWidget;
|
||||
|
@ -14,8 +14,6 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgslayerpropertiesdialog.h"
|
||||
#include "qgsmaplayerloadstyledialog.h"
|
||||
#include "qgsmaplayersavestyledialog.h"
|
||||
#include "qgsmaplayerconfigwidget.h"
|
||||
#include "qgsmaplayerconfigwidgetfactory.h"
|
||||
#include "qgsmaplayerstylemanager.h"
|
||||
@ -23,9 +21,7 @@
|
||||
#include "qgssettings.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsmetadatawidget.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgsfileutils.h"
|
||||
#include "qgssldexportcontext.h"
|
||||
#include "qstackedwidget.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
|
||||
@ -39,6 +35,7 @@ QgsLayerPropertiesDialog::QgsLayerPropertiesDialog( QgsMapLayer *layer, QgsMapCa
|
||||
, mCanvas( canvas )
|
||||
, mLayer( layer )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void QgsLayerPropertiesDialog::setMetadataWidget( QgsMetadataWidget *widget, QWidget *page )
|
||||
@ -254,6 +251,29 @@ void QgsLayerPropertiesDialog::saveStyleAsDefault()
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayerPropertiesDialog::loadDefaultStyle()
|
||||
{
|
||||
if ( !mLayer )
|
||||
return;
|
||||
|
||||
bool defaultLoadedFlag = false;
|
||||
const QString message = mLayer->loadDefaultStyle( defaultLoadedFlag );
|
||||
// reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
syncToLayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise let the user know what went wrong
|
||||
QMessageBox::information( this,
|
||||
tr( "Default Style" ),
|
||||
message
|
||||
);
|
||||
refocusDialog();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayerPropertiesDialog::initialize()
|
||||
{
|
||||
restoreOptionsBaseUi( generateDialogTitle() );
|
||||
@ -283,303 +303,6 @@ void QgsLayerPropertiesDialog::addPropertiesPageFactory( const QgsMapLayerConfig
|
||||
page->syncToLayer( mLayer );
|
||||
}
|
||||
|
||||
void QgsLayerPropertiesDialog::loadDefaultStyle()
|
||||
{
|
||||
QString msg;
|
||||
bool defaultLoadedFlag = false;
|
||||
|
||||
const QgsDataProvider *provider = mLayer->dataProvider();
|
||||
if ( !provider )
|
||||
return;
|
||||
if ( provider->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
|
||||
{
|
||||
QMessageBox askToUser;
|
||||
askToUser.setText( tr( "Load default style from: " ) );
|
||||
askToUser.setIcon( QMessageBox::Question );
|
||||
askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
|
||||
askToUser.addButton( tr( "Local Database" ), QMessageBox::NoRole );
|
||||
askToUser.addButton( tr( "Datasource Database" ), QMessageBox::YesRole );
|
||||
|
||||
switch ( askToUser.exec() )
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case 2:
|
||||
msg = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, false );
|
||||
if ( !defaultLoadedFlag )
|
||||
{
|
||||
//something went wrong - let them know why
|
||||
QMessageBox::information( this, tr( "Default Style" ), msg );
|
||||
}
|
||||
if ( msg.compare( tr( "Loaded from Provider" ) ) )
|
||||
{
|
||||
QMessageBox::information( this, tr( "Default Style" ),
|
||||
tr( "No default style was found for this layer." ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString myMessage = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, true );
|
||||
// QString myMessage = layer->loadDefaultStyle( defaultLoadedFlag );
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
// all worked OK so no need to inform user
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
//something went wrong - let them know why
|
||||
QMessageBox::information( this, tr( "Default Style" ), myMessage );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayerPropertiesDialog::saveDefaultStyle()
|
||||
{
|
||||
QString errorMsg;
|
||||
const QgsDataProvider *provider = mLayer->dataProvider();
|
||||
if ( !provider )
|
||||
return;
|
||||
if ( provider->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::SaveToDatabase ) )
|
||||
{
|
||||
QMessageBox askToUser;
|
||||
askToUser.setText( tr( "Save default style to: " ) );
|
||||
askToUser.setIcon( QMessageBox::Question );
|
||||
askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
|
||||
askToUser.addButton( tr( "Local Database" ), QMessageBox::NoRole );
|
||||
askToUser.addButton( tr( "Datasource Database" ), QMessageBox::YesRole );
|
||||
|
||||
switch ( askToUser.exec() )
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case 2:
|
||||
{
|
||||
apply();
|
||||
QString errorMessage;
|
||||
if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), QString(), errorMessage ) )
|
||||
{
|
||||
if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
|
||||
QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
|
||||
QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( !errorMessage.isEmpty() )
|
||||
{
|
||||
QMessageBox::warning( nullptr, QObject::tr( "Save style in database" ),
|
||||
errorMessage );
|
||||
return;
|
||||
}
|
||||
|
||||
mLayer->saveStyleToDatabase( QString(), QString(), true, QString(), errorMsg );
|
||||
if ( errorMsg.isNull() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QgsLayerPropertiesDialog::saveStyleAsDefault();
|
||||
}
|
||||
|
||||
void QgsLayerPropertiesDialog::saveStyleAs()
|
||||
{
|
||||
if ( !mLayer->dataProvider() )
|
||||
return;
|
||||
QgsMapLayerSaveStyleDialog dlg( mLayer );
|
||||
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
apply();
|
||||
|
||||
bool defaultLoadedFlag = false;
|
||||
QString errorMessage;
|
||||
|
||||
StyleType type = dlg.currentStyleType();
|
||||
switch ( type )
|
||||
{
|
||||
case QML:
|
||||
case SLD:
|
||||
{
|
||||
QString filePath = dlg.outputFilePath();
|
||||
if ( type == QML )
|
||||
errorMessage = mLayer->saveNamedStyle( filePath, defaultLoadedFlag, dlg.styleCategories() );
|
||||
else
|
||||
{
|
||||
const QgsSldExportContext sldContext { dlg.sldExportOptions(), Qgis::SldExportVendorExtension::NoVendorExtension, filePath };
|
||||
errorMessage = mLayer->saveSldStyleV2( defaultLoadedFlag, sldContext );
|
||||
}
|
||||
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
syncToLayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the user know what went wrong
|
||||
QMessageBox::information( this, tr( "Save Style" ), errorMessage );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case DatasourceDatabase:
|
||||
{
|
||||
QString infoWindowTitle = QObject::tr( "Save style to DB (%1)" ).arg( mLayer->providerType() );
|
||||
|
||||
QgsMapLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
|
||||
|
||||
if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), dbSettings.name, errorMessage ) )
|
||||
{
|
||||
if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
|
||||
QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
|
||||
QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( !errorMessage.isEmpty() )
|
||||
{
|
||||
QMessageBox::warning( this, infoWindowTitle, errorMessage );
|
||||
return;
|
||||
}
|
||||
|
||||
mLayer->saveStyleToDatabase( dbSettings.name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, errorMessage, dlg.styleCategories() );
|
||||
|
||||
if ( !errorMessage.isNull() )
|
||||
{
|
||||
QMessageBox::warning( this, infoWindowTitle, errorMessage );
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information( this, infoWindowTitle, tr( "Style saved" ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UserDatabase:
|
||||
{
|
||||
QString infoWindowTitle = tr( "Save default style to local database" );
|
||||
errorMessage = mLayer->saveDefaultStyle( defaultLoadedFlag, dlg.styleCategories() );
|
||||
if ( !defaultLoadedFlag )
|
||||
{
|
||||
QMessageBox::warning( this, infoWindowTitle, errorMessage );
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information( this, infoWindowTitle, tr( "Style saved" ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayerPropertiesDialog::loadStyle()
|
||||
{
|
||||
QString errorMsg;
|
||||
QStringList ids, names, descriptions;
|
||||
|
||||
//get the list of styles in the db
|
||||
int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
|
||||
QgsMapLayerLoadStyleDialog dlg( mLayer, this );
|
||||
dlg.initializeLists( ids, names, descriptions, sectionLimit );
|
||||
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
mOldStyle = mLayer->styleManager()->style( mLayer->styleManager()->currentStyle() );
|
||||
QgsMapLayer::StyleCategories categories = dlg.styleCategories();
|
||||
StyleType type = dlg.currentStyleType();
|
||||
bool defaultLoadedFlag = false;
|
||||
switch ( type )
|
||||
{
|
||||
case QML:
|
||||
case SLD:
|
||||
{
|
||||
QString filePath = dlg.filePath();
|
||||
if ( type == SLD )
|
||||
{
|
||||
errorMsg = mLayer->loadSldStyle( filePath, defaultLoadedFlag );
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = mLayer->loadNamedStyle( filePath, defaultLoadedFlag, true, categories );
|
||||
}
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the user know what went wrong
|
||||
QMessageBox::warning( this, tr( "Load Style" ), errorMsg );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DatasourceDatabase:
|
||||
{
|
||||
QString selectedStyleId = dlg.selectedStyleId();
|
||||
|
||||
QString qmlStyle = mLayer->getStyleFromDatabase( selectedStyleId, errorMsg );
|
||||
if ( !errorMsg.isNull() )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Load Styles from Database" ), errorMsg );
|
||||
return;
|
||||
}
|
||||
|
||||
QDomDocument myDocument( QStringLiteral( "qgis" ) );
|
||||
myDocument.setContent( qmlStyle );
|
||||
|
||||
if ( mLayer->importNamedStyle( myDocument, errorMsg, categories ) )
|
||||
{
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Load Styles from Database" ),
|
||||
tr( "The retrieved style is not a valid named style. Error message: %1" )
|
||||
.arg( errorMsg ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UserDatabase:
|
||||
{
|
||||
errorMsg = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, true, categories );
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Load Default Style" ), errorMsg );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
activateWindow(); // set focus back to properties dialog
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayerPropertiesDialog::storeCurrentStyleForUndo()
|
||||
{
|
||||
if ( !mLayer )
|
||||
|
@ -42,21 +42,6 @@ class GUI_EXPORT QgsLayerPropertiesDialog : public QgsOptionsDialogBase SIP_ABST
|
||||
|
||||
public:
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* Style storage type.
|
||||
*/
|
||||
enum StyleType
|
||||
{
|
||||
QML,
|
||||
SLD,
|
||||
DatasourceDatabase,
|
||||
UserDatabase,
|
||||
};
|
||||
Q_ENUM( StyleType )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Constructor for QgsLayerPropertiesDialog.
|
||||
*
|
||||
@ -81,27 +66,6 @@ class GUI_EXPORT QgsLayerPropertiesDialog : public QgsOptionsDialogBase SIP_ABST
|
||||
*/
|
||||
virtual void addPropertiesPageFactory( const QgsMapLayerConfigWidgetFactory *factory );
|
||||
|
||||
/**
|
||||
* Saves the default style when appropriate button is pressed
|
||||
*
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
void saveDefaultStyle();
|
||||
|
||||
/**
|
||||
* Triggers a dialog to load a saved style
|
||||
*
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
void loadStyle();
|
||||
|
||||
/**
|
||||
* Saves a style when appriate button is pressed
|
||||
*
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
void saveStyleAs();
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "qgsmaplayerloadstyledialog.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgslayerpropertiesdialog.h"
|
||||
#include "qgsvectorlayerproperties.h"
|
||||
#include "qgsmaplayerstylecategoriesmodel.h"
|
||||
#include "qgshelp.h"
|
||||
#include "qgsapplication.h"
|
||||
@ -43,29 +43,50 @@ QgsMapLayerLoadStyleDialog::QgsMapLayerLoadStyleDialog( QgsMapLayer *layer, QWid
|
||||
|
||||
QgsSettings settings;
|
||||
|
||||
QString providerName = mLayer->providerType();
|
||||
if ( providerName == QLatin1String( "ogr" ) )
|
||||
{
|
||||
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( mLayer );
|
||||
providerName = vl->dataProvider()->storageType();
|
||||
if ( providerName == QLatin1String( "GPKG" ) )
|
||||
providerName = QStringLiteral( "GeoPackage" );
|
||||
}
|
||||
|
||||
const QString myLastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
|
||||
|
||||
// load style type combobox
|
||||
connect( mStyleTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
|
||||
{
|
||||
const QgsLayerPropertiesDialog::StyleType type = currentStyleType();
|
||||
mFileLabel->setVisible( type != QgsLayerPropertiesDialog::StyleType::DatasourceDatabase && type != QgsLayerPropertiesDialog::StyleType::UserDatabase );
|
||||
mFileWidget->setVisible( type != QgsLayerPropertiesDialog::StyleType::DatasourceDatabase && type != QgsLayerPropertiesDialog::StyleType::UserDatabase );
|
||||
mFromDbWidget->setVisible( type == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase );
|
||||
mDeleteButton->setVisible( type == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase && mLayer->dataProvider()->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::DeleteFromDatabase ) );
|
||||
const QgsVectorLayerProperties::StyleType type = currentStyleType();
|
||||
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( mLayer );
|
||||
mFileLabel->setVisible( !vl || ( type != QgsVectorLayerProperties::StyleType::DB && type != QgsVectorLayerProperties::StyleType::Local ) );
|
||||
mFileWidget->setVisible( !vl || ( type != QgsVectorLayerProperties::StyleType::DB && type != QgsVectorLayerProperties::StyleType::Local ) );
|
||||
if ( vl )
|
||||
{
|
||||
mFromDbWidget->setVisible( type == QgsVectorLayerProperties::StyleType::DB );
|
||||
mDeleteButton->setVisible( type == QgsVectorLayerProperties::StyleType::DB && vl->dataProvider()->isDeleteStyleFromDatabaseSupported() );
|
||||
}
|
||||
else
|
||||
{
|
||||
mFromDbWidget->setVisible( false );
|
||||
mDeleteButton->setVisible( false );
|
||||
}
|
||||
|
||||
mStyleCategoriesListView->setEnabled( currentStyleType() != QgsLayerPropertiesDialog::StyleType::SLD );
|
||||
mStyleCategoriesListView->setEnabled( !vl || currentStyleType() != QgsVectorLayerProperties::StyleType::SLD );
|
||||
updateLoadButtonState();
|
||||
} );
|
||||
mStyleTypeComboBox->addItem( tr( "From file" ), QgsLayerPropertiesDialog::QML ); // QML is used as entry, but works for SLD too, see currentStyleType()
|
||||
mStyleTypeComboBox->addItem( tr( "Default from local database" ), QgsLayerPropertiesDialog::UserDatabase );
|
||||
mStyleTypeComboBox->addItem( tr( "From File" ), QgsVectorLayerProperties::QML ); // QML is used as entry, but works for SLD too, see currentStyleType()
|
||||
mStyleTypeComboBox->addItem( tr( "Default from local database" ), QgsVectorLayerProperties::Local );
|
||||
|
||||
if ( mLayer->dataProvider()->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
|
||||
if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( mLayer ) )
|
||||
{
|
||||
mStyleTypeComboBox->addItem( tr( "From datasource database" ), QgsLayerPropertiesDialog::StyleType::DatasourceDatabase );
|
||||
if ( settings.value( QStringLiteral( "style/lastLoadStyleTypeSelection" ) ) == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase )
|
||||
if ( vl->dataProvider()->isSaveAndLoadStyleToDatabaseSupported() )
|
||||
{
|
||||
mStyleTypeComboBox->setCurrentIndex( mStyleTypeComboBox->findData( QgsLayerPropertiesDialog::StyleType::DatasourceDatabase ) );
|
||||
mStyleTypeComboBox->addItem( tr( "From Database (%1)" ).arg( providerName ), QgsVectorLayerProperties::StyleType::DB );
|
||||
if ( settings.value( QStringLiteral( "style/lastLoadStyleTypeSelection" ) ) == QgsVectorLayerProperties::StyleType::DB )
|
||||
{
|
||||
mStyleTypeComboBox->setCurrentIndex( mStyleTypeComboBox->findData( QgsVectorLayerProperties::StyleType::DB ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +124,8 @@ QgsMapLayerLoadStyleDialog::QgsMapLayerLoadStyleDialog( QgsMapLayer *layer, QWid
|
||||
mFileWidget->setDefaultRoot( myLastUsedDir );
|
||||
connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
|
||||
{
|
||||
mStyleCategoriesListView->setEnabled( currentStyleType() != QgsLayerPropertiesDialog::SLD );
|
||||
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( mLayer );
|
||||
mStyleCategoriesListView->setEnabled( !vl || currentStyleType() != QgsVectorLayerProperties::SLD );
|
||||
QgsSettings settings;
|
||||
const QFileInfo tmplFileInfo( path );
|
||||
settings.setValue( QStringLiteral( "style/lastStyleDir" ), tmplFileInfo.absolutePath() );
|
||||
@ -145,14 +167,14 @@ QgsMapLayer::StyleCategories QgsMapLayerLoadStyleDialog::styleCategories() const
|
||||
return mModel->categories();
|
||||
}
|
||||
|
||||
QgsLayerPropertiesDialog::StyleType QgsMapLayerLoadStyleDialog::currentStyleType() const
|
||||
QgsVectorLayerProperties::StyleType QgsMapLayerLoadStyleDialog::currentStyleType() const
|
||||
{
|
||||
QgsLayerPropertiesDialog::StyleType type = mStyleTypeComboBox->currentData().value<QgsLayerPropertiesDialog::StyleType>();
|
||||
if ( type == QgsLayerPropertiesDialog::QML )
|
||||
QgsVectorLayerProperties::StyleType type = mStyleTypeComboBox->currentData().value<QgsVectorLayerProperties::StyleType>();
|
||||
if ( type == QgsVectorLayerProperties::QML )
|
||||
{
|
||||
const QFileInfo fi( mFileWidget->filePath() );
|
||||
if ( fi.exists() && fi.suffix().compare( QStringLiteral( "sld" ), Qt::CaseInsensitive ) == 0 )
|
||||
type = QgsLayerPropertiesDialog::SLD;
|
||||
type = QgsVectorLayerProperties::SLD;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@ -276,6 +298,10 @@ void QgsMapLayerLoadStyleDialog::accept()
|
||||
|
||||
void QgsMapLayerLoadStyleDialog::deleteStyleFromDB()
|
||||
{
|
||||
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( mLayer );
|
||||
if ( !vl )
|
||||
return;
|
||||
|
||||
QString msgError;
|
||||
const QString opInfo = QObject::tr( "Delete style %1 from %2" ).arg( mSelectedStyleName, mLayer->providerType() );
|
||||
|
||||
@ -284,7 +310,7 @@ void QgsMapLayerLoadStyleDialog::deleteStyleFromDB()
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
|
||||
return;
|
||||
|
||||
mLayer->deleteStyleFromDatabase( mSelectedStyleId, msgError );
|
||||
vl->deleteStyleFromDatabase( mSelectedStyleId, msgError );
|
||||
if ( !msgError.isNull() )
|
||||
{
|
||||
QgsDebugError( opInfo + " failed." );
|
||||
@ -302,7 +328,7 @@ void QgsMapLayerLoadStyleDialog::deleteStyleFromDB()
|
||||
QString errorMsg;
|
||||
QStringList ids, names, descriptions;
|
||||
//get the list of styles in the db
|
||||
const int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
|
||||
const int sectionLimit = vl->listStylesInDatabase( ids, names, descriptions, errorMsg );
|
||||
if ( !errorMsg.isNull() )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Error occurred while retrieving styles from database" ), errorMsg );
|
||||
@ -316,12 +342,19 @@ void QgsMapLayerLoadStyleDialog::deleteStyleFromDB()
|
||||
|
||||
void QgsMapLayerLoadStyleDialog::updateLoadButtonState()
|
||||
{
|
||||
const QgsLayerPropertiesDialog::StyleType type = currentStyleType();
|
||||
mLoadButton->setEnabled( ( type == QgsLayerPropertiesDialog::DatasourceDatabase
|
||||
&& ( mRelatedTable->selectionModel()->hasSelection() || mOthersTable->selectionModel()->hasSelection()
|
||||
) ) ||
|
||||
( type != QgsLayerPropertiesDialog::DatasourceDatabase && !mFileWidget->filePath().isEmpty() ) ||
|
||||
type == QgsLayerPropertiesDialog::UserDatabase );
|
||||
const QgsVectorLayerProperties::StyleType type = currentStyleType();
|
||||
if ( mLayer->type() == Qgis::LayerType::Vector )
|
||||
{
|
||||
mLoadButton->setEnabled( ( type == QgsVectorLayerProperties::DB
|
||||
&& ( mRelatedTable->selectionModel()->hasSelection() || mOthersTable->selectionModel()->hasSelection()
|
||||
) ) ||
|
||||
( type != QgsVectorLayerProperties::DB && !mFileWidget->filePath().isEmpty() ) ||
|
||||
type == QgsVectorLayerProperties::Local );
|
||||
}
|
||||
else
|
||||
{
|
||||
mLoadButton->setEnabled( !mFileWidget->filePath().isEmpty() );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMapLayerLoadStyleDialog::showHelp()
|
||||
|
@ -54,9 +54,9 @@ class GUI_EXPORT QgsMapLayerLoadStyleDialog : public QDialog, private Ui::QgsVec
|
||||
QgsMapLayer::StyleCategories styleCategories() const;
|
||||
|
||||
/**
|
||||
* Returns the selected style type.
|
||||
* Returns the selected vector style type, for vector layers only.
|
||||
*/
|
||||
QgsLayerPropertiesDialog::StyleType currentStyleType() const;
|
||||
QgsVectorLayerProperties::StyleType currentStyleType() const;
|
||||
|
||||
/**
|
||||
* Returns the file extension for the selected layer style source file.
|
||||
|
@ -30,8 +30,6 @@ QgsMapLayerStyleCategoriesModel::QgsMapLayerStyleCategoriesModel( Qgis::LayerTyp
|
||||
break;
|
||||
|
||||
case Qgis::LayerType::Raster:
|
||||
mCategoryList << QgsMapLayer::StyleCategory::Symbology << QgsMapLayer::StyleCategory::AllStyleCategories;
|
||||
break;
|
||||
case Qgis::LayerType::Annotation:
|
||||
case Qgis::LayerType::Plugin:
|
||||
case Qgis::LayerType::Mesh:
|
||||
@ -43,11 +41,7 @@ QgsMapLayerStyleCategoriesModel::QgsMapLayerStyleCategoriesModel( Qgis::LayerTyp
|
||||
}
|
||||
|
||||
// move All categories to top
|
||||
int idxAllStyleCategories = mCategoryList.indexOf( QgsMapLayer::AllStyleCategories );
|
||||
if ( idxAllStyleCategories > 0 )
|
||||
{
|
||||
mCategoryList.move( idxAllStyleCategories, 0 );
|
||||
}
|
||||
mCategoryList.move( mCategoryList.indexOf( QgsMapLayer::AllStyleCategories ), 0 );
|
||||
}
|
||||
|
||||
void QgsMapLayerStyleCategoriesModel::setCategories( QgsMapLayer::StyleCategories categories )
|
||||
@ -75,7 +69,7 @@ void QgsMapLayerStyleCategoriesModel::setShowAllCategories( bool showAll )
|
||||
int QgsMapLayerStyleCategoriesModel::rowCount( const QModelIndex & ) const
|
||||
{
|
||||
int count = mCategoryList.count();
|
||||
if ( count > 0 && !mShowAllCategories )
|
||||
if ( !mShowAllCategories )
|
||||
count--;
|
||||
return count;
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer *lyr, QgsMapCanv
|
||||
setMetadataWidget( mMetadataWidget, mOptsPage_Metadata );
|
||||
|
||||
QMenu *menuStyle = new QMenu( this );
|
||||
menuStyle->addAction( tr( "Load Style…" ), this, &QgsRasterLayerProperties::loadStyle );
|
||||
menuStyle->addAction( tr( "Load Style…" ), this, &QgsRasterLayerProperties::loadStyleFromFile );
|
||||
menuStyle->addAction( tr( "Save Style…" ), this, &QgsRasterLayerProperties::saveStyleAs );
|
||||
menuStyle->addSeparator();
|
||||
menuStyle->addAction( tr( "Save as Default" ), this, &QgsRasterLayerProperties::saveStyleAsDefault );
|
||||
@ -1600,6 +1600,66 @@ void QgsRasterLayerProperties::saveDefaultStyle()
|
||||
saveStyleAsDefault();
|
||||
}
|
||||
|
||||
void QgsRasterLayerProperties::loadStyle()
|
||||
{
|
||||
loadStyleFromFile();
|
||||
}
|
||||
|
||||
void QgsRasterLayerProperties::saveStyleAs()
|
||||
{
|
||||
QgsSettings settings;
|
||||
QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
|
||||
|
||||
QString selectedFilter;
|
||||
QString outputFileName = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
tr( "Save layer properties as style file" ),
|
||||
lastUsedDir,
|
||||
tr( "QGIS Layer Style File" ) + " (*.qml)" + ";;" + tr( "Styled Layer Descriptor" ) + " (*.sld)",
|
||||
&selectedFilter );
|
||||
if ( outputFileName.isEmpty() )
|
||||
return;
|
||||
|
||||
StyleType type;
|
||||
// use selectedFilter to set style type
|
||||
if ( selectedFilter.contains( QStringLiteral( ".qml" ), Qt::CaseInsensitive ) )
|
||||
{
|
||||
outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "qml" ) );
|
||||
type = StyleType::QML;
|
||||
}
|
||||
else
|
||||
{
|
||||
outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "sld" ) );
|
||||
type = StyleType::SLD;
|
||||
}
|
||||
|
||||
apply(); // make sure the style to save is up-to-date
|
||||
|
||||
// then export style
|
||||
bool defaultLoadedFlag = false;
|
||||
QString message;
|
||||
switch ( type )
|
||||
{
|
||||
case QML:
|
||||
{
|
||||
message = mRasterLayer->saveNamedStyle( outputFileName, defaultLoadedFlag );
|
||||
break;
|
||||
}
|
||||
case SLD:
|
||||
{
|
||||
message = mRasterLayer->saveSldStyle( outputFileName, defaultLoadedFlag );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( outputFileName ).absolutePath() );
|
||||
sync();
|
||||
}
|
||||
else
|
||||
QMessageBox::information( this, tr( "Save Style" ), message );
|
||||
}
|
||||
|
||||
void QgsRasterLayerProperties::restoreWindowModality()
|
||||
{
|
||||
hide();
|
||||
|
@ -94,6 +94,20 @@ class GUI_EXPORT QgsRasterLayerProperties : public QgsLayerPropertiesDialog, pri
|
||||
*/
|
||||
Q_DECL_DEPRECATED void saveDefaultStyle() SIP_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Loads a saved style when appropriate button is pressed
|
||||
*
|
||||
* \deprecated use loadStyleFromFile() instead.
|
||||
*/
|
||||
Q_DECL_DEPRECATED void loadStyle() SIP_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Saves a style when appriate button is pressed
|
||||
*
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
void saveStyleAs();
|
||||
|
||||
protected slots:
|
||||
void optionsStackedWidget_CurrentChanged( int index ) FINAL;
|
||||
void apply() FINAL;
|
||||
|
@ -48,11 +48,12 @@
|
||||
#include "qgsrendererpropertiesdialog.h"
|
||||
#include "qgsstyle.h"
|
||||
#include "qgsauxiliarystorage.h"
|
||||
#include "qgsmaplayersavestyledialog.h"
|
||||
#include "qgsmaplayerserverproperties.h"
|
||||
#include "qgsnewauxiliarylayerdialog.h"
|
||||
#include "qgsnewauxiliaryfielddialog.h"
|
||||
#include "qgslabelinggui.h"
|
||||
#include "qgsvectorlayersavestyledialog.h"
|
||||
#include "qgsmaplayerloadstyledialog.h"
|
||||
#include "qgsmessagebar.h"
|
||||
#include "qgssymbolwidgetcontext.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
@ -1038,9 +1039,217 @@ void QgsVectorLayerProperties::mCrsSelector_crsChanged( const QgsCoordinateRefer
|
||||
mMetadataWidget->crsChanged();
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::loadDefaultStyle()
|
||||
{
|
||||
QString msg;
|
||||
bool defaultLoadedFlag = false;
|
||||
|
||||
const QgsVectorDataProvider *provider = mLayer->dataProvider();
|
||||
if ( !provider )
|
||||
return;
|
||||
if ( provider->isSaveAndLoadStyleToDatabaseSupported() )
|
||||
{
|
||||
QMessageBox askToUser;
|
||||
askToUser.setText( tr( "Load default style from: " ) );
|
||||
askToUser.setIcon( QMessageBox::Question );
|
||||
askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
|
||||
askToUser.addButton( tr( "Local Database" ), QMessageBox::NoRole );
|
||||
askToUser.addButton( tr( "Datasource Database" ), QMessageBox::YesRole );
|
||||
|
||||
switch ( askToUser.exec() )
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case 2:
|
||||
msg = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag );
|
||||
if ( !defaultLoadedFlag )
|
||||
{
|
||||
//something went wrong - let them know why
|
||||
QMessageBox::information( this, tr( "Default Style" ), msg );
|
||||
}
|
||||
if ( msg.compare( tr( "Loaded from Provider" ) ) )
|
||||
{
|
||||
QMessageBox::information( this, tr( "Default Style" ),
|
||||
tr( "No default style was found for this layer." ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString myMessage = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, true );
|
||||
// QString myMessage = layer->loadDefaultStyle( defaultLoadedFlag );
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
// all worked OK so no need to inform user
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
//something went wrong - let them know why
|
||||
QMessageBox::information( this, tr( "Default Style" ), myMessage );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::saveDefaultStyle()
|
||||
{
|
||||
QString errorMsg;
|
||||
const QgsVectorDataProvider *provider = mLayer->dataProvider();
|
||||
if ( !provider )
|
||||
return;
|
||||
if ( provider->isSaveAndLoadStyleToDatabaseSupported() )
|
||||
{
|
||||
QMessageBox askToUser;
|
||||
askToUser.setText( tr( "Save default style to: " ) );
|
||||
askToUser.setIcon( QMessageBox::Question );
|
||||
askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
|
||||
askToUser.addButton( tr( "Local Database" ), QMessageBox::NoRole );
|
||||
askToUser.addButton( tr( "Datasource Database" ), QMessageBox::YesRole );
|
||||
|
||||
switch ( askToUser.exec() )
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case 2:
|
||||
{
|
||||
apply();
|
||||
QString errorMessage;
|
||||
if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), QString(), errorMessage ) )
|
||||
{
|
||||
if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
|
||||
QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
|
||||
QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( !errorMessage.isEmpty() )
|
||||
{
|
||||
QMessageBox::warning( nullptr, QObject::tr( "Save style in database" ),
|
||||
errorMessage );
|
||||
return;
|
||||
}
|
||||
|
||||
mLayer->saveStyleToDatabase( QString(), QString(), true, QString(), errorMsg );
|
||||
if ( errorMsg.isNull() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QgsLayerPropertiesDialog::saveStyleAsDefault();
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::saveStyleAs()
|
||||
{
|
||||
if ( !mLayer->dataProvider() )
|
||||
return;
|
||||
QgsVectorLayerSaveStyleDialog dlg( mLayer );
|
||||
QgsSettings settings;
|
||||
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
apply();
|
||||
|
||||
bool defaultLoadedFlag = false;
|
||||
QString errorMessage;
|
||||
|
||||
StyleType type = dlg.currentStyleType();
|
||||
switch ( type )
|
||||
{
|
||||
case QML:
|
||||
case SLD:
|
||||
{
|
||||
QString filePath = dlg.outputFilePath();
|
||||
if ( type == QML )
|
||||
errorMessage = mLayer->saveNamedStyle( filePath, defaultLoadedFlag, dlg.styleCategories() );
|
||||
else
|
||||
{
|
||||
const QgsSldExportContext sldContext { dlg.sldExportOptions(), Qgis::SldExportVendorExtension::NoVendorExtension, filePath };
|
||||
errorMessage = mLayer->saveSldStyleV2( defaultLoadedFlag, sldContext );
|
||||
}
|
||||
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
syncToLayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the user know what went wrong
|
||||
QMessageBox::information( this, tr( "Save Style" ), errorMessage );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case DB:
|
||||
{
|
||||
QString infoWindowTitle = QObject::tr( "Save style to DB (%1)" ).arg( mLayer->providerType() );
|
||||
|
||||
QgsVectorLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
|
||||
|
||||
if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), dbSettings.name, errorMessage ) )
|
||||
{
|
||||
if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
|
||||
QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
|
||||
QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( !errorMessage.isEmpty() )
|
||||
{
|
||||
mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
|
||||
return;
|
||||
}
|
||||
|
||||
mLayer->saveStyleToDatabase( dbSettings.name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, errorMessage, dlg.styleCategories() );
|
||||
|
||||
if ( !errorMessage.isNull() )
|
||||
{
|
||||
mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
|
||||
}
|
||||
else
|
||||
{
|
||||
mMessageBar->pushMessage( infoWindowTitle, tr( "Style saved" ), Qgis::MessageLevel::Success );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Local:
|
||||
{
|
||||
QString infoWindowTitle = tr( "Save default style to local database" );
|
||||
errorMessage = mLayer->saveDefaultStyle( defaultLoadedFlag, dlg.styleCategories() );
|
||||
if ( !defaultLoadedFlag )
|
||||
{
|
||||
mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
|
||||
}
|
||||
else
|
||||
{
|
||||
mMessageBar->pushMessage( infoWindowTitle, tr( "Style saved" ), Qgis::MessageLevel::Success );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::saveMultipleStylesAs()
|
||||
{
|
||||
QgsMapLayerSaveStyleDialog dlg( mLayer );
|
||||
QgsVectorLayerSaveStyleDialog dlg( mLayer );
|
||||
dlg.setSaveOnlyCurrentStyle( false );
|
||||
QgsSettings settings;
|
||||
|
||||
@ -1110,13 +1319,13 @@ void QgsVectorLayerProperties::saveMultipleStylesAs()
|
||||
|
||||
break;
|
||||
}
|
||||
case DatasourceDatabase:
|
||||
case DB:
|
||||
{
|
||||
QString infoWindowTitle = QObject::tr( "Save style '%1' to DB (%2)" )
|
||||
.arg( styleName, mLayer->providerType() );
|
||||
QString msgError;
|
||||
|
||||
QgsMapLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
|
||||
QgsVectorLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
|
||||
|
||||
// If a name is defined, we add _1 etc. else we use the style name
|
||||
QString name { dbSettings.name };
|
||||
@ -1149,7 +1358,7 @@ void QgsVectorLayerProperties::saveMultipleStylesAs()
|
||||
}
|
||||
else if ( !errorMessage.isEmpty() )
|
||||
{
|
||||
QMessageBox::warning( this, infoWindowTitle, errorMessage );
|
||||
mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1157,15 +1366,16 @@ void QgsVectorLayerProperties::saveMultipleStylesAs()
|
||||
|
||||
if ( !msgError.isNull() )
|
||||
{
|
||||
QMessageBox::warning( this, infoWindowTitle, msgError );
|
||||
mMessageBar->pushMessage( infoWindowTitle, msgError, Qgis::MessageLevel::Warning );
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information( this, infoWindowTitle, tr( "Style '%1' saved" ).arg( styleName ) );
|
||||
mMessageBar->pushMessage( infoWindowTitle, tr( "Style '%1' saved" ).arg( styleName ),
|
||||
Qgis::MessageLevel::Success );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UserDatabase:
|
||||
case Local:
|
||||
break;
|
||||
}
|
||||
styleIndex ++;
|
||||
@ -1205,6 +1415,98 @@ void QgsVectorLayerProperties::aboutToShowStyleMenu()
|
||||
QgsMapLayerStyleGuiUtils::instance()->addStyleManagerActions( m, mLayer );
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::loadStyle()
|
||||
{
|
||||
QgsSettings settings; // where we keep last used filter in persistent state
|
||||
|
||||
QString errorMsg;
|
||||
QStringList ids, names, descriptions;
|
||||
|
||||
//get the list of styles in the db
|
||||
int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
|
||||
QgsMapLayerLoadStyleDialog dlg( mLayer, this );
|
||||
dlg.initializeLists( ids, names, descriptions, sectionLimit );
|
||||
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
mOldStyle = mLayer->styleManager()->style( mLayer->styleManager()->currentStyle() );
|
||||
QgsMapLayer::StyleCategories categories = dlg.styleCategories();
|
||||
StyleType type = dlg.currentStyleType();
|
||||
bool defaultLoadedFlag = false;
|
||||
switch ( type )
|
||||
{
|
||||
case QML:
|
||||
case SLD:
|
||||
{
|
||||
QString filePath = dlg.filePath();
|
||||
if ( type == SLD )
|
||||
{
|
||||
errorMsg = mLayer->loadSldStyle( filePath, defaultLoadedFlag );
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = mLayer->loadNamedStyle( filePath, defaultLoadedFlag, true, categories );
|
||||
}
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the user know what went wrong
|
||||
QMessageBox::warning( this, tr( "Load Style" ), errorMsg );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DB:
|
||||
{
|
||||
QString selectedStyleId = dlg.selectedStyleId();
|
||||
|
||||
QString qmlStyle = mLayer->getStyleFromDatabase( selectedStyleId, errorMsg );
|
||||
if ( !errorMsg.isNull() )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Load Styles from Database" ), errorMsg );
|
||||
return;
|
||||
}
|
||||
|
||||
QDomDocument myDocument( QStringLiteral( "qgis" ) );
|
||||
myDocument.setContent( qmlStyle );
|
||||
|
||||
if ( mLayer->importNamedStyle( myDocument, errorMsg, categories ) )
|
||||
{
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Load Styles from Database" ),
|
||||
tr( "The retrieved style is not a valid named style. Error message: %1" )
|
||||
.arg( errorMsg ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Local:
|
||||
{
|
||||
errorMsg = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, true, categories );
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
syncToLayer();
|
||||
apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Load Default Style" ), errorMsg );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
activateWindow(); // set focus back to properties dialog
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::mButtonAddJoin_clicked()
|
||||
{
|
||||
if ( !mLayer )
|
||||
|
@ -59,11 +59,49 @@ class GUI_EXPORT QgsVectorLayerProperties : public QgsLayerPropertiesDialog, pri
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
#ifndef SIP_RUN
|
||||
enum StyleType
|
||||
{
|
||||
QML,
|
||||
SLD,
|
||||
DB,
|
||||
Local,
|
||||
};
|
||||
Q_ENUM( StyleType )
|
||||
#endif
|
||||
|
||||
QgsVectorLayerProperties( QgsMapCanvas *canvas, QgsMessageBar *messageBar, QgsVectorLayer *lyr = nullptr, QWidget *parent = nullptr, Qt::WindowFlags fl = QgsGuiUtils::ModalDialogFlags );
|
||||
|
||||
bool eventFilter( QObject *obj, QEvent *ev ) override;
|
||||
|
||||
/**
|
||||
* Loads the default style when appropriate button is pressed
|
||||
*
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
void loadDefaultStyle();
|
||||
|
||||
/**
|
||||
* Saves the default style when appropriate button is pressed
|
||||
*
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
void saveDefaultStyle();
|
||||
|
||||
/**
|
||||
* Loads a saved style when appropriate button is pressed
|
||||
*
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
void loadStyle();
|
||||
|
||||
/**
|
||||
* Saves a style when appriate button is pressed
|
||||
*
|
||||
* \since QGIS 3.30
|
||||
*/
|
||||
void saveStyleAs();
|
||||
|
||||
protected slots:
|
||||
void optionsStackedWidget_CurrentChanged( int index ) final;
|
||||
void syncToLayer() FINAL;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
qgsmaplayersavestyledialog.h
|
||||
qgsvectorlayersavestyledialog.h
|
||||
--------------------------------------
|
||||
Date : September 2018
|
||||
Copyright : (C) 2018 by Denis Rouzaud
|
||||
@ -15,17 +15,16 @@
|
||||
|
||||
#include <QListWidgetItem>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "qgsmaplayersavestyledialog.h"
|
||||
#include "qgsvectorlayersavestyledialog.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgshelp.h"
|
||||
#include "qgsgui.h"
|
||||
#include "qgsmaplayerstylecategoriesmodel.h"
|
||||
#include "qgsmaplayerstylemanager.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
QgsMapLayerSaveStyleDialog::QgsMapLayerSaveStyleDialog( QgsMapLayer *layer, QWidget *parent )
|
||||
QgsVectorLayerSaveStyleDialog::QgsVectorLayerSaveStyleDialog( QgsVectorLayer *layer, QWidget *parent )
|
||||
: QDialog( parent )
|
||||
, mLayer( layer )
|
||||
{
|
||||
@ -39,28 +38,28 @@ QgsMapLayerSaveStyleDialog::QgsMapLayerSaveStyleDialog( QgsMapLayer *layer, QWid
|
||||
// save style type combobox
|
||||
connect( mStyleTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
|
||||
{
|
||||
const QgsLayerPropertiesDialog::StyleType type = currentStyleType();
|
||||
mFileLabel->setVisible( type != QgsLayerPropertiesDialog::DatasourceDatabase && type != QgsLayerPropertiesDialog::UserDatabase );
|
||||
mFileWidget->setVisible( type != QgsLayerPropertiesDialog::DatasourceDatabase && type != QgsLayerPropertiesDialog::UserDatabase );
|
||||
mSaveToDbWidget->setVisible( type == QgsLayerPropertiesDialog::DatasourceDatabase );
|
||||
mSaveToSldWidget->setVisible( type == QgsLayerPropertiesDialog::SLD && layer->type() == Qgis::LayerType::Vector && static_cast<QgsVectorLayer *>( layer )->geometryType() == Qgis::GeometryType::Polygon );
|
||||
mStyleCategoriesListView->setEnabled( type != QgsLayerPropertiesDialog::SLD );
|
||||
mFileWidget->setFilter( type == QgsLayerPropertiesDialog::QML ? tr( "QGIS Layer Style File (*.qml)" ) : tr( "SLD File (*.sld)" ) );
|
||||
const QgsVectorLayerProperties::StyleType type = currentStyleType();
|
||||
mFileLabel->setVisible( type != QgsVectorLayerProperties::DB && type != QgsVectorLayerProperties::Local );
|
||||
mFileWidget->setVisible( type != QgsVectorLayerProperties::DB && type != QgsVectorLayerProperties::Local );
|
||||
mSaveToDbWidget->setVisible( type == QgsVectorLayerProperties::DB );
|
||||
mSaveToSldWidget->setVisible( type == QgsVectorLayerProperties::SLD && layer->geometryType() == Qgis::GeometryType::Polygon );
|
||||
mStyleCategoriesListView->setEnabled( type != QgsVectorLayerProperties::SLD );
|
||||
mFileWidget->setFilter( type == QgsVectorLayerProperties::QML ? tr( "QGIS Layer Style File (*.qml)" ) : tr( "SLD File (*.sld)" ) );
|
||||
updateSaveButtonState();
|
||||
} );
|
||||
|
||||
// Save to DB setup
|
||||
connect( mDbStyleNameEdit, &QLineEdit::textChanged, this, &QgsMapLayerSaveStyleDialog::updateSaveButtonState );
|
||||
connect( mDbStyleNameEdit, &QLineEdit::textChanged, this, &QgsVectorLayerSaveStyleDialog::updateSaveButtonState );
|
||||
mDbStyleDescriptionEdit->setTabChangesFocus( true );
|
||||
setTabOrder( mDbStyleNameEdit, mDbStyleDescriptionEdit );
|
||||
setTabOrder( mDbStyleDescriptionEdit, mDbStyleUseAsDefault );
|
||||
mDbStyleUIFileWidget->setDefaultRoot( myLastUsedDir );
|
||||
mDbStyleUIFileWidget->setFilter( tr( "Qt Designer UI file (*.ui)" ) );
|
||||
connect( mDbStyleUIFileWidget, &QgsFileWidget::fileChanged, this, &QgsMapLayerSaveStyleDialog::readUiFileContent );
|
||||
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsMapLayerSaveStyleDialog::showHelp );
|
||||
connect( mDbStyleUIFileWidget, &QgsFileWidget::fileChanged, this, &QgsVectorLayerSaveStyleDialog::readUiFileContent );
|
||||
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsVectorLayerSaveStyleDialog::showHelp );
|
||||
|
||||
// save to file setup
|
||||
connect( mFileWidget, &QgsFileWidget::fileChanged, this, &QgsMapLayerSaveStyleDialog::updateSaveButtonState );
|
||||
connect( mFileWidget, &QgsFileWidget::fileChanged, this, &QgsVectorLayerSaveStyleDialog::updateSaveButtonState );
|
||||
mFileWidget->setStorageMode( QgsFileWidget::SaveFile );
|
||||
mFileWidget->setDefaultRoot( myLastUsedDir );
|
||||
connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
|
||||
@ -82,32 +81,40 @@ QgsMapLayerSaveStyleDialog::QgsMapLayerSaveStyleDialog( QgsMapLayer *layer, QWid
|
||||
|
||||
}
|
||||
|
||||
void QgsMapLayerSaveStyleDialog::populateStyleComboBox()
|
||||
void QgsVectorLayerSaveStyleDialog::populateStyleComboBox()
|
||||
{
|
||||
mStyleTypeComboBox->clear();
|
||||
mStyleTypeComboBox->addItem( tr( "As QGIS QML style file" ), QgsLayerPropertiesDialog::QML );
|
||||
mStyleTypeComboBox->addItem( tr( "As SLD style file" ), QgsLayerPropertiesDialog::SLD );
|
||||
QString providerName = mLayer->providerType();
|
||||
if ( providerName == QLatin1String( "ogr" ) )
|
||||
{
|
||||
providerName = mLayer->dataProvider()->storageType();
|
||||
if ( providerName == QLatin1String( "GPKG" ) )
|
||||
providerName = QStringLiteral( "GeoPackage" );
|
||||
}
|
||||
|
||||
if ( mLayer->dataProvider()->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::SaveToDatabase ) )
|
||||
mStyleTypeComboBox->addItem( tr( "In datasource database" ), QgsLayerPropertiesDialog::DatasourceDatabase );
|
||||
mStyleTypeComboBox->clear();
|
||||
mStyleTypeComboBox->addItem( tr( "As QGIS QML Style File" ), QgsVectorLayerProperties::QML );
|
||||
mStyleTypeComboBox->addItem( tr( "As SLD Style File" ), QgsVectorLayerProperties::SLD );
|
||||
|
||||
if ( mLayer->dataProvider()->isSaveAndLoadStyleToDatabaseSupported() )
|
||||
mStyleTypeComboBox->addItem( tr( "In Database (%1)" ).arg( providerName ), QgsVectorLayerProperties::DB );
|
||||
|
||||
if ( mSaveOnlyCurrentStyle )
|
||||
mStyleTypeComboBox->addItem( tr( "As default in local user database" ), QgsLayerPropertiesDialog::UserDatabase );
|
||||
mStyleTypeComboBox->addItem( tr( "As Default In Local Database" ), QgsVectorLayerProperties::Local );
|
||||
}
|
||||
|
||||
void QgsMapLayerSaveStyleDialog::accept()
|
||||
void QgsVectorLayerSaveStyleDialog::accept()
|
||||
{
|
||||
QgsSettings().setFlagValue( QStringLiteral( "style/lastStyleCategories" ), styleCategories() );
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void QgsMapLayerSaveStyleDialog::updateSaveButtonState()
|
||||
void QgsVectorLayerSaveStyleDialog::updateSaveButtonState()
|
||||
{
|
||||
const QgsLayerPropertiesDialog::StyleType type = currentStyleType();
|
||||
const QgsVectorLayerProperties::StyleType type = currentStyleType();
|
||||
bool enabled { false };
|
||||
switch ( type )
|
||||
{
|
||||
case QgsLayerPropertiesDialog::DatasourceDatabase:
|
||||
case QgsVectorLayerProperties::DB:
|
||||
if ( saveOnlyCurrentStyle( ) )
|
||||
{
|
||||
enabled = ! mDbStyleNameEdit->text().isEmpty();
|
||||
@ -117,18 +124,18 @@ void QgsMapLayerSaveStyleDialog::updateSaveButtonState()
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
case QgsLayerPropertiesDialog::QML:
|
||||
case QgsLayerPropertiesDialog::SLD:
|
||||
case QgsVectorLayerProperties::QML:
|
||||
case QgsVectorLayerProperties::SLD:
|
||||
enabled = ! mFileWidget->filePath().isEmpty();
|
||||
break;
|
||||
case QgsLayerPropertiesDialog::UserDatabase:
|
||||
case QgsVectorLayerProperties::Local:
|
||||
enabled = true;
|
||||
break;
|
||||
}
|
||||
buttonBox->button( QDialogButtonBox::Ok )->setEnabled( enabled );
|
||||
}
|
||||
|
||||
QgsMapLayerSaveStyleDialog::SaveToDbSettings QgsMapLayerSaveStyleDialog::saveToDbSettings() const
|
||||
QgsVectorLayerSaveStyleDialog::SaveToDbSettings QgsVectorLayerSaveStyleDialog::saveToDbSettings() const
|
||||
{
|
||||
SaveToDbSettings settings;
|
||||
settings.name = mDbStyleNameEdit->text();
|
||||
@ -138,22 +145,22 @@ QgsMapLayerSaveStyleDialog::SaveToDbSettings QgsMapLayerSaveStyleDialog::saveToD
|
||||
return settings;
|
||||
}
|
||||
|
||||
QString QgsMapLayerSaveStyleDialog::outputFilePath() const
|
||||
QString QgsVectorLayerSaveStyleDialog::outputFilePath() const
|
||||
{
|
||||
return mFileWidget->filePath();
|
||||
}
|
||||
|
||||
QgsMapLayer::StyleCategories QgsMapLayerSaveStyleDialog::styleCategories() const
|
||||
QgsMapLayer::StyleCategories QgsVectorLayerSaveStyleDialog::styleCategories() const
|
||||
{
|
||||
return mModel->categories();
|
||||
}
|
||||
|
||||
QgsLayerPropertiesDialog::StyleType QgsMapLayerSaveStyleDialog::currentStyleType() const
|
||||
QgsVectorLayerProperties::StyleType QgsVectorLayerSaveStyleDialog::currentStyleType() const
|
||||
{
|
||||
return mStyleTypeComboBox->currentData().value<QgsLayerPropertiesDialog::StyleType>();
|
||||
return mStyleTypeComboBox->currentData().value<QgsVectorLayerProperties::StyleType>();
|
||||
}
|
||||
|
||||
void QgsMapLayerSaveStyleDialog::readUiFileContent( const QString &filePath )
|
||||
void QgsVectorLayerSaveStyleDialog::readUiFileContent( const QString &filePath )
|
||||
{
|
||||
QgsSettings myQSettings; // where we keep last used filter in persistent state
|
||||
mUiFileContent = QString();
|
||||
@ -184,7 +191,7 @@ void QgsMapLayerSaveStyleDialog::readUiFileContent( const QString &filePath )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMapLayerSaveStyleDialog::setupMultipleStyles()
|
||||
void QgsVectorLayerSaveStyleDialog::setupMultipleStyles()
|
||||
{
|
||||
// Show/hide part of the UI according to multiple style support
|
||||
if ( ! mSaveOnlyCurrentStyle )
|
||||
@ -222,12 +229,12 @@ void QgsMapLayerSaveStyleDialog::setupMultipleStyles()
|
||||
populateStyleComboBox();
|
||||
}
|
||||
|
||||
bool QgsMapLayerSaveStyleDialog::saveOnlyCurrentStyle() const
|
||||
bool QgsVectorLayerSaveStyleDialog::saveOnlyCurrentStyle() const
|
||||
{
|
||||
return mSaveOnlyCurrentStyle;
|
||||
}
|
||||
|
||||
void QgsMapLayerSaveStyleDialog::setSaveOnlyCurrentStyle( bool saveOnlyCurrentStyle )
|
||||
void QgsVectorLayerSaveStyleDialog::setSaveOnlyCurrentStyle( bool saveOnlyCurrentStyle )
|
||||
{
|
||||
if ( mSaveOnlyCurrentStyle != saveOnlyCurrentStyle )
|
||||
{
|
||||
@ -236,23 +243,23 @@ void QgsMapLayerSaveStyleDialog::setSaveOnlyCurrentStyle( bool saveOnlyCurrentSt
|
||||
}
|
||||
}
|
||||
|
||||
const QListWidget *QgsMapLayerSaveStyleDialog::stylesWidget()
|
||||
const QListWidget *QgsVectorLayerSaveStyleDialog::stylesWidget()
|
||||
{
|
||||
return mStylesWidget;
|
||||
}
|
||||
|
||||
Qgis::SldExportOptions QgsMapLayerSaveStyleDialog::sldExportOptions() const
|
||||
Qgis::SldExportOptions QgsVectorLayerSaveStyleDialog::sldExportOptions() const
|
||||
{
|
||||
Qgis::SldExportOptions options;
|
||||
|
||||
if ( mStyleTypeComboBox->currentData( ) == QgsLayerPropertiesDialog::SLD )
|
||||
if ( mStyleTypeComboBox->currentData( ) == QgsVectorLayerProperties::SLD )
|
||||
{
|
||||
options.setFlag( Qgis::SldExportOption::Png );
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
void QgsMapLayerSaveStyleDialog::showHelp()
|
||||
void QgsVectorLayerSaveStyleDialog::showHelp()
|
||||
{
|
||||
QgsHelp::openHelp( QStringLiteral( "introduction/general_tools.html#save-and-share-layer-properties" ) );
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
qgsmaplayersavestyledialog.h
|
||||
qgsvectorlayersavestyledialog.h
|
||||
--------------------------------------
|
||||
Date : September 2018
|
||||
Copyright : (C) 2018 by Denis Rouzaud
|
||||
@ -13,31 +13,29 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMAPLAYERSAVESTYLEDIALOG_H
|
||||
#define QGSMAPLAYERSAVESTYLEDIALOG_H
|
||||
#ifndef QGSVECTORLAYERSAVESTYLEDIALOG_H
|
||||
#define QGSVECTORLAYERSAVESTYLEDIALOG_H
|
||||
|
||||
// We don't want to expose this in the public API
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include <QDialog>
|
||||
#include "ui_qgsmaplayersavestyledialog.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgslayerpropertiesdialog.h"
|
||||
#include "ui_qgsvectorlayersavestyledialog.h"
|
||||
#include "qgsvectorlayerproperties.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QgsVectorLayer;
|
||||
class QgsMapLayerStyleCategoriesModel;
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* \class QgsMapLayerSaveStyleDialog
|
||||
* \class QgsVectorLayerSaveStyleDialog
|
||||
*
|
||||
* \brief The QgsMapLayerSaveStyleDialog class provides the UI to save the current style
|
||||
* \brief The QgsVectorLayerSaveStyleDialog class provides the UI to save the current style
|
||||
* or multiple styles into different storage containers (QML, SLD and DB).
|
||||
* The user can select what categories must be saved.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class GUI_EXPORT QgsMapLayerSaveStyleDialog : public QDialog, private Ui::QgsMapLayerSaveStyleDialog
|
||||
class GUI_EXPORT QgsVectorLayerSaveStyleDialog : public QDialog, private Ui::QgsVectorLayerSaveStyleDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -52,48 +50,17 @@ class GUI_EXPORT QgsMapLayerSaveStyleDialog : public QDialog, private Ui::QgsMap
|
||||
bool isDefault;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
explicit QgsMapLayerSaveStyleDialog( QgsMapLayer *layer, QWidget *parent = nullptr );
|
||||
explicit QgsVectorLayerSaveStyleDialog( QgsVectorLayer *layer, QWidget *parent = nullptr );
|
||||
|
||||
/**
|
||||
* Returns the database settings for saving the style in the DB.
|
||||
*/
|
||||
SaveToDbSettings saveToDbSettings() const;
|
||||
|
||||
/**
|
||||
* Returns the selected file output path.
|
||||
*/
|
||||
QString outputFilePath() const;
|
||||
|
||||
/**
|
||||
* Returns the available style categories.
|
||||
*/
|
||||
QgsMapLayer::StyleCategories styleCategories() const;
|
||||
|
||||
/**
|
||||
* Returns the selected style storage type.
|
||||
*/
|
||||
QgsLayerPropertiesDialog::StyleType currentStyleType() const;
|
||||
QgsVectorLayerProperties::StyleType currentStyleType() const;
|
||||
|
||||
/**
|
||||
* Returns whether the user only allowed to save the current style.
|
||||
*
|
||||
* \see setSaveOnlyCurrentStyle()
|
||||
*/
|
||||
bool saveOnlyCurrentStyle() const;
|
||||
|
||||
/**
|
||||
* Sets whether the user only allowed to save the current style.
|
||||
*
|
||||
* \see saveOnlyCurrentStyle()
|
||||
*/
|
||||
void setSaveOnlyCurrentStyle( bool saveCurrentStyle );
|
||||
|
||||
/**
|
||||
* Returns the styles list widget.
|
||||
*/
|
||||
const QListWidget *stylesWidget( );
|
||||
|
||||
/**
|
||||
@ -113,10 +80,10 @@ class GUI_EXPORT QgsMapLayerSaveStyleDialog : public QDialog, private Ui::QgsMap
|
||||
private:
|
||||
void setupMultipleStyles();
|
||||
void populateStyleComboBox();
|
||||
QgsMapLayer *mLayer = nullptr;
|
||||
QgsVectorLayer *mLayer = nullptr;
|
||||
QgsMapLayerStyleCategoriesModel *mModel;
|
||||
QString mUiFileContent;
|
||||
bool mSaveOnlyCurrentStyle = true;
|
||||
};
|
||||
|
||||
#endif // QGSMAPLAYERSAVESTYLEDIALOG_H
|
||||
#endif // QGSVECTORLAYERSAVESTYLE_H
|
@ -1129,17 +1129,6 @@ bool QgsMssqlProvider::isValid() const
|
||||
return mValid;
|
||||
}
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities QgsMssqlProvider::styleStorageCapabilities() const
|
||||
{
|
||||
Qgis::ProviderStyleStorageCapabilities storageCapabilities;
|
||||
if ( isValid() )
|
||||
{
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::SaveToDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::LoadFromDatabase;
|
||||
}
|
||||
return storageCapabilities;
|
||||
}
|
||||
|
||||
bool QgsMssqlProvider::addFeatures( QgsFeatureList &flist, Flags flags )
|
||||
{
|
||||
for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
|
||||
|
@ -115,7 +115,7 @@ class QgsMssqlProvider final: public QgsVectorDataProvider
|
||||
|
||||
bool isValid() const override;
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const override;
|
||||
bool isSaveAndLoadStyleToDatabaseSupported() const override { return true; }
|
||||
|
||||
bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override;
|
||||
|
||||
|
@ -337,14 +337,6 @@ bool QgsOracleProvider::execLoggedStatic( QSqlQuery &qry, const QString &sql, co
|
||||
return res;
|
||||
}
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities QgsOracleProvider::styleStorageCapabilities() const
|
||||
{
|
||||
Qgis::ProviderStyleStorageCapabilities storageCapabilities;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::SaveToDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::LoadFromDatabase;
|
||||
return storageCapabilities;
|
||||
}
|
||||
|
||||
void QgsOracleProvider::setTransaction( QgsTransaction *transaction )
|
||||
{
|
||||
// static_cast since layers cannot be added to a transaction of a non-matching provider
|
||||
|
@ -185,7 +185,7 @@ class QgsOracleProvider final: public QgsVectorDataProvider
|
||||
|
||||
static bool execLoggedStatic( QSqlQuery &qry, const QString &sql, const QVariantList &args, const QString &uri, const QString &originatorClass = QString(), const QString &queryOrigin = QString() );
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const override;
|
||||
bool isSaveAndLoadStyleToDatabaseSupported() const override { return true; }
|
||||
void setTransaction( QgsTransaction *transaction ) override;
|
||||
QgsTransaction *transaction() const override;
|
||||
|
||||
|
@ -2269,18 +2269,6 @@ bool QgsPostgresProvider::isValid() const
|
||||
return mValid;
|
||||
}
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities QgsPostgresProvider::styleStorageCapabilities() const
|
||||
{
|
||||
Qgis::ProviderStyleStorageCapabilities storageCapabilities;
|
||||
if ( isValid() )
|
||||
{
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::SaveToDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::LoadFromDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::DeleteFromDatabase;
|
||||
}
|
||||
return storageCapabilities;
|
||||
}
|
||||
|
||||
QString QgsPostgresProvider::defaultValueClause( int fieldId ) const
|
||||
{
|
||||
QString defVal = mDefaultValues.value( fieldId, QString() );
|
||||
|
@ -154,7 +154,8 @@ class QgsPostgresProvider final: public QgsVectorDataProvider
|
||||
QgsFeedback *feedback = nullptr ) const override;
|
||||
void enumValues( int index, QStringList &enumList ) const override;
|
||||
bool isValid() const override;
|
||||
Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const override;
|
||||
bool isSaveAndLoadStyleToDatabaseSupported() const override { return true; }
|
||||
bool isDeleteStyleFromDatabaseSupported() const override { return true; }
|
||||
QgsAttributeList attributeIndexes() const override;
|
||||
QgsAttributeList pkAttributeIndexes() const override { return mPrimaryKeyAttrs; }
|
||||
QString defaultValueClause( int fieldId ) const override;
|
||||
|
@ -3781,15 +3781,9 @@ bool QgsSpatiaLiteProvider::isValid() const
|
||||
return mValid;
|
||||
}
|
||||
|
||||
Qgis::ProviderStyleStorageCapabilities QgsSpatiaLiteProvider::styleStorageCapabilities() const
|
||||
bool QgsSpatiaLiteProvider::isSaveAndLoadStyleToDatabaseSupported() const
|
||||
{
|
||||
Qgis::ProviderStyleStorageCapabilities storageCapabilities;
|
||||
if ( isValid() )
|
||||
{
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::SaveToDatabase;
|
||||
storageCapabilities |= Qgis::ProviderStyleStorageCapability::LoadFromDatabase;
|
||||
}
|
||||
return storageCapabilities;
|
||||
return mValid;
|
||||
}
|
||||
|
||||
QString QgsSpatiaLiteProvider::name() const
|
||||
|
@ -114,7 +114,7 @@ class QgsSpatiaLiteProvider final: public QgsVectorDataProvider
|
||||
QgsFeedback *feedback = nullptr ) const override;
|
||||
|
||||
bool isValid() const override;
|
||||
Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const override;
|
||||
bool isSaveAndLoadStyleToDatabaseSupported() const override;
|
||||
bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override;
|
||||
bool deleteFeatures( const QgsFeatureIds &id ) override;
|
||||
bool truncate() override;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsMapLayerSaveStyleDialog</class>
|
||||
<widget class="QDialog" name="QgsMapLayerSaveStyleDialog">
|
||||
<class>QgsVectorLayerSaveStyleDialog</class>
|
||||
<widget class="QDialog" name="QgsVectorLayerSaveStyleDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
@ -200,7 +200,7 @@
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>QgsMapLayerSaveStyleDialog</receiver>
|
||||
<receiver>QgsVectorLayerSaveStyleDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
@ -216,7 +216,7 @@
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>QgsMapLayerSaveStyleDialog</receiver>
|
||||
<receiver>QgsVectorLayerSaveStyleDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
@ -15,7 +15,6 @@ import qgis # NOQA
|
||||
from qgis.PyQt.QtCore import QDate, QDateTime, QDir, QTime, QVariant
|
||||
from qgis.core import (
|
||||
NULL,
|
||||
Qgis,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsDataProvider,
|
||||
QgsDataSourceUri,
|
||||
@ -404,8 +403,8 @@ class TestPyQgsMssqlProvider(QgisTestCase, ProviderTestCase):
|
||||
|
||||
vl = self.getSource()
|
||||
self.assertTrue(vl.isValid())
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
|
||||
self.assertTrue(
|
||||
vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported())
|
||||
|
||||
# table layer_styles does not exist
|
||||
|
||||
|
@ -667,8 +667,7 @@ class TestPyQgsOGRProviderGpkg(QgisTestCase):
|
||||
# First test with invalid URI
|
||||
vl = QgsVectorLayer('/idont/exist.gpkg', 'test', 'ogr')
|
||||
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, 0)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, 0)
|
||||
self.assertFalse(vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported())
|
||||
|
||||
res, err = QgsProviderRegistry.instance().styleExists('ogr', '/idont/exist.gpkg', '')
|
||||
self.assertFalse(res)
|
||||
@ -717,8 +716,7 @@ class TestPyQgsOGRProviderGpkg(QgisTestCase):
|
||||
vl2 = QgsVectorLayer(f'{tmpfile}|layername=test2', 'test2', 'ogr')
|
||||
self.assertTrue(vl2.isValid())
|
||||
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
|
||||
self.assertTrue(vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported())
|
||||
|
||||
# style tables don't exist yet
|
||||
res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), '')
|
||||
@ -1157,8 +1155,7 @@ class TestPyQgsOGRProviderGpkg(QgisTestCase):
|
||||
if count > 0:
|
||||
# We should have just 1 but for obscure reasons
|
||||
# uniqueFields() (sometimes?) leaves one behind
|
||||
# Even more obscure reasons a third FD remains open
|
||||
self.assertIn(count, (1, 2, 3))
|
||||
self.assertIn(count, (1, 2))
|
||||
|
||||
for i in range(70):
|
||||
got = [feat for feat in vl.getFeatures()]
|
||||
@ -1169,7 +1166,7 @@ class TestPyQgsOGRProviderGpkg(QgisTestCase):
|
||||
# one shared by the feature iterators
|
||||
count = count_opened_filedescriptors(tmpfile)
|
||||
if count > 0:
|
||||
self.assertIn(count, (2, 3))
|
||||
self.assertEqual(count, 2)
|
||||
|
||||
# Re-open an already opened layers. We should get a new handle
|
||||
layername = 'layer%d' % 0
|
||||
|
@ -1941,9 +1941,9 @@ class TestPyQgsPostgresProvider(QgisTestCase, ProviderTestCase):
|
||||
|
||||
vl = self.getEditableLayer()
|
||||
self.assertTrue(vl.isValid())
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.DeleteFromDatabase, Qgis.ProviderStyleStorageCapability.DeleteFromDatabase)
|
||||
self.assertTrue(
|
||||
vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported())
|
||||
self.assertTrue(vl.dataProvider().isDeleteStyleFromDatabaseSupported())
|
||||
|
||||
# table layer_styles does not exist
|
||||
|
||||
@ -2125,9 +2125,9 @@ class TestPyQgsPostgresProvider(QgisTestCase, ProviderTestCase):
|
||||
|
||||
vl = self.getEditableLayer()
|
||||
self.assertTrue(vl.isValid())
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.DeleteFromDatabase, Qgis.ProviderStyleStorageCapability.DeleteFromDatabase)
|
||||
self.assertTrue(
|
||||
vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported())
|
||||
self.assertTrue(vl.dataProvider().isDeleteStyleFromDatabaseSupported())
|
||||
|
||||
mFilePath = QDir.toNativeSeparators(
|
||||
f"{unitTestDataPath()}/symbol_layer/fontSymbol.qml")
|
||||
|
@ -1096,8 +1096,7 @@ class TestQgsSpatialiteProvider(QgisTestCase, ProviderTestCase):
|
||||
# First test with invalid URI
|
||||
vl = QgsVectorLayer('/idont/exist.sqlite', 'test', 'spatialite')
|
||||
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, 0)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, 0)
|
||||
self.assertFalse(vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported())
|
||||
|
||||
res, err = QgsProviderRegistry.instance().styleExists('spatialite', '/idont/exist.sqlite', '')
|
||||
self.assertFalse(res)
|
||||
@ -1151,8 +1150,7 @@ class TestQgsSpatialiteProvider(QgisTestCase, ProviderTestCase):
|
||||
vl = QgsVectorLayer(testPath, 'test', 'spatialite')
|
||||
self.assertTrue(vl.isValid())
|
||||
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
|
||||
self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
|
||||
self.assertTrue(vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported())
|
||||
|
||||
# style tables don't exist yet
|
||||
res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), '')
|
||||
|
Loading…
x
Reference in New Issue
Block a user