mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-07 00:15:48 -04:00
[pyqgis] add QgsSettings.enumValue and flagValue to the bindings (#7024)
* [pyqgis] add QgsSettings.enumValue and flagValue to the bindings these are done in pure Python since no implementation is possible in SIP there is a dirty hack for flags since QgsMapLayerProxyModel.Filters.__qualname__ returns 'Filters' and not 'QgsMapLayerProxyModel.Filters' * fix typo
This commit is contained in:
parent
deccf205cf
commit
b4ec9a3190
@ -35,6 +35,7 @@ from .additions.qgsdefaultvalue import _isValid
|
||||
from .additions.qgsfeature import mapping_feature
|
||||
from .additions.qgsfunction import register_function, qgsfunction
|
||||
from .additions.qgsgeometry import _geometryNonZero, mapping_geometry
|
||||
from .additions.qgssettings import _qgssettings_enum_value, _qgssettings_flag_value
|
||||
from .additions.qgstaskwrapper import QgsTaskWrapper
|
||||
from .additions.readwritecontextentercategory import ReadWriteContextEnterCategory
|
||||
|
||||
@ -48,27 +49,36 @@ QgsProcessingFeatureSourceDefinition.__repr__ = processing_source_repr
|
||||
QgsProcessingOutputLayerDefinition.__repr__ = processing_output_layer_repr
|
||||
QgsProject.blockDirtying = ProjectDirtyBlocker
|
||||
QgsReadWriteContext.enterCategory = ReadWriteContextEnterCategory
|
||||
QgsSettings.enumValue = _qgssettings_enum_value
|
||||
QgsSettings.flagValue = _qgssettings_flag_value
|
||||
QgsTask.fromFunction = fromFunction
|
||||
|
||||
# -----------------
|
||||
# DO NOT EDIT BELOW
|
||||
# These are automatically added by calling sipify.pl script
|
||||
QgsTolerance.UnitType.baseClass = QgsTolerance
|
||||
|
||||
QgsAuthManager.MessageLevel.baseClass = QgsAuthManager
|
||||
QgsDataItem.Type.baseClass = QgsDataItem
|
||||
QgsDataItem.State.baseClass = QgsDataItem
|
||||
QgsLayerItem.LayerType.baseClass = QgsLayerItem
|
||||
QgsDataProvider.DataCapability.baseClass = QgsDataProvider
|
||||
QgsDataSourceUri.SslMode.baseClass = QgsDataSourceUri
|
||||
QgsFieldProxyModel.Filters.baseClass = QgsFieldProxyModel
|
||||
Filters = QgsFieldProxyModel # dirty hack since SIP seems to introduce the flags in module
|
||||
QgsMapLayerProxyModel.Filters.baseClass = QgsMapLayerProxyModel
|
||||
Filters = QgsMapLayerProxyModel # dirty hack since SIP seems to introduce the flags in module
|
||||
QgsNetworkContentFetcherRegistry.FetchingMode.baseClass = QgsNetworkContentFetcherRegistry
|
||||
QgsSnappingConfig.SnappingMode.baseClass = QgsSnappingConfig
|
||||
QgsSnappingConfig.SnappingType.baseClass = QgsSnappingConfig
|
||||
QgsTolerance.UnitType.baseClass = QgsTolerance
|
||||
QgsUnitTypes.DistanceUnit.baseClass = QgsUnitTypes
|
||||
QgsUnitTypes.AreaUnit.baseClass = QgsUnitTypes
|
||||
QgsUnitTypes.AngleUnit.baseClass = QgsUnitTypes
|
||||
QgsUnitTypes.RenderUnit.baseClass = QgsUnitTypes
|
||||
QgsUnitTypes.LayoutUnit.baseClass = QgsUnitTypes
|
||||
QgsVectorSimplifyMethod.SimplifyHint.baseClass = QgsVectorSimplifyMethod
|
||||
QgsVectorSimplifyMethod.SimplifyHints.baseClass = QgsVectorSimplifyMethod
|
||||
SimplifyHints = QgsVectorSimplifyMethod # dirty hack since SIP seems to introduce the flags in module
|
||||
QgsVectorSimplifyMethod.SimplifyAlgorithm.baseClass = QgsVectorSimplifyMethod
|
||||
QgsRasterProjector.Precision.baseClass = QgsRasterProjector
|
||||
QgsAbstractGeometry.SegmentationToleranceType.baseClass = QgsAbstractGeometry
|
||||
|
@ -18,11 +18,27 @@
|
||||
"""
|
||||
|
||||
|
||||
def metaEnumFromValue(enumValue, raiseException=True, baseClass=None):
|
||||
return metaEnumFromType(enumValue.__class__, raiseException, baseClass)
|
||||
def metaEnumFromValue(enumValue, baseClass=None, raiseException=True):
|
||||
"""
|
||||
Returns the QMetaEnum for an enum value.
|
||||
The enum must have declared using the Q_ENUM macro
|
||||
:param enumValue: the enum value
|
||||
:param baseClass: the enum base class. If not given, it will try to get it by using `enumValue.__class__.baseClass`
|
||||
:param raiseException: if False, no exception will be raised and None will be return in case of failure
|
||||
:return: the QMetaEnum if it succeeds, None otherwise
|
||||
"""
|
||||
return metaEnumFromType(enumValue.__class__, baseClass, raiseException)
|
||||
|
||||
|
||||
def metaEnumFromType(enumClass, raiseException=True, baseClass=None):
|
||||
def metaEnumFromType(enumClass, baseClass=None, raiseException=True):
|
||||
"""
|
||||
Returns the QMetaEnum for an enum type.
|
||||
The enum must have declared using the Q_ENUM macro
|
||||
:param enumClass: the enum class
|
||||
:param baseClass: the enum base class. If not given, it will try to get it by using `enumValue.__class__.baseClass`
|
||||
:param raiseException: if False, no exception will be raised and None will be return in case of failure
|
||||
:return: the QMetaEnum if it succeeds, None otherwise
|
||||
"""
|
||||
if enumClass == int:
|
||||
if raiseException:
|
||||
raise TypeError("enumClass is an int, while it should be an enum")
|
||||
@ -32,7 +48,7 @@ def metaEnumFromType(enumClass, raiseException=True, baseClass=None):
|
||||
if baseClass is None:
|
||||
try:
|
||||
baseClass = enumClass.baseClass
|
||||
return metaEnumFromType(enumClass, raiseException, baseClass)
|
||||
return metaEnumFromType(enumClass, baseClass, raiseException)
|
||||
except AttributeError:
|
||||
if raiseException:
|
||||
raise ValueError("Enum type does not implement baseClass method. Provide the base class as argument.")
|
||||
|
101
python/core/additions/qgssettings.py
Normal file
101
python/core/additions/qgssettings.py
Normal file
@ -0,0 +1,101 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
qgssettings.py
|
||||
---------------------
|
||||
Date : May 2018
|
||||
Copyright : (C) 2018 by Denis Rouzaud
|
||||
Email : denis@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. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
from .metaenum import metaEnumFromValue
|
||||
import qgis
|
||||
|
||||
|
||||
def _qgssettings_enum_value(self, key, enumDefaultValue, section=None):
|
||||
"""
|
||||
Return the setting value for a setting based on an enum.
|
||||
This forces the output to be a valid and existing entry of the enum.
|
||||
Hence if the setting value is incorrect, the given default value is returned.
|
||||
This tries first with setting as a string (as the enum) and then as an integer value.
|
||||
|
||||
:param self: the QgsSettings object
|
||||
:param key: the setting key
|
||||
:param enumDefaultValue: the default value as an enum value
|
||||
:param section: optional section
|
||||
:return: the setting value
|
||||
|
||||
.. note:: The enum needs to be declared with Q_ENUM.
|
||||
|
||||
"""
|
||||
if section is None:
|
||||
section = self.NoSection
|
||||
|
||||
meta_enum = metaEnumFromValue(enumDefaultValue)
|
||||
if meta_enum is None or not meta_enum.isValid():
|
||||
# this should not happen
|
||||
raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(enumDefaultValue)))
|
||||
|
||||
str_val = self.value(key, meta_enum.valueToKey(enumDefaultValue))
|
||||
# need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (proaby a PyQt issue)
|
||||
meta_enum_2 = metaEnumFromValue(enumDefaultValue)
|
||||
(enu_val, ok) = meta_enum_2.keyToValue(str_val)
|
||||
|
||||
if not ok:
|
||||
enu_val = enumDefaultValue
|
||||
|
||||
return enu_val
|
||||
|
||||
|
||||
def _qgssettings_flag_value(self, key, flagDefaultValue, section=None):
|
||||
"""
|
||||
Return the setting value for a setting based on a flag.
|
||||
This forces the output to be a valid and existing entry of the enum.
|
||||
Hence if the setting value is incorrect, the given default value is returned.
|
||||
This tries first with setting as a string (as the enum) and then as an integer value.
|
||||
|
||||
:param self: the QgsSettings object
|
||||
:param key: the setting key
|
||||
:param flagDefaultValue: the default value as a flag value
|
||||
:param section: optional section
|
||||
:return: the setting value
|
||||
|
||||
.. note:: The flag needs to be declared with Q_FLAG (not Q_FLAGS).
|
||||
|
||||
"""
|
||||
if section is None:
|
||||
section = self.NoSection
|
||||
|
||||
# There is an issue in SIP, flags.__class__ does not return the proper class
|
||||
# (e.g. Filters instead of QgsMapLayerProxyModel.Filters)
|
||||
# dirty hack to get the parent class
|
||||
__import__(flagDefaultValue.__module__)
|
||||
baseClass = None
|
||||
exec("baseClass={module}.{flag_class}".format(module=flagDefaultValue.__module__.replace('_', ''),
|
||||
flag_class=flagDefaultValue.__class__.__name__))
|
||||
|
||||
meta_enum = metaEnumFromValue(flagDefaultValue, baseClass)
|
||||
if meta_enum is None or not meta_enum.isValid():
|
||||
# this should not happen
|
||||
raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(flagDefaultValue)))
|
||||
|
||||
str_val = self.value(key, meta_enum.valueToKey(flagDefaultValue))
|
||||
# need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (proaby a PyQt issue)
|
||||
meta_enum_2 = metaEnumFromValue(flagDefaultValue)
|
||||
(flag_val, ok) = meta_enum_2.keysToValue(str_val)
|
||||
|
||||
if not ok:
|
||||
flag_val = flagDefaultValue
|
||||
else:
|
||||
flag_val = flagDefaultValue.__class__(flag_val)
|
||||
|
||||
return flag_val
|
@ -30,12 +30,20 @@ from qgis._gui import *
|
||||
# DO NOT EDIT BELOW
|
||||
# These are automatically added by calling sipify.pl script
|
||||
QgsAuthSettingsWidget.WarningType.baseClass = QgsAuthSettingsWidget
|
||||
QgsAdvancedDigitizingDockWidget.CadCapacities.baseClass = QgsAdvancedDigitizingDockWidget
|
||||
CadCapacities = QgsAdvancedDigitizingDockWidget # dirty hack since SIP seems to introduce the flags in module
|
||||
QgsColorButton.Behavior.baseClass = QgsColorButton
|
||||
QgsColorTextWidget.ColorTextFormat.baseClass = QgsColorTextWidget
|
||||
QgsFilterLineEdit.ClearMode.baseClass = QgsFilterLineEdit
|
||||
QgsFloatingWidget.AnchorPoint.baseClass = QgsFloatingWidget
|
||||
QgsFontButton.Mode.baseClass = QgsFontButton
|
||||
QgsMapLayerAction.Targets.baseClass = QgsMapLayerAction
|
||||
Targets = QgsMapLayerAction # dirty hack since SIP seems to introduce the flags in module
|
||||
QgsMapLayerAction.Flags.baseClass = QgsMapLayerAction
|
||||
Flags = QgsMapLayerAction # dirty hack since SIP seems to introduce the flags in module
|
||||
QgsMapToolIdentify.IdentifyMode.baseClass = QgsMapToolIdentify
|
||||
QgsMapToolIdentify.LayerType.baseClass = QgsMapToolIdentify
|
||||
LayerType = QgsMapToolIdentify # dirty hack since SIP seems to introduce the flags in module
|
||||
QgsAttributeTableFilterModel.FilterMode.baseClass = QgsAttributeTableFilterModel
|
||||
QgsAttributeTableFilterModel.ColumnType.baseClass = QgsAttributeTableFilterModel
|
||||
QgsDualView.ViewMode.baseClass = QgsDualView
|
||||
|
@ -612,10 +612,11 @@ while ($LINE_IDX < $LINE_COUNT){
|
||||
}
|
||||
next;
|
||||
}
|
||||
if ($LINE =~ m/Q_ENUM\(\s*(\w+)\s*\)/ ){
|
||||
if ($LINE =~ m/Q_(ENUM|FLAG)\(\s*(\w+)\s*\)/ ){
|
||||
if ($LINE !~ m/SIP_SKIP/){
|
||||
my $enum_helper = "$ACTUAL_CLASS.$1.baseClass = $ACTUAL_CLASS";
|
||||
dbg_info("Q_ENUM $enum_helper");
|
||||
my $is_flag = $1 eq 'FLAG' ? 1 : 0;
|
||||
my $enum_helper = "$ACTUAL_CLASS.$2.baseClass = $ACTUAL_CLASS";
|
||||
dbg_info("Q_ENUM/Q_FLAG $enum_helper");
|
||||
if ($python_output ne ''){
|
||||
my $pl;
|
||||
open(FH, '+<', $python_output) or die $!;
|
||||
@ -626,6 +627,11 @@ while ($LINE_IDX < $LINE_COUNT){
|
||||
}
|
||||
}
|
||||
if ($enum_helper ne ''){
|
||||
if ($is_flag == 1){
|
||||
# SIP seems to introduce the flags in the module rather than in the class itself
|
||||
# as a dirty hack, inject directly in module, hopefully we don't have flags with the same name....
|
||||
$enum_helper .= "\n$2 = $ACTUAL_CLASS # dirty hack since SIP seems to introduce the flags in module";
|
||||
}
|
||||
print FH "$enum_helper\n";
|
||||
}
|
||||
close(FH);
|
||||
|
@ -227,6 +227,7 @@ class CORE_EXPORT QgsSettings : public QObject
|
||||
* Hence if the setting value is incorrect, the given default value is returned.
|
||||
* This tries first with setting as a string (as the enum) and then as an integer value.
|
||||
* \note The enum needs to be declared with Q_ENUM, and flags with Q_FLAG (not Q_FLAGS).
|
||||
* \note for Python bindings, a custom implementation is achieved in Python directly
|
||||
* \see setEnumValue
|
||||
* \see flagValue
|
||||
*/
|
||||
@ -304,6 +305,7 @@ class CORE_EXPORT QgsSettings : public QObject
|
||||
* Hence if the setting value is incorrect, the given default value is returned.
|
||||
* This tries first with setting as a string (using a byte array) and then as an integer value.
|
||||
* \note The flag needs to be declared with Q_FLAG (not Q_FLAGS).
|
||||
* \note for Python bindings, a custom implementation is achieved in Python directly.
|
||||
* \see setFlagValue
|
||||
* \see enumValue
|
||||
*/
|
||||
|
@ -24,16 +24,19 @@ start_app()
|
||||
|
||||
class TestCoreAdditions(unittest.TestCase):
|
||||
|
||||
def testEnum(self):
|
||||
def testMetaEnum(self):
|
||||
me = metaEnumFromValue(QgsTolerance.Pixels)
|
||||
self.assertIsNotNone(me)
|
||||
self.assertEqual(me.valueToKey(QgsTolerance.Pixels), 'Pixels')
|
||||
|
||||
# if using same variable twice (e.g. me = me2), this seg faults
|
||||
me2 = metaEnumFromValue(QgsTolerance.Pixels, True, QgsTolerance)
|
||||
me2 = metaEnumFromValue(QgsTolerance.Pixels, QgsTolerance)
|
||||
self.assertIsNotNone(me)
|
||||
self.assertEqual(me2.valueToKey(QgsTolerance.Pixels), 'Pixels')
|
||||
|
||||
# do not raise error
|
||||
self.assertIsNone(metaEnumFromValue(1, QgsTolerance, False))
|
||||
|
||||
# do not provide an int
|
||||
with self.assertRaises(TypeError):
|
||||
metaEnumFromValue(1)
|
||||
|
@ -12,7 +12,7 @@ the Free Software Foundation; either version 2 of the License, or
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
from qgis.core import (QgsSettings,)
|
||||
from qgis.core import QgsSettings, QgsTolerance, QgsMapLayerProxyModel
|
||||
from qgis.testing import start_app, unittest
|
||||
from qgis.PyQt.QtCore import QSettings
|
||||
|
||||
@ -391,6 +391,23 @@ class TestQgsSettings(unittest.TestCase):
|
||||
self.settings.remove('testQgisSettings/temp', section=QgsSettings.Core)
|
||||
self.assertEqual(self.settings.value('testqQgisSettings/temp', section=QgsSettings.Core), None)
|
||||
|
||||
def test_enumValue(self):
|
||||
self.settings.setValue('enum', 'LayerUnits')
|
||||
self.assertEqual(self.settings.enumValue('enum', QgsTolerance.Pixels), QgsTolerance.LayerUnits)
|
||||
self.settings.setValue('enum', 'dummy_setting')
|
||||
self.assertEqual(self.settings.enumValue('enum', QgsTolerance.Pixels), QgsTolerance.Pixels)
|
||||
self.assertEqual(type(self.settings.enumValue('enum', QgsTolerance.Pixels)), QgsTolerance.UnitType)
|
||||
|
||||
def test_flagValue(self):
|
||||
pointAndLine = QgsMapLayerProxyModel.Filters(QgsMapLayerProxyModel.PointLayer | QgsMapLayerProxyModel.LineLayer)
|
||||
pointAndPolygon = QgsMapLayerProxyModel.Filters(QgsMapLayerProxyModel.PointLayer | QgsMapLayerProxyModel.PolygonLayer)
|
||||
|
||||
self.settings.setValue('flag', 'PointLayer|PolygonLayer')
|
||||
self.assertEqual(self.settings.flagValue('flag', pointAndLine), pointAndPolygon)
|
||||
self.settings.setValue('flag', 'dummy_setting')
|
||||
self.assertEqual(self.settings.flagValue('flag', pointAndLine), pointAndLine)
|
||||
self.assertEqual(type(self.settings.flagValue('enum', pointAndLine)), QgsMapLayerProxyModel.Filters)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user