Skip to content

Commit 05f55f0

Browse files
authoredMay 11, 2021
use QgsXmlUtils::read/writeVariant to save QgsObjectCustomProperties (#43099)
* use QgsXmlUtils to save QgsObjectCustomProperties This allows to have more complex properties such as maps * add test * code layout
1 parent ee022ba commit 05f55f0

File tree

2 files changed

+54
-49
lines changed

2 files changed

+54
-49
lines changed
 

‎src/core/qgsobjectcustomproperties.cpp

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "qgsobjectcustomproperties.h"
1919
#include "qgis.h"
20+
#include "qgsxmlutils.h"
2021

2122
#include <QDomNode>
2223
#include <QStringList>
@@ -77,39 +78,53 @@ void QgsObjectCustomProperties::readXml( const QDomNode &parentNode, const QStri
7778
mMap.clear();
7879
}
7980

80-
QDomNodeList nodes = propsNode.childNodes();
81-
82-
for ( int i = 0; i < nodes.size(); i++ )
81+
const QVariant newProps = QgsXmlUtils::readVariant( propsNode.firstChildElement() );
82+
if ( newProps.type() == QVariant::Map )
83+
{
84+
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
85+
const QVariantMap propsMap = newProps.toMap();
86+
for ( auto it = propsMap.constBegin(); it != propsMap.constEnd(); ++it )
87+
mMap.insert( it.key(), it.value() );
88+
#else
89+
mMap.insert( newProps.toMap() );
90+
#endif
91+
}
92+
else
8393
{
84-
QDomNode propNode = nodes.at( i );
85-
if ( propNode.isNull() || propNode.nodeName() != QLatin1String( "property" ) )
86-
continue;
87-
QDomElement propElement = propNode.toElement();
94+
// backward compatibility code for QGIS < 3.20
95+
QDomNodeList nodes = propsNode.childNodes();
8896

89-
QString key = propElement.attribute( QStringLiteral( "key" ) );
90-
if ( key.isEmpty() || key.startsWith( keyStartsWith ) )
97+
for ( int i = 0; i < nodes.size(); i++ )
9198
{
92-
if ( propElement.hasAttribute( QStringLiteral( "value" ) ) )
93-
{
94-
QString value = propElement.attribute( QStringLiteral( "value" ) );
95-
mMap[key] = QVariant( value );
96-
}
97-
else
98-
{
99-
QStringList list;
99+
QDomNode propNode = nodes.at( i );
100+
if ( propNode.isNull() || propNode.nodeName() != QLatin1String( "property" ) )
101+
continue;
102+
QDomElement propElement = propNode.toElement();
100103

101-
for ( QDomElement itemElement = propElement.firstChildElement( QStringLiteral( "value" ) );
102-
!itemElement.isNull();
103-
itemElement = itemElement.nextSiblingElement( QStringLiteral( "value" ) ) )
104+
QString key = propElement.attribute( QStringLiteral( "key" ) );
105+
if ( key.isEmpty() || key.startsWith( keyStartsWith ) )
106+
{
107+
if ( propElement.hasAttribute( QStringLiteral( "value" ) ) )
104108
{
105-
list << itemElement.text();
109+
QString value = propElement.attribute( QStringLiteral( "value" ) );
110+
mMap[key] = QVariant( value );
106111
}
112+
else
113+
{
114+
QStringList list;
107115

108-
mMap[key] = QVariant( list );
116+
for ( QDomElement itemElement = propElement.firstChildElement( QStringLiteral( "value" ) );
117+
!itemElement.isNull();
118+
itemElement = itemElement.nextSiblingElement( QStringLiteral( "value" ) ) )
119+
{
120+
list << itemElement.text();
121+
}
122+
123+
mMap[key] = QVariant( list );
124+
}
109125
}
110126
}
111127
}
112-
113128
}
114129

115130
void QgsObjectCustomProperties::writeXml( QDomNode &parentNode, QDomDocument &doc ) const
@@ -122,32 +137,7 @@ void QgsObjectCustomProperties::writeXml( QDomNode &parentNode, QDomDocument &do
122137
}
123138

124139
QDomElement propsElement = doc.createElement( QStringLiteral( "customproperties" ) );
125-
126-
auto keys = mMap.keys();
127-
128-
std::sort( keys.begin(), keys.end() );
129-
130-
for ( const auto &key : std::as_const( keys ) )
131-
{
132-
QDomElement propElement = doc.createElement( QStringLiteral( "property" ) );
133-
propElement.setAttribute( QStringLiteral( "key" ), key );
134-
const QVariant value = mMap.value( key );
135-
if ( value.canConvert<QString>() )
136-
{
137-
propElement.setAttribute( QStringLiteral( "value" ), value.toString() );
138-
}
139-
else if ( value.canConvert<QStringList>() )
140-
{
141-
const auto constToStringList = value.toStringList();
142-
for ( const QString &valueStr : constToStringList )
143-
{
144-
QDomElement itemElement = doc.createElement( QStringLiteral( "value" ) );
145-
itemElement.appendChild( doc.createTextNode( valueStr ) );
146-
propElement.appendChild( itemElement );
147-
}
148-
}
149-
propsElement.appendChild( propElement );
150-
}
140+
propsElement.appendChild( QgsXmlUtils::writeVariant( mMap, doc ) );
151141

152142
parentNode.appendChild( propsElement );
153143
}

‎tests/src/python/test_qgsobjectcustomproperties.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,21 @@ def testSaveRestore(self):
7979
self.assertEqual(props2.value('a', defaultValue=6), '7')
8080
self.assertEqual(props2.value('b', defaultValue='yy'), 'xx')
8181

82+
def testCompatibilityRestore(self):
83+
# for pre 3.20
84+
legacy_xml = '<test>\n <customproperties>\n <property key="a" value="7"/>\n <property key="b" value="xx"/>\n </customproperties>\n</test>\n'
85+
doc = QDomDocument()
86+
doc.setContent(legacy_xml)
87+
88+
props = QgsObjectCustomProperties()
89+
props.readXml(doc.documentElement())
90+
91+
self.assertCountEqual(props.keys(), ['a', 'b'])
92+
self.assertTrue(props.contains('a'))
93+
self.assertTrue(props.contains('b'))
94+
self.assertEqual(props.value('a', defaultValue=6), '7')
95+
self.assertEqual(props.value('b', defaultValue='yy'), 'xx')
96+
8297

8398
if __name__ == '__main__':
8499
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.