Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsxmlutils.cpp 3 : : --------------------- 4 : : begin : December 2013 5 : : copyright : (C) 2013 by Martin Dobias 6 : : email : wonder dot sk at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : #include "qgsxmlutils.h" 16 : : 17 : : #include <QDomElement> 18 : : 19 : : #include "qgslogger.h" 20 : : #include "qgsrectangle.h" 21 : : #include "qgsproperty.h" 22 : : #include "qgssymbollayerutils.h" 23 : : #include "qgsprocessingparameters.h" 24 : : #include "qgsremappingproxyfeaturesink.h" 25 : : 26 : 0 : QgsUnitTypes::DistanceUnit QgsXmlUtils::readMapUnits( const QDomElement &element ) 27 : : { 28 : 0 : if ( "unknown" == element.text() ) 29 : : { 30 : 0 : return QgsUnitTypes::DistanceUnknownUnit; 31 : : } 32 : : else 33 : : { 34 : 0 : QgsUnitTypes::DistanceUnit unit = QgsUnitTypes::decodeDistanceUnit( element.text() ); 35 : 0 : return unit == QgsUnitTypes::DistanceUnknownUnit ? QgsUnitTypes::DistanceDegrees : unit; 36 : : } 37 : 0 : } 38 : : 39 : 0 : QgsRectangle QgsXmlUtils::readRectangle( const QDomElement &element ) 40 : : { 41 : 0 : QgsRectangle aoi; 42 : : 43 : 0 : QDomNode xminNode = element.namedItem( QStringLiteral( "xmin" ) ); 44 : 0 : QDomNode yminNode = element.namedItem( QStringLiteral( "ymin" ) ); 45 : 0 : QDomNode xmaxNode = element.namedItem( QStringLiteral( "xmax" ) ); 46 : 0 : QDomNode ymaxNode = element.namedItem( QStringLiteral( "ymax" ) ); 47 : : 48 : 0 : QDomElement exElement = xminNode.toElement(); 49 : 0 : double xmin = exElement.text().toDouble(); 50 : 0 : aoi.setXMinimum( xmin ); 51 : : 52 : 0 : exElement = yminNode.toElement(); 53 : 0 : double ymin = exElement.text().toDouble(); 54 : 0 : aoi.setYMinimum( ymin ); 55 : : 56 : 0 : exElement = xmaxNode.toElement(); 57 : 0 : double xmax = exElement.text().toDouble(); 58 : 0 : aoi.setXMaximum( xmax ); 59 : : 60 : 0 : exElement = ymaxNode.toElement(); 61 : 0 : double ymax = exElement.text().toDouble(); 62 : 0 : aoi.setYMaximum( ymax ); 63 : : 64 : : return aoi; 65 : 0 : } 66 : : 67 : : 68 : : 69 : 0 : QDomElement QgsXmlUtils::writeMapUnits( QgsUnitTypes::DistanceUnit units, QDomDocument &doc ) 70 : : { 71 : 0 : QString unitsString = QgsUnitTypes::encodeUnit( units ); 72 : : // maintain compatibility with old projects 73 : 0 : if ( units == QgsUnitTypes::DistanceUnknownUnit ) 74 : 0 : unitsString = QStringLiteral( "unknown" ); 75 : : 76 : 0 : QDomElement unitsNode = doc.createElement( QStringLiteral( "units" ) ); 77 : 0 : unitsNode.appendChild( doc.createTextNode( unitsString ) ); 78 : 0 : return unitsNode; 79 : 0 : } 80 : : 81 : 0 : QDomElement QgsXmlUtils::writeRectangle( const QgsRectangle &rect, QDomDocument &doc, const QString &elementName ) 82 : : { 83 : 0 : QDomElement xMin = doc.createElement( QStringLiteral( "xmin" ) ); 84 : 0 : QDomElement yMin = doc.createElement( QStringLiteral( "ymin" ) ); 85 : 0 : QDomElement xMax = doc.createElement( QStringLiteral( "xmax" ) ); 86 : 0 : QDomElement yMax = doc.createElement( QStringLiteral( "ymax" ) ); 87 : : 88 : 0 : QDomText xMinText = doc.createTextNode( qgsDoubleToString( rect.xMinimum() ) ); 89 : 0 : QDomText yMinText = doc.createTextNode( qgsDoubleToString( rect.yMinimum() ) ); 90 : 0 : QDomText xMaxText = doc.createTextNode( qgsDoubleToString( rect.xMaximum() ) ); 91 : 0 : QDomText yMaxText = doc.createTextNode( qgsDoubleToString( rect.yMaximum() ) ); 92 : : 93 : 0 : xMin.appendChild( xMinText ); 94 : 0 : yMin.appendChild( yMinText ); 95 : 0 : xMax.appendChild( xMaxText ); 96 : 0 : yMax.appendChild( yMaxText ); 97 : : 98 : 0 : QDomElement extentNode = doc.createElement( elementName ); 99 : 0 : extentNode.appendChild( xMin ); 100 : 0 : extentNode.appendChild( yMin ); 101 : 0 : extentNode.appendChild( xMax ); 102 : 0 : extentNode.appendChild( yMax ); 103 : 0 : return extentNode; 104 : 0 : } 105 : : 106 : 0 : QDomElement QgsXmlUtils::writeVariant( const QVariant &value, QDomDocument &doc ) 107 : : { 108 : 0 : QDomElement element = doc.createElement( QStringLiteral( "Option" ) ); 109 : 0 : switch ( value.type() ) 110 : : { 111 : : case QVariant::Invalid: 112 : : { 113 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "invalid" ) ); 114 : 0 : break; 115 : : } 116 : : 117 : : case QVariant::Map: 118 : : { 119 : 0 : QVariantMap map = value.toMap(); 120 : : 121 : 0 : for ( auto option = map.constBegin(); option != map.constEnd(); ++option ) 122 : : { 123 : 0 : QDomElement optionElement = writeVariant( option.value(), doc ); 124 : 0 : optionElement.setAttribute( QStringLiteral( "name" ), option.key() ); 125 : 0 : element.appendChild( optionElement ); 126 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "Map" ) ); 127 : 0 : } 128 : : break; 129 : 0 : } 130 : : 131 : : case QVariant::List: 132 : : { 133 : 0 : QVariantList list = value.toList(); 134 : : 135 : 0 : const auto constList = list; 136 : 0 : for ( const QVariant &value : constList ) 137 : : { 138 : 0 : QDomElement valueElement = writeVariant( value, doc ); 139 : 0 : element.appendChild( valueElement ); 140 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "List" ) ); 141 : 0 : } 142 : : break; 143 : 0 : } 144 : : 145 : : case QVariant::StringList: 146 : : { 147 : 0 : QStringList list = value.toStringList(); 148 : : 149 : 0 : const auto constList = list; 150 : 0 : for ( const QString &value : constList ) 151 : : { 152 : 0 : QDomElement valueElement = writeVariant( value, doc ); 153 : 0 : element.appendChild( valueElement ); 154 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "StringList" ) ); 155 : 0 : } 156 : : break; 157 : 0 : } 158 : : 159 : : case QVariant::Int: 160 : : case QVariant::UInt: 161 : : case QVariant::Bool: 162 : : case QVariant::Double: 163 : : case QVariant::LongLong: 164 : : case QVariant::ULongLong: 165 : : case QVariant::String: 166 : 0 : element.setAttribute( QStringLiteral( "type" ), QVariant::typeToName( value.type() ) ); 167 : 0 : element.setAttribute( QStringLiteral( "value" ), value.toString() ); 168 : 0 : break; 169 : : 170 : : case QVariant::Char: 171 : 0 : element.setAttribute( QStringLiteral( "type" ), QVariant::typeToName( value.type() ) ); 172 : 0 : element.setAttribute( QStringLiteral( "value" ), value.isNull() ? QString() : value.toString() ); 173 : 0 : break; 174 : : 175 : : case QVariant::Color: 176 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "color" ) ); 177 : 0 : element.setAttribute( QStringLiteral( "value" ), value.value< QColor >().isValid() ? QgsSymbolLayerUtils::encodeColor( value.value< QColor >() ) : QString() ); 178 : 0 : break; 179 : : 180 : : case QVariant::DateTime: 181 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "datetime" ) ); 182 : 0 : element.setAttribute( QStringLiteral( "value" ), value.value< QDateTime >().isValid() ? value.toDateTime().toString( Qt::ISODate ) : QString() ); 183 : 0 : break; 184 : : 185 : : case QVariant::Date: 186 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "date" ) ); 187 : 0 : element.setAttribute( QStringLiteral( "value" ), value.value< QDate >().isValid() ? value.toDate().toString( Qt::ISODate ) : QString() ); 188 : 0 : break; 189 : : 190 : : case QVariant::Time: 191 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "time" ) ); 192 : 0 : element.setAttribute( QStringLiteral( "value" ), value.value< QTime >().isValid() ? value.toTime().toString( Qt::ISODate ) : QString() ); 193 : 0 : break; 194 : : 195 : : case QVariant::UserType: 196 : : { 197 : 0 : if ( value.canConvert< QgsProperty >() ) 198 : : { 199 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProperty" ) ); 200 : 0 : const QDomElement propertyElem = QgsXmlUtils::writeVariant( value.value< QgsProperty >().toVariant(), doc ); 201 : 0 : element.appendChild( propertyElem ); 202 : : break; 203 : 0 : } 204 : 0 : else if ( value.canConvert< QgsCoordinateReferenceSystem >() ) 205 : : { 206 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsCoordinateReferenceSystem" ) ); 207 : 0 : const QgsCoordinateReferenceSystem crs = value.value< QgsCoordinateReferenceSystem >(); 208 : 0 : crs.writeXml( element, doc ); 209 : : break; 210 : 0 : } 211 : 0 : else if ( value.canConvert< QgsGeometry >() ) 212 : : { 213 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsGeometry" ) ); 214 : 0 : const QgsGeometry geom = value.value< QgsGeometry >(); 215 : 0 : element.setAttribute( QStringLiteral( "value" ), geom.asWkt() ); 216 : : break; 217 : 0 : } 218 : 0 : else if ( value.canConvert< QgsProcessingOutputLayerDefinition >() ) 219 : : { 220 : 0 : QDomElement valueElement = writeVariant( value.value< QgsProcessingOutputLayerDefinition >().toVariant(), doc ); 221 : 0 : element.appendChild( valueElement ); 222 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProcessingOutputLayerDefinition" ) ); 223 : : break; 224 : 0 : } 225 : 0 : else if ( value.canConvert< QgsProcessingFeatureSourceDefinition >() ) 226 : : { 227 : 0 : QDomElement valueElement = writeVariant( value.value< QgsProcessingFeatureSourceDefinition >().toVariant(), doc ); 228 : 0 : element.appendChild( valueElement ); 229 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProcessingFeatureSourceDefinition" ) ); 230 : : break; 231 : 0 : } 232 : 0 : else if ( value.canConvert< QgsRemappingSinkDefinition >() ) 233 : : { 234 : 0 : QDomElement valueElement = writeVariant( value.value< QgsRemappingSinkDefinition >().toVariant(), doc ); 235 : 0 : element.appendChild( valueElement ); 236 : 0 : element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsRemappingSinkDefinition" ) ); 237 : : break; 238 : 0 : } 239 : : Q_ASSERT_X( false, "QgsXmlUtils::writeVariant", QStringLiteral( "unsupported user variant type %1" ).arg( QMetaType::typeName( value.userType() ) ).toLocal8Bit() ); 240 : 0 : break; 241 : : } 242 : : 243 : : default: 244 : : Q_ASSERT_X( false, "QgsXmlUtils::writeVariant", QStringLiteral( "unsupported variant type %1" ).arg( QVariant::typeToName( value.type() ) ).toLocal8Bit() ); 245 : 0 : break; 246 : : } 247 : : 248 : 0 : return element; 249 : 0 : } 250 : : 251 : 21246 : QVariant QgsXmlUtils::readVariant( const QDomElement &element ) 252 : : { 253 : 42492 : QString type = element.attribute( QStringLiteral( "type" ) ); 254 : : 255 : 21246 : if ( type == QLatin1String( "invalid" ) ) 256 : : { 257 : 0 : return QVariant(); 258 : : } 259 : 21246 : else if ( type == QLatin1String( "int" ) ) 260 : : { 261 : 0 : return element.attribute( QStringLiteral( "value" ) ).toInt(); 262 : : } 263 : 21246 : else if ( type == QLatin1String( "uint" ) ) 264 : : { 265 : 0 : return element.attribute( QStringLiteral( "value" ) ).toUInt(); 266 : : } 267 : 21246 : else if ( type == QLatin1String( "qlonglong" ) ) 268 : : { 269 : 0 : return element.attribute( QStringLiteral( "value" ) ).toLongLong(); 270 : : } 271 : 21246 : else if ( type == QLatin1String( "qulonglong" ) ) 272 : : { 273 : 0 : return element.attribute( QStringLiteral( "value" ) ).toULongLong(); 274 : : } 275 : 21246 : else if ( type == QLatin1String( "double" ) ) 276 : : { 277 : 0 : return element.attribute( QStringLiteral( "value" ) ).toDouble(); 278 : : } 279 : 21246 : else if ( type == QLatin1String( "QString" ) ) 280 : : { 281 : 33484 : return element.attribute( QStringLiteral( "value" ) ); 282 : : } 283 : 4504 : else if ( type == QLatin1String( "QChar" ) ) 284 : : { 285 : 0 : const QString res = element.attribute( QStringLiteral( "value" ) ); 286 : 0 : return res.isEmpty() ? QChar() : res.at( 0 ); 287 : 0 : } 288 : 4504 : else if ( type == QLatin1String( "bool" ) ) 289 : : { 290 : 0 : return element.attribute( QStringLiteral( "value" ) ) == QLatin1String( "true" ); 291 : : } 292 : 4504 : else if ( type == QLatin1String( "color" ) ) 293 : : { 294 : 0 : return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QColor() : QgsSymbolLayerUtils::decodeColor( element.attribute( QStringLiteral( "value" ) ) ); 295 : : } 296 : 4504 : else if ( type == QLatin1String( "datetime" ) ) 297 : : { 298 : 0 : return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QDateTime() : QDateTime::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate ); 299 : : } 300 : 4504 : else if ( type == QLatin1String( "date" ) ) 301 : : { 302 : 0 : return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QDate() : QDate::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate ); 303 : : } 304 : 4504 : else if ( type == QLatin1String( "time" ) ) 305 : : { 306 : 0 : return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QTime() : QTime::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate ); 307 : : } 308 : 4504 : else if ( type == QLatin1String( "Map" ) ) 309 : : { 310 : 2374 : QVariantMap map; 311 : 2374 : QDomNodeList options = element.childNodes(); 312 : : 313 : 20710 : for ( int i = 0; i < options.count(); ++i ) 314 : : { 315 : 18336 : QDomElement elem = options.at( i ).toElement(); 316 : 18336 : if ( elem.tagName() == QLatin1String( "Option" ) ) 317 : 36672 : map.insert( elem.attribute( QStringLiteral( "name" ) ), readVariant( elem ) ); 318 : 18336 : } 319 : 2374 : return map; 320 : 2374 : } 321 : 2130 : else if ( type == QLatin1String( "List" ) ) 322 : : { 323 : 0 : QVariantList list; 324 : 0 : QDomNodeList values = element.childNodes(); 325 : 0 : for ( int i = 0; i < values.count(); ++i ) 326 : : { 327 : 0 : QDomElement elem = values.at( i ).toElement(); 328 : 0 : list.append( readVariant( elem ) ); 329 : 0 : } 330 : 0 : return list; 331 : 0 : } 332 : 2130 : else if ( type == QLatin1String( "StringList" ) ) 333 : : { 334 : 0 : QStringList list; 335 : 0 : QDomNodeList values = element.childNodes(); 336 : 0 : for ( int i = 0; i < values.count(); ++i ) 337 : : { 338 : 0 : QDomElement elem = values.at( i ).toElement(); 339 : 0 : list.append( readVariant( elem ).toString() ); 340 : 0 : } 341 : 0 : return list; 342 : 0 : } 343 : 2130 : else if ( type == QLatin1String( "QgsProperty" ) ) 344 : : { 345 : 0 : const QDomNodeList values = element.childNodes(); 346 : 0 : if ( values.isEmpty() ) 347 : 0 : return QVariant(); 348 : : 349 : 0 : QgsProperty p; 350 : 0 : if ( p.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ) ) ) 351 : 0 : return p; 352 : : 353 : 0 : return QVariant(); 354 : 0 : } 355 : 2130 : else if ( type == QLatin1String( "QgsCoordinateReferenceSystem" ) ) 356 : : { 357 : 0 : QgsCoordinateReferenceSystem crs; 358 : 0 : crs.readXml( element ); 359 : 0 : return crs; 360 : 0 : } 361 : 2130 : else if ( type == QLatin1String( "QgsGeometry" ) ) 362 : : { 363 : 0 : return QgsGeometry::fromWkt( element.attribute( "value" ) ); 364 : : } 365 : 2130 : else if ( type == QLatin1String( "QgsProcessingOutputLayerDefinition" ) ) 366 : : { 367 : 0 : QgsProcessingOutputLayerDefinition res; 368 : 0 : const QDomNodeList values = element.childNodes(); 369 : 0 : if ( values.isEmpty() ) 370 : 0 : return QVariant(); 371 : : 372 : 0 : if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) ) 373 : 0 : return res; 374 : : 375 : 0 : return QVariant(); 376 : 0 : } 377 : 2130 : else if ( type == QLatin1String( "QgsProcessingFeatureSourceDefinition" ) ) 378 : : { 379 : 0 : QgsProcessingFeatureSourceDefinition res; 380 : 0 : const QDomNodeList values = element.childNodes(); 381 : 0 : if ( values.isEmpty() ) 382 : 0 : return QVariant(); 383 : : 384 : 0 : if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) ) 385 : 0 : return res; 386 : : 387 : 0 : return QVariant(); 388 : 0 : } 389 : 2130 : else if ( type == QLatin1String( "QgsRemappingSinkDefinition" ) ) 390 : : { 391 : 0 : QgsRemappingSinkDefinition res; 392 : 0 : const QDomNodeList values = element.childNodes(); 393 : 0 : if ( values.isEmpty() ) 394 : 0 : return QVariant(); 395 : : 396 : 0 : if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) ) 397 : 0 : return QVariant::fromValue( res ); 398 : : 399 : 0 : return QVariant(); 400 : 0 : } 401 : : else 402 : : { 403 : 2130 : return QVariant(); 404 : : } 405 : 21246 : }