Skip to content

Commit

Permalink
Added new QgsSettingsEntryFlag and tests for enum and flag
Browse files Browse the repository at this point in the history
  • Loading branch information
domi4484 committed Apr 1, 2021
1 parent d16702d commit fe0dcee
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 20 deletions.
3 changes: 2 additions & 1 deletion python/core/auto_generated/settings/qgssettingsentry.sip.in
Expand Up @@ -49,7 +49,8 @@ to validate set values and provide more accurate settings description for the gu
Bool,
Integer,
Double,
Enum
Enum,
Flag
};

QgsSettingsEntryBase( QString key,
Expand Down
14 changes: 0 additions & 14 deletions src/core/settings/qgssettingsentry.cpp
Expand Up @@ -441,19 +441,5 @@ int QgsSettingsEntryDouble::displayHintDecimals() const
return mDisplayHintDecimals;
}

bool QgsSettingsEntryEnum::setValue( const QVariant &value, const QString &dynamicKeyPart ) const
{
if ( mMetaEnum.isValid() == false )
{
QgsDebugMsg( QStringLiteral( "Invalid metaenum. Enum probably misses Q_ENUM or Q_FLAG declaration." ) );
return false;
}

return QgsSettingsEntryBase::setValue( mMetaEnum.valueToKey( value.toInt() ), dynamicKeyPart );
}

QgsSettingsEntryBase::SettingsType QgsSettingsEntryEnum::settingsType() const
{
return QgsSettingsEntryBase::Enum;
}

172 changes: 167 additions & 5 deletions src/core/settings/qgssettingsentry.h
Expand Up @@ -65,7 +65,8 @@ class CORE_EXPORT QgsSettingsEntryBase
Bool,
Integer,
Double,
Enum
Enum,
Flag
};

/**
Expand Down Expand Up @@ -576,6 +577,7 @@ class CORE_EXPORT QgsSettingsEntryDouble : public QgsSettingsEntryBase
* An enum settings entry.
* \since QGIS 3.20
*/
template <typename T>
class CORE_EXPORT QgsSettingsEntryEnum : public QgsSettingsEntryBase
{
public:
Expand All @@ -589,14 +591,13 @@ class CORE_EXPORT QgsSettingsEntryEnum : public QgsSettingsEntryBase
* The \a default value argument specifies the default value for the settings entry.
* The \a description argument specifies a description for the settings entry.
*/
template <class T>
QgsSettingsEntryEnum( const QString &key,
QgsSettings::Section section,
const T &defaultValue,
const QString &description = QString() )
: QgsSettingsEntryBase( key,
section,
defaultValue,
QMetaEnum::fromType<T>().valueToKey( defaultValue ),
description )
{
mMetaEnum = QMetaEnum::fromType<T>();
Expand All @@ -607,11 +608,66 @@ class CORE_EXPORT QgsSettingsEntryEnum : public QgsSettingsEntryBase
}
}

/**
* Get settings value.
*
* The \a dynamicKeyPart argument specifies the dynamic part of the settings key.
*/
T value( const QString &dynamicKeyPart = QString() ) const
{
return QgsSettings().enumValue( key( dynamicKeyPart ),
defaultValueAsVariant().value<T>(),
section() );
}

/**
* Get settings default value.
*/
T defaultValue() const
{
if ( !mMetaEnum.isValid() )
{
QgsDebugMsg( QStringLiteral( "Invalid metaenum. Enum probably misses Q_ENUM or Q_FLAG declaration." ) );
return T();
}

QByteArray byteArray = defaultValueAsVariant().toByteArray();
bool ok = false;
T defaultValue = static_cast<T>( mMetaEnum.keyToValue( byteArray, &ok ) );
if ( !ok )
{
QgsDebugMsg( QStringLiteral( "Invalid enum key '%1'." ).arg( defaultValueAsVariant().toString() ) );
return T();
}

return defaultValue;
}

//! \copydoc QgsSettingsEntry::setValue
bool setValue( const QVariant &value, const QString &dynamicKeyPart = QString() ) const override;
bool setValue( const QVariant &value, const QString &dynamicKeyPart = QString() ) const override
{
if ( !mMetaEnum.isValid() )
{
QgsDebugMsg( QStringLiteral( "Invalid metaenum. Enum probably misses Q_ENUM or Q_FLAG declaration." ) );
return false;
}

const char *enumKey = mMetaEnum.valueToKey( value.toInt() );
if ( enumKey == nullptr )
{
QgsDebugMsg( QStringLiteral( "Invalid enum value '%1'." ).arg( value.toInt() ) );
return false;
}

QgsSettingsEntryBase::setValue( enumKey, dynamicKeyPart );
return true;
}

//! \copydoc QgsSettingsEntry::settingsType
virtual SettingsType settingsType() const override;
virtual SettingsType settingsType() const override
{
return QgsSettingsEntryBase::Enum;
}

private:

Expand All @@ -621,5 +677,111 @@ class CORE_EXPORT QgsSettingsEntryEnum : public QgsSettingsEntryBase
#endif


#ifndef SIP_RUN

/**
* \class QgsSettingsEntryFlag
* \ingroup core
* An flag settings entry.
* \since QGIS 3.20
*/
template <typename T>
class CORE_EXPORT QgsSettingsEntryFlag : public QgsSettingsEntryBase
{
public:

/**
* Constructor for QgsSettingsEntryFlag.
*
* The \a key argument specifies the final part of the settings key.
* The \a parentGroup argument specifies a parent group which is used to rebuild
* the entiere settings key and to determine the settings section.
* The \a default value argument specifies the default value for the settings entry.
* The \a description argument specifies a description for the settings entry.
*/
QgsSettingsEntryFlag( const QString &key,
QgsSettings::Section section,
const T &defaultValue,
const QString &description = QString() )
: QgsSettingsEntryBase( key,
section,
QMetaEnum::fromType<T>().valueToKeys( defaultValue ),
description )
{
mMetaEnum = QMetaEnum::fromType<T>();
Q_ASSERT( mMetaEnum.isValid() );
if ( !mMetaEnum.isValid() )
{
QgsDebugMsg( QStringLiteral( "Invalid metaenum. Flag probably misses Q_ENUM or Q_FLAG declaration." ) );
}
}

/**
* Get settings value.
*
* The \a dynamicKeyPart argument specifies the dynamic part of the settings key.
*/
T value( const QString &dynamicKeyPart = QString() ) const
{
return QgsSettings().flagValue( key( dynamicKeyPart ),
defaultValueAsVariant().value<T>(),
section() );
}

/**
* Get settings default value.
*/
T defaultValue() const
{
if ( !mMetaEnum.isValid() )
{
QgsDebugMsg( QStringLiteral( "Invalid metaenum. Enum probably misses Q_ENUM or Q_FLAG declaration." ) );
return T();
}

QByteArray byteArray = defaultValueAsVariant().toByteArray();
bool ok = false;
T defaultValue = static_cast<T>( mMetaEnum.keysToValue( byteArray, &ok ) );
if ( !ok )
{
QgsDebugMsg( QStringLiteral( "Invalid flag keys '%1'." ).arg( defaultValueAsVariant().toString() ) );
return T();
}

return defaultValue;
}

//! \copydoc QgsSettingsEntry::setValue
bool setValue( const T &value, const QString &dynamicKeyPart = QString() ) const
{
if ( !mMetaEnum.isValid() )
{
QgsDebugMsg( QStringLiteral( "Invalid metaenum. Flag probably misses Q_ENUM or Q_FLAG declaration." ) );
return false;
}

QByteArray flagKeys = mMetaEnum.valueToKeys( value );
if ( flagKeys.isEmpty() )
{
QgsDebugMsg( QStringLiteral( "Invalid flag value '%1'." ).arg( value ) );
return false;
}

QgsSettingsEntryBase::setValue( flagKeys, dynamicKeyPart );
return true;
}

//! \copydoc QgsSettingsEntry::settingsType
virtual SettingsType settingsType() const override
{
return QgsSettingsEntryBase::Flag;
}

private:

QMetaEnum mMetaEnum;

};
#endif

#endif // QGSSETTINGSENTRY_H
1 change: 1 addition & 0 deletions tests/src/core/CMakeLists.txt
Expand Up @@ -188,6 +188,7 @@ set(TESTS
testqgsrulebasedrenderer.cpp
testqgsruntimeprofiler.cpp
testqgssettings.cpp
testqgssettingsentry.cpp
testqgsshapeburst.cpp
testqgssimplemarker.cpp
testqgssnappingutils.cpp
Expand Down
126 changes: 126 additions & 0 deletions tests/src/core/testqgssettingsentry.cpp
@@ -0,0 +1,126 @@
/***************************************************************************
testqgssettingsentry.cpp
--------------------------------------
Date : 01.04.2021
Copyright : (C) 2021 by Damiano Lombardi
Email : damiano@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <QObject>


#include "qgssettings.h"
#include "qgssettingsentry.h"
#include "qgsunittypes.h"
#include "qgsmaplayerproxymodel.h"
#include "qgstest.h"


/**
* \ingroup UnitTests
* This is a unit test for the operations on curve geometries
*/
class TestQgsSettingsEntry : public QObject
{
Q_OBJECT

private slots:
void enumValue();
void flagValue();
};


void TestQgsSettingsEntry::enumValue()
{
QString settingsKey( "qgis/testing/my_enum_value_for_units" );

// Make sure the setting is not existing
QgsSettings().remove( settingsKey, QgsSettings::NoSection );

QgsSettingsEntryEnum settingsEntryEnum( settingsKey, QgsSettings::NoSection, QgsUnitTypes::LayoutMeters, "Layout unit" );

// Check default value
QCOMPARE( settingsEntryEnum.defaultValue(), QgsUnitTypes::LayoutMeters );

// Check set value
{
bool success = settingsEntryEnum.setValue( QgsUnitTypes::LayoutFeet );
QCOMPARE( success, true );
QgsUnitTypes::LayoutUnit qgsSettingsValue = QgsSettings().enumValue( settingsKey, QgsUnitTypes::LayoutMeters, QgsSettings::NoSection );
QCOMPARE( qgsSettingsValue, QgsUnitTypes::LayoutFeet );
}

// Check get value
QgsSettings().setEnumValue( settingsKey, QgsUnitTypes::LayoutPicas, QgsSettings::NoSection );
QCOMPARE( settingsEntryEnum.value(), QgsUnitTypes::LayoutPicas );

// Check settings type
QCOMPARE( settingsEntryEnum.settingsType(), QgsSettingsEntryBase::Enum );

// assign to inexisting value
{
bool success = settingsEntryEnum.setValue( -1 );
QCOMPARE( success, false );

// Current value should not have changed
QgsUnitTypes::LayoutUnit qgsSettingsValue = QgsSettings().enumValue( settingsKey, QgsUnitTypes::LayoutMeters, QgsSettings::NoSection );
QCOMPARE( qgsSettingsValue, QgsUnitTypes::LayoutPicas );
}

// check that value is stored as string
QCOMPARE( settingsEntryEnum.valueAsVariant().toString(), QMetaEnum::fromType<QgsUnitTypes::LayoutUnit>().key( QgsUnitTypes::LayoutPicas ) );

// auto conversion of old settings (int to str)
QSettings().setValue( settingsKey, static_cast<int>( QgsUnitTypes::LayoutCentimeters ) );
QCOMPARE( settingsEntryEnum.valueAsVariant().toInt(), QgsUnitTypes::LayoutCentimeters );
QCOMPARE( settingsEntryEnum.value(), QgsUnitTypes::LayoutCentimeters );
}

void TestQgsSettingsEntry::flagValue()
{
QString settingsKey( "qgis/testing/my_flag_value_for_units" );
QgsMapLayerProxyModel::Filters pointAndLine = QgsMapLayerProxyModel::Filters( QgsMapLayerProxyModel::PointLayer | QgsMapLayerProxyModel::LineLayer );
QgsMapLayerProxyModel::Filters pointAndPolygon = QgsMapLayerProxyModel::Filters( QgsMapLayerProxyModel::PointLayer | QgsMapLayerProxyModel::PolygonLayer );
QgsMapLayerProxyModel::Filters hasGeometry = QgsMapLayerProxyModel::Filters( QgsMapLayerProxyModel::HasGeometry );

// Make sure the setting is not existing
QgsSettings().remove( settingsKey, QgsSettings::NoSection );

QgsSettingsEntryFlag settingsEntryFlag( settingsKey, QgsSettings::NoSection, pointAndLine, "Filters" );

// Check default value
QCOMPARE( settingsEntryFlag.defaultValue(), pointAndLine );

// Check set value
{
bool success = settingsEntryFlag.setValue( hasGeometry );
QCOMPARE( success, true );
QgsMapLayerProxyModel::Filters qgsSettingsValue = QgsSettings().flagValue( settingsKey, pointAndLine, QgsSettings::NoSection );
QCOMPARE( qgsSettingsValue, hasGeometry );
}

// Check get value
QgsSettings().setFlagValue( settingsKey, pointAndLine, QgsSettings::NoSection );
QCOMPARE( settingsEntryFlag.value(), pointAndLine );

// Check settings type
QCOMPARE( settingsEntryFlag.settingsType(), QgsSettingsEntryBase::Flag );

// check that value is stored as string
QCOMPARE( settingsEntryFlag.valueAsVariant().toByteArray(), QMetaEnum::fromType<QgsMapLayerProxyModel::Filters>().valueToKeys( pointAndLine ) );

// auto conversion of old settings (int to str)
QSettings().setValue( settingsKey, static_cast<int>( pointAndPolygon ) );
QCOMPARE( settingsEntryFlag.valueAsVariant().toInt(), pointAndPolygon );
QCOMPARE( settingsEntryFlag.value(), pointAndPolygon );
}


QGSTEST_MAIN( TestQgsSettingsEntry )
#include "testqgssettingsentry.moc"

0 comments on commit fe0dcee

Please sign in to comment.