QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsprojectfiletransform.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprojectfiletransform.cpp - description
3 -------------------
4 begin : Sun 15 dec 2007
5 copyright : (C) 2007 by Magnus Homann
6 email : magnus at homann.se
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18
20#include "qgsprojectversion.h"
21#include "qgslogger.h"
22#include "qgsrasterlayer.h"
23#include "qgsreadwritecontext.h"
25#include "qgsvectorlayer.h"
26#include "qgspathresolver.h"
27#include "qgsproject.h"
28#include "qgsprojectproperty.h"
29#include "qgsrasterbandstats.h"
31#include "qgsxmlutils.h"
32
33#include <QTextStream>
34#include <QDomDocument>
35#include <QRegularExpression>
36#ifndef QT_NO_PRINTER
37#include <QPrinter> //to find out screen resolution
38#endif
39#include <cstdlib>
40
42
43// Transformer functions below. Declare functions here,
44// define them in qgsprojectfiletransform.cpp and add them
45// to the transformArray with proper version number
46void transformNull( QgsProjectFileTransform *pft ) { Q_UNUSED( pft ) } // Do absolutely nothing
56
57//helper functions
58int rasterBandNumber( const QDomElement &rasterPropertiesElem, const QString &bandName, QgsRasterLayer *rlayer );
59void transformContrastEnhancement( QDomDocument &doc, const QDomElement &rasterproperties, QDomElement &rendererElem );
60void transformRasterTransparency( QDomDocument &doc, const QDomElement &orig, QDomElement &rendererElem );
61
62typedef struct
63{
66 void ( * transformFunc )( QgsProjectFileTransform * );
68
69typedef std::vector<TransformItem> Transformers;
70
72{
73 Q_UNUSED( newVersion )
74 bool returnValue = false;
75
76 static const Transformers transformers(
77 {
78 {PFV( 0, 8, 0 ), PFV( 0, 8, 1 ), &transformNull},
79 {PFV( 0, 8, 1 ), PFV( 0, 9, 0 ), &transform081to090},
80 {PFV( 0, 9, 0 ), PFV( 0, 9, 1 ), &transformNull},
81 {PFV( 0, 9, 1 ), PFV( 0, 10, 0 ), &transform091to0100},
82 // Following line is a hack that takes us straight from 0.9.2 to 0.11.0
83 // due to an unknown bug in migrating 0.9.2 files which we didn't pursue (TS & GS)
84 {PFV( 0, 9, 2 ), PFV( 0, 11, 0 ), &transformNull},
85 {PFV( 0, 10, 0 ), PFV( 0, 11, 0 ), &transform0100to0110},
86 {PFV( 0, 11, 0 ), PFV( 1, 0, 0 ), &transform0110to1000},
87 {PFV( 1, 0, 0 ), PFV( 1, 1, 0 ), &transformNull},
88 {PFV( 1, 0, 2 ), PFV( 1, 1, 0 ), &transformNull},
89 {PFV( 1, 1, 0 ), PFV( 1, 2, 0 ), &transform1100to1200},
90 {PFV( 1, 2, 0 ), PFV( 1, 3, 0 ), &transformNull},
91 {PFV( 1, 3, 0 ), PFV( 1, 4, 0 ), &transformNull},
92 {PFV( 1, 4, 0 ), PFV( 1, 5, 0 ), &transform1400to1500},
93 {PFV( 1, 5, 0 ), PFV( 1, 6, 0 ), &transformNull},
94 {PFV( 1, 6, 0 ), PFV( 1, 7, 0 ), &transformNull},
95 {PFV( 1, 7, 0 ), PFV( 1, 8, 0 ), &transformNull},
96 {PFV( 1, 8, 0 ), PFV( 1, 9, 0 ), &transform1800to1900},
97 {PFV( 1, 9, 0 ), PFV( 2, 0, 0 ), &transformNull},
98 {PFV( 2, 0, 0 ), PFV( 2, 1, 0 ), &transformNull},
99 {PFV( 2, 1, 0 ), PFV( 2, 2, 0 ), &transformNull},
100 {PFV( 2, 2, 0 ), PFV( 2, 3, 0 ), &transform2200to2300},
101 // A transformer with a NULL from version means that it should be run when upgrading
102 // from any version and will take care that it's not going to cause trouble if it's
103 // run several times on the same file.
104 {PFV(), PFV( 3, 0, 0 ), &transform3000},
105 } );
106
107 if ( !mDom.isNull() )
108 {
109 for ( const TransformItem &transformer : transformers )
110 {
111 if ( transformer.to >= mCurrentVersion && ( transformer.from == mCurrentVersion || transformer.from.isNull() ) )
112 {
113 // Run the transformer, and update the revision in every case
114 ( *( transformer.transformFunc ) )( this );
115 mCurrentVersion = transformer.to;
116 returnValue = true;
117 }
118 }
119 }
120 return returnValue;
121}
122
124{
125 QgsDebugMsg( QStringLiteral( "Current project file version is %1.%2.%3" )
126 .arg( mCurrentVersion.majorVersion() )
127 .arg( mCurrentVersion.minorVersion() )
128 .arg( mCurrentVersion.subVersion() ) );
129#ifdef QGISDEBUG
130 // Using QgsDebugMsg() didn't print the entire pft->dom()...
131 std::cout << mDom.toString( 2 ).toLatin1().constData(); // OK
132#endif
133}
134
135/*
136 * Transformers below!
137 */
138
140{
141 QgsDebugMsg( QStringLiteral( "Entering..." ) );
142 if ( ! pft->dom().isNull() )
143 {
144 // Start with inserting a mapcanvas element and populate it
145
146 QDomElement mapCanvas; // A null element.
147
148 // there should only be one <qgis>
149 QDomNode qgis = pft->dom().firstChildElement( QStringLiteral( "qgis" ) );
150 if ( ! qgis.isNull() )
151 {
152 QgsDebugMsg( QStringLiteral( "Populating new mapcanvas" ) );
153
154 // Create a mapcanvas
155 mapCanvas = pft->dom().createElement( QStringLiteral( "mapcanvas" ) );
156 // Append mapcanvas to parent 'qgis'.
157 qgis.appendChild( mapCanvas );
158 // Re-parent units
159 mapCanvas.appendChild( qgis.namedItem( QStringLiteral( "units" ) ) );
160 // Re-parent extent
161 mapCanvas.appendChild( qgis.namedItem( QStringLiteral( "extent" ) ) );
162
163 // See if we can find if projection is on.
164
165 const QDomElement properties = qgis.firstChildElement( QStringLiteral( "properties" ) );
166 const QDomElement spatial = properties.firstChildElement( QStringLiteral( "SpatialRefSys" ) );
167 const QDomElement hasCrsTransformEnabled = spatial.firstChildElement( QStringLiteral( "ProjectionsEnabled" ) );
168 // Type is 'int', and '1' if on.
169 // Create an element
170 QDomElement projection = pft->dom().createElement( QStringLiteral( "projections" ) );
171 QgsDebugMsg( QStringLiteral( "Projection flag: " ) + hasCrsTransformEnabled.text() );
172 // Set flag from ProjectionsEnabled
173 projection.appendChild( pft->dom().createTextNode( hasCrsTransformEnabled.text() ) );
174 // Set new element as child of <mapcanvas>
175 mapCanvas.appendChild( projection );
176
177 }
178
179
180 // Transforming coordinate-transforms
181 // Create a list of all map layers
182 const QDomNodeList mapLayers = pft->dom().elementsByTagName( QStringLiteral( "maplayer" ) );
183 bool doneDestination = false;
184 for ( int i = 0; i < mapLayers.count(); i++ )
185 {
186 QDomNode mapLayer = mapLayers.item( i );
187 // Find the coordinatetransform
188 const QDomNode coordinateTransform = mapLayer.namedItem( QStringLiteral( "coordinatetransform" ) );
189 // Find the sourcesrs
190 const QDomNode sourceCrs = coordinateTransform.namedItem( QStringLiteral( "sourcesrs" ) );
191 // Rename to srs
192 sourceCrs.toElement().setTagName( QStringLiteral( "srs" ) );
193 // Re-parent to maplayer
194 mapLayer.appendChild( sourceCrs );
195 // Re-move coordinatetransform
196 // Take the destination CRS of the first layer and use for mapcanvas projection
197 if ( ! doneDestination )
198 {
199 // Use destination CRS from the last layer
200 const QDomNode destinationCRS = coordinateTransform.namedItem( QStringLiteral( "destinationsrs" ) );
201 // Re-parent the destination CRS to the mapcanvas
202 // If mapcanvas wasn't set, nothing will happen.
203 mapCanvas.appendChild( destinationCRS );
204 // Only do this once
205 doneDestination = true;
206 }
207 mapLayer.removeChild( coordinateTransform );
208 //QDomNode id = mapLayer.namedItem("id");
209 //QgsDebugMsg(QString("Found maplayer ") + id.toElement().text());
210
211 }
212
213 // Set the flag 'visible' to match the status of 'checked'
214 const QDomNodeList legendLayerFiles = pft->dom().elementsByTagName( QStringLiteral( "legendlayerfile" ) );
215 QgsDebugMsg( QStringLiteral( "Legend layer file entries: " ) + QString::number( legendLayerFiles.count() ) );
216 for ( int i = 0; i < mapLayers.count(); i++ )
217 {
218 // Get one maplayer element from list
219 const QDomElement mapLayer = mapLayers.item( i ).toElement();
220 // Find it's id.
221 const QString id = mapLayer.firstChildElement( QStringLiteral( "id" ) ).text();
222 QgsDebugMsg( QStringLiteral( "Handling layer %1" ).arg( id ) );
223 // Now, look it up in legend
224 for ( int j = 0; j < legendLayerFiles.count(); j++ )
225 {
226 QDomElement legendLayerFile = legendLayerFiles.item( j ).toElement();
227 if ( id == legendLayerFile.attribute( QStringLiteral( "layerid" ) ) )
228 {
229 // Found a the legend layer that matches the maplayer
230 QgsDebugMsg( QStringLiteral( "Found matching id" ) );
231
232 // Set visible flag from maplayer to legendlayer
233 legendLayerFile.setAttribute( QStringLiteral( "visible" ), mapLayer.attribute( QStringLiteral( "visible" ) ) );
234
235 // Set overview flag from maplayer to legendlayer
236 legendLayerFile.setAttribute( QStringLiteral( "isInOverview" ), mapLayer.attribute( QStringLiteral( "showInOverviewFlag" ) ) );
237 }
238 }
239 }
240 }
241}
242
244{
245 if ( ! pft->dom().isNull() )
246 {
247 // Insert transforms here!
248 const QDomNodeList rasterPropertyList = pft->dom().elementsByTagName( QStringLiteral( "rasterproperties" ) );
249 QgsDebugMsg( QStringLiteral( "Raster properties file entries: " ) + QString::number( rasterPropertyList.count() ) );
250 for ( int i = 0; i < rasterPropertyList.count(); i++ )
251 {
252 // Get one rasterproperty element from list, and rename the sub-properties.
253 const QDomNode rasterProperty = rasterPropertyList.item( i );
254 // rasterProperty.namedItem("").toElement().setTagName("");
255
256 rasterProperty.namedItem( QStringLiteral( "stdDevsToPlotDouble" ) ).toElement().setTagName( QStringLiteral( "mStandardDeviations" ) );
257
258 rasterProperty.namedItem( QStringLiteral( "invertHistogramFlag" ) ).toElement().setTagName( QStringLiteral( "mInvertPixelsFlag" ) );
259 rasterProperty.namedItem( QStringLiteral( "showDebugOverLayFlag" ) ).toElement().setTagName( QStringLiteral( "mDebugOverLayFlag" ) );
260
261 rasterProperty.namedItem( QStringLiteral( "redBandNameQString" ) ).toElement().setTagName( QStringLiteral( "mRedBandName" ) );
262 rasterProperty.namedItem( QStringLiteral( "blueBandNameQString" ) ).toElement().setTagName( QStringLiteral( "mBlueBandName" ) );
263 rasterProperty.namedItem( QStringLiteral( "greenBandNameQString" ) ).toElement().setTagName( QStringLiteral( "mGreenBandName" ) );
264 rasterProperty.namedItem( QStringLiteral( "grayBandNameQString" ) ).toElement().setTagName( QStringLiteral( "mGrayBandName" ) );
265 }
266
267 // Changing symbol size for hard: symbols
268 const QDomNodeList symbolPropertyList = pft->dom().elementsByTagName( QStringLiteral( "symbol" ) );
269 for ( int i = 0; i < symbolPropertyList.count(); i++ )
270 {
271 // Get the <poinmtsymbol> to check for 'hard:' for each <symbol>
272 QDomNode symbolProperty = symbolPropertyList.item( i );
273
274 const QDomElement pointSymbol = symbolProperty.firstChildElement( QStringLiteral( "pointsymbol" ) );
275 if ( pointSymbol.text().startsWith( QLatin1String( "hard:" ) ) )
276 {
277 // Get pointsize and line width
278 const int lineWidth = symbolProperty.firstChildElement( QStringLiteral( "outlinewidth" ) ).text().toInt();
279 int pointSize = symbolProperty.firstChildElement( QStringLiteral( "pointsize" ) ).text().toInt();
280 // Just a precaution, checking for 0
281 if ( pointSize != 0 )
282 {
283 // int r = (s-2*lw)/2-1 --> 2r = (s-2*lw)-2 --> 2r+2 = s-2*lw
284 // --> 2r+2+2*lw = s
285 // where '2r' is the old size.
286 pointSize = pointSize + 2 + 2 * lineWidth;
287 QgsDebugMsg( QStringLiteral( "Setting point size to %1" ).arg( pointSize ) );
288 QDomElement newPointSizeProperty = pft->dom().createElement( QStringLiteral( "pointsize" ) );
289 const QDomText newPointSizeTxt = pft->dom().createTextNode( QString::number( pointSize ) );
290 newPointSizeProperty.appendChild( newPointSizeTxt );
291 symbolProperty.replaceChild( newPointSizeProperty, pointSymbol );
292 }
293 }
294 }
295
296 }
297}
298
300{
301 if ( ! pft->dom().isNull() )
302 {
303#ifndef QT_NO_PRINTER
304 //Change 'outlinewidth' in QgsSymbol
305 const QPrinter myPrinter( QPrinter::ScreenResolution );
306 const int screenDpi = myPrinter.resolution();
307 const double widthScaleFactor = 25.4 / screenDpi;
308
309 const QDomNodeList outlineWidthList = pft->dom().elementsByTagName( QStringLiteral( "outlinewidth" ) );
310 for ( int i = 0; i < outlineWidthList.size(); ++i )
311 {
312 //calculate new width
313 QDomElement currentOutlineElem = outlineWidthList.at( i ).toElement();
314 double outlineWidth = currentOutlineElem.text().toDouble();
315 outlineWidth *= widthScaleFactor;
316
317 //replace old text node
318 const QDomNode outlineTextNode = currentOutlineElem.firstChild();
319 const QDomText newOutlineText = pft->dom().createTextNode( QString::number( outlineWidth ) );
320 currentOutlineElem.replaceChild( newOutlineText, outlineTextNode );
321
322 }
323
324 //Change 'pointsize' in QgsSymbol
325 const QDomNodeList pointSizeList = pft->dom().elementsByTagName( QStringLiteral( "pointsize" ) );
326 for ( int i = 0; i < pointSizeList.size(); ++i )
327 {
328 //calculate new size
329 QDomElement currentPointSizeElem = pointSizeList.at( i ).toElement();
330 double pointSize = currentPointSizeElem.text().toDouble();
331 pointSize *= widthScaleFactor;
332
333 //replace old text node
334 const QDomNode pointSizeTextNode = currentPointSizeElem.firstChild();
335 const QDomText newPointSizeText = pft->dom().createTextNode( QString::number( static_cast< int >( pointSize ) ) );
336 currentPointSizeElem.replaceChild( newPointSizeText, pointSizeTextNode );
337 }
338#endif
339 }
340}
341
343{
344 if ( ! pft->dom().isNull() )
345 {
346 const QDomNodeList layerList = pft->dom().elementsByTagName( QStringLiteral( "maplayer" ) );
347 for ( int i = 0; i < layerList.size(); ++i )
348 {
349 const QDomElement layerElem = layerList.at( i ).toElement();
350 const QString typeString = layerElem.attribute( QStringLiteral( "type" ) );
351 if ( typeString != QLatin1String( "vector" ) )
352 {
353 continue;
354 }
355
356 //datasource
357 const QDomNode dataSourceNode = layerElem.namedItem( QStringLiteral( "datasource" ) );
358 if ( dataSourceNode.isNull() )
359 {
360 return;
361 }
362 const QString dataSource = dataSourceNode.toElement().text();
363
364 //provider key
365 const QDomNode providerNode = layerElem.namedItem( QStringLiteral( "provider" ) );
366 if ( providerNode.isNull() )
367 {
368 return;
369 }
370 const QString providerKey = providerNode.toElement().text();
371
372 //create the layer to get the provider for int->fieldName conversion
374 options.loadDefaultStyle = false;
375 QgsVectorLayer *layer = new QgsVectorLayer( dataSource, QString(), providerKey, options );
376 if ( !layer->isValid() )
377 {
378 delete layer;
379 return;
380 }
381
382 QgsVectorDataProvider *provider = layer->dataProvider();
383 if ( !provider )
384 {
385 return;
386 }
387 const QgsFields fields = provider->fields();
388
389 //read classificationfield
390 const QDomNodeList classificationFieldList = layerElem.elementsByTagName( QStringLiteral( "classificationfield" ) );
391 for ( int j = 0; j < classificationFieldList.size(); ++j )
392 {
393 QDomElement classificationFieldElem = classificationFieldList.at( j ).toElement();
394 const int fieldNumber = classificationFieldElem.text().toInt();
395 if ( fieldNumber >= 0 && fieldNumber < fields.count() )
396 {
397 const QDomText fieldName = pft->dom().createTextNode( fields.at( fieldNumber ).name() );
398 const QDomNode nameNode = classificationFieldElem.firstChild();
399 classificationFieldElem.replaceChild( fieldName, nameNode );
400 }
401 }
402
403 }
404 }
405}
406
408{
409 QgsDebugMsg( QStringLiteral( "Entering..." ) );
410 if ( pft->dom().isNull() )
411 return;
412
413 const QDomNode qgis = pft->dom().firstChildElement( QStringLiteral( "qgis" ) );
414 if ( qgis.isNull() )
415 return;
416
417 const QDomElement properties = qgis.firstChildElement( QStringLiteral( "properties" ) );
418 if ( properties.isNull() )
419 return;
420
421 QDomElement digitizing = properties.firstChildElement( QStringLiteral( "Digitizing" ) );
422 if ( digitizing.isNull() )
423 return;
424
425 const QDomElement tolList = digitizing.firstChildElement( QStringLiteral( "LayerSnappingToleranceList" ) );
426 if ( tolList.isNull() )
427 return;
428
429 const QDomElement tolUnitList = digitizing.firstChildElement( QStringLiteral( "LayerSnappingToleranceUnitList" ) );
430 if ( !tolUnitList.isNull() )
431 return;
432
433 QStringList units;
434 for ( int i = 0; i < tolList.childNodes().count(); i++ )
435 units << QStringLiteral( "0" );
436
437 QgsProjectPropertyValue value( units );
438 value.writeXml( QStringLiteral( "LayerSnappingToleranceUnitList" ), digitizing, pft->dom() );
439}
440
442{
443 //Adapt the XML description of the composer legend model to version 1.5
444 if ( pft->dom().isNull() )
445 {
446 return;
447 }
448 //Add layer id to <VectorClassificationItem>
449 const QDomNodeList layerItemList = pft->dom().elementsByTagName( QStringLiteral( "LayerItem" ) );
450 QDomElement currentLayerItemElem;
451 QString currentLayerId;
452
453 for ( int i = 0; i < layerItemList.size(); ++i )
454 {
455 currentLayerItemElem = layerItemList.at( i ).toElement();
456 if ( currentLayerItemElem.isNull() )
457 {
458 continue;
459 }
460 currentLayerId = currentLayerItemElem.attribute( QStringLiteral( "layerId" ) );
461
462 const QDomNodeList vectorClassificationList = currentLayerItemElem.elementsByTagName( QStringLiteral( "VectorClassificationItem" ) );
463 QDomElement currentClassificationElem;
464 for ( int j = 0; j < vectorClassificationList.size(); ++j )
465 {
466 currentClassificationElem = vectorClassificationList.at( j ).toElement();
467 if ( !currentClassificationElem.isNull() )
468 {
469 currentClassificationElem.setAttribute( QStringLiteral( "layerId" ), currentLayerId );
470 }
471 }
472
473 //replace the text items with VectorClassification or RasterClassification items
474 const QDomNodeList textItemList = currentLayerItemElem.elementsByTagName( QStringLiteral( "TextItem" ) );
475 QDomElement currentTextItem;
476
477 for ( int j = 0; j < textItemList.size(); ++j )
478 {
479 currentTextItem = textItemList.at( j ).toElement();
480 if ( currentTextItem.isNull() )
481 {
482 continue;
483 }
484
485 QDomElement classificationElement;
486 if ( !vectorClassificationList.isEmpty() ) //we guess it is a vector layer
487 {
488 classificationElement = pft->dom().createElement( QStringLiteral( "VectorClassificationItem" ) );
489 }
490 else
491 {
492 classificationElement = pft->dom().createElement( QStringLiteral( "RasterClassificationItem" ) );
493 }
494
495 classificationElement.setAttribute( QStringLiteral( "layerId" ), currentLayerId );
496 classificationElement.setAttribute( QStringLiteral( "text" ), currentTextItem.attribute( QStringLiteral( "text" ) ) );
497 currentLayerItemElem.replaceChild( classificationElement, currentTextItem );
498 }
499 }
500}
501
503{
504 if ( pft->dom().isNull() )
505 {
506 return;
507 }
508
509 QgsReadWriteContext context;
510 context.setPathResolver( QgsProject::instance()->pathResolver() );
511
512 const QDomNodeList layerItemList = pft->dom().elementsByTagName( QStringLiteral( "rasterproperties" ) );
513 for ( int i = 0; i < layerItemList.size(); ++i )
514 {
515 QDomElement rasterPropertiesElem = layerItemList.at( i ).toElement();
516 QDomNode layerNode = rasterPropertiesElem.parentNode();
517 const QDomElement dataSourceElem = layerNode.firstChildElement( QStringLiteral( "datasource" ) );
518 const QDomElement layerNameElem = layerNode.firstChildElement( QStringLiteral( "layername" ) );
519 QgsRasterLayer rasterLayer;
520 // TODO: We have to use more data from project file to read the layer it correctly,
521 // OTOH, we should not read it until it was converted
522 rasterLayer.readLayerXml( layerNode.toElement(), context );
523 QgsProjectFileTransform::convertRasterProperties( pft->dom(), layerNode, rasterPropertiesElem, &rasterLayer );
524 }
525
526 //composer: replace mGridAnnotationPosition with mLeftGridAnnotationPosition & co.
527 // and mGridAnnotationDirection with mLeftGridAnnotationDirection & co.
528 const QDomNodeList composerMapList = pft->dom().elementsByTagName( QStringLiteral( "ComposerMap" ) );
529 for ( int i = 0; i < composerMapList.size(); ++i )
530 {
531 const QDomNodeList gridList = composerMapList.at( i ).toElement().elementsByTagName( QStringLiteral( "Grid" ) );
532 for ( int j = 0; j < gridList.size(); ++j )
533 {
534 const QDomNodeList annotationList = gridList.at( j ).toElement().elementsByTagName( QStringLiteral( "Annotation" ) );
535 for ( int k = 0; k < annotationList.size(); ++k )
536 {
537 QDomElement annotationElem = annotationList.at( k ).toElement();
538
539 //position
540 if ( annotationElem.hasAttribute( QStringLiteral( "position" ) ) )
541 {
542 const int pos = annotationElem.attribute( QStringLiteral( "position" ) ).toInt();
543 annotationElem.setAttribute( QStringLiteral( "leftPosition" ), pos );
544 annotationElem.setAttribute( QStringLiteral( "rightPosition" ), pos );
545 annotationElem.setAttribute( QStringLiteral( "topPosition" ), pos );
546 annotationElem.setAttribute( QStringLiteral( "bottomPosition" ), pos );
547 annotationElem.removeAttribute( QStringLiteral( "position" ) );
548 }
549
550 //direction
551 if ( annotationElem.hasAttribute( QStringLiteral( "direction" ) ) )
552 {
553 const int dir = annotationElem.attribute( QStringLiteral( "direction" ) ).toInt();
554 if ( dir == 2 )
555 {
556 annotationElem.setAttribute( QStringLiteral( "leftDirection" ), 0 );
557 annotationElem.setAttribute( QStringLiteral( "rightDirection" ), 0 );
558 annotationElem.setAttribute( QStringLiteral( "topDirection" ), 1 );
559 annotationElem.setAttribute( QStringLiteral( "bottomDirection" ), 1 );
560 }
561 else if ( dir == 3 )
562 {
563 annotationElem.setAttribute( QStringLiteral( "leftDirection" ), 1 );
564 annotationElem.setAttribute( QStringLiteral( "rightDirection" ), 1 );
565 annotationElem.setAttribute( QStringLiteral( "topDirection" ), 0 );
566 annotationElem.setAttribute( QStringLiteral( "bottomDirection" ), 0 );
567 }
568 else
569 {
570 annotationElem.setAttribute( QStringLiteral( "leftDirection" ), dir );
571 annotationElem.setAttribute( QStringLiteral( "rightDirection" ), dir );
572 annotationElem.setAttribute( QStringLiteral( "topDirection" ), dir );
573 annotationElem.setAttribute( QStringLiteral( "bottomDirection" ), dir );
574 }
575 annotationElem.removeAttribute( QStringLiteral( "direction" ) );
576 }
577 }
578 }
579 }
580
581 //Composer: move all items under Composition element
582 const QDomNodeList composerList = pft->dom().elementsByTagName( QStringLiteral( "Composer" ) );
583 for ( int i = 0; i < composerList.size(); ++i )
584 {
585 QDomElement composerElem = composerList.at( i ).toElement();
586
587 //find <QgsComposition element
588 QDomElement compositionElem = composerElem.firstChildElement( QStringLiteral( "Composition" ) );
589 if ( compositionElem.isNull() )
590 {
591 continue;
592 }
593
594 const QDomNodeList composerChildren = composerElem.childNodes();
595
596 if ( composerChildren.size() < 1 )
597 {
598 continue;
599 }
600
601 for ( int j = composerChildren.size() - 1; j >= 0; --j )
602 {
603 const QDomElement childElem = composerChildren.at( j ).toElement();
604 if ( childElem.tagName() == QLatin1String( "Composition" ) )
605 {
606 continue;
607 }
608
609 composerElem.removeChild( childElem );
610 compositionElem.appendChild( childElem );
611
612 }
613 }
614
615 // SimpleFill symbol layer v2: avoid double transparency
616 // replacing alpha value of symbol layer's color with 255 (the
617 // transparency value is already stored as symbol transparency).
618 const QDomNodeList rendererList = pft->dom().elementsByTagName( QStringLiteral( "renderer-v2" ) );
619 for ( int i = 0; i < rendererList.size(); ++i )
620 {
621 const QDomNodeList layerList = rendererList.at( i ).toElement().elementsByTagName( QStringLiteral( "layer" ) );
622 for ( int j = 0; j < layerList.size(); ++j )
623 {
624 const QDomElement layerElem = layerList.at( j ).toElement();
625 if ( layerElem.attribute( QStringLiteral( "class" ) ) == QLatin1String( "SimpleFill" ) )
626 {
627 const QDomNodeList propList = layerElem.elementsByTagName( QStringLiteral( "prop" ) );
628 for ( int k = 0; k < propList.size(); ++k )
629 {
630 QDomElement propElem = propList.at( k ).toElement();
631 if ( propElem.attribute( QStringLiteral( "k" ) ) == QLatin1String( "color" ) || propElem.attribute( QStringLiteral( "k" ) ) == QLatin1String( "color_border" ) )
632 {
633 propElem.setAttribute( QStringLiteral( "v" ), propElem.attribute( QStringLiteral( "v" ) ).section( ',', 0, 2 ) + ",255" );
634 }
635 }
636 }
637 }
638 }
639
640 QgsDebugMsgLevel( pft->dom().toString(), 2 );
641}
642
644{
645 //composer: set placement for all picture items to middle, to mimic <=2.2 behavior
646 const QDomNodeList composerPictureList = pft->dom().elementsByTagName( QStringLiteral( "ComposerPicture" ) );
647 for ( int i = 0; i < composerPictureList.size(); ++i )
648 {
649 QDomElement picture = composerPictureList.at( i ).toElement();
650 picture.setAttribute( QStringLiteral( "anchorPoint" ), QString::number( 4 ) );
651 }
652}
653
655{
656 // transform OTF off to "no projection" for project
657 QDomElement propsElem = pft->dom().firstChildElement( QStringLiteral( "qgis" ) ).toElement().firstChildElement( QStringLiteral( "properties" ) );
658 if ( !propsElem.isNull() )
659 {
660 const QDomNodeList srsNodes = propsElem.elementsByTagName( QStringLiteral( "SpatialRefSys" ) );
661 QDomElement srsElem;
662 QDomElement projElem;
663 if ( srsNodes.count() > 0 )
664 {
665 srsElem = srsNodes.at( 0 ).toElement();
666 const QDomNodeList projNodes = srsElem.elementsByTagName( QStringLiteral( "ProjectionsEnabled" ) );
667 if ( projNodes.count() == 0 )
668 {
669 projElem = pft->dom().createElement( QStringLiteral( "ProjectionsEnabled" ) );
670 projElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "int" ) );
671 const QDomText projText = pft->dom().createTextNode( QStringLiteral( "0" ) );
672 projElem.appendChild( projText );
673 srsElem.appendChild( projElem );
674 }
675 }
676 else
677 {
678 srsElem = pft->dom().createElement( QStringLiteral( "SpatialRefSys" ) );
679 projElem = pft->dom().createElement( QStringLiteral( "ProjectionsEnabled" ) );
680 projElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "int" ) );
681 const QDomText projText = pft->dom().createTextNode( QStringLiteral( "0" ) );
682 projElem.appendChild( projText );
683 srsElem.appendChild( projElem );
684 propsElem.appendChild( srsElem );
685 }
686
687 // transform map canvas CRS to project CRS - this is because project CRS was inconsistently used
688 // prior to 3.0. In >= 3.0 main canvas CRS is forced to match project CRS, so we need to make
689 // sure we can read the project CRS correctly
690 const QDomNodeList canvasNodes = pft->dom().elementsByTagName( QStringLiteral( "mapcanvas" ) );
691 if ( canvasNodes.count() > 0 )
692 {
693 const QDomElement canvasElem = canvasNodes.at( 0 ).toElement();
694 const QDomNodeList canvasSrsNodes = canvasElem.elementsByTagName( QStringLiteral( "spatialrefsys" ) );
695 if ( canvasSrsNodes.count() > 0 )
696 {
697 const QDomElement canvasSrsElem = canvasSrsNodes.at( 0 ).toElement();
698 QString proj;
699 QString authid;
700 QString srsid;
701
702 const QDomNodeList proj4Nodes = canvasSrsElem.elementsByTagName( QStringLiteral( "proj4" ) );
703 if ( proj4Nodes.count() > 0 )
704 {
705 const QDomElement proj4Node = proj4Nodes.at( 0 ).toElement();
706 proj = proj4Node.text();
707 }
708 const QDomNodeList authidNodes = canvasSrsElem.elementsByTagName( QStringLiteral( "authid" ) );
709 if ( authidNodes.count() > 0 )
710 {
711 const QDomElement authidNode = authidNodes.at( 0 ).toElement();
712 authid = authidNode.text();
713 }
714 const QDomNodeList srsidNodes = canvasSrsElem.elementsByTagName( QStringLiteral( "srsid" ) );
715 if ( srsidNodes.count() > 0 )
716 {
717 const QDomElement srsidNode = srsidNodes.at( 0 ).toElement();
718 srsid = srsidNode.text();
719 }
720
721 // clear existing project CRS nodes
722 const QDomNodeList oldProjectProj4Nodes = srsElem.elementsByTagName( QStringLiteral( "ProjectCRSProj4String" ) );
723 for ( int i = oldProjectProj4Nodes.count(); i >= 0; --i )
724 {
725 srsElem.removeChild( oldProjectProj4Nodes.at( i ) );
726 }
727 const QDomNodeList oldProjectCrsNodes = srsElem.elementsByTagName( QStringLiteral( "ProjectCrs" ) );
728 for ( int i = oldProjectCrsNodes.count(); i >= 0; --i )
729 {
730 srsElem.removeChild( oldProjectCrsNodes.at( i ) );
731 }
732 const QDomNodeList oldProjectCrsIdNodes = srsElem.elementsByTagName( QStringLiteral( "ProjectCRSID" ) );
733 for ( int i = oldProjectCrsIdNodes.count(); i >= 0; --i )
734 {
735 srsElem.removeChild( oldProjectCrsIdNodes.at( i ) );
736 }
737 const QDomNodeList projectionsEnabledNodes = srsElem.elementsByTagName( QStringLiteral( "ProjectionsEnabled" ) );
738 for ( int i = projectionsEnabledNodes.count(); i >= 0; --i )
739 {
740 srsElem.removeChild( projectionsEnabledNodes.at( i ) );
741 }
742
743 QDomElement proj4Elem = pft->dom().createElement( QStringLiteral( "ProjectCRSProj4String" ) );
744 proj4Elem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QString" ) );
745 const QDomText proj4Text = pft->dom().createTextNode( proj );
746 proj4Elem.appendChild( proj4Text );
747 QDomElement projectCrsElem = pft->dom().createElement( QStringLiteral( "ProjectCrs" ) );
748 projectCrsElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QString" ) );
749 const QDomText projectCrsText = pft->dom().createTextNode( authid );
750 projectCrsElem.appendChild( projectCrsText );
751 QDomElement projectCrsIdElem = pft->dom().createElement( QStringLiteral( "ProjectCRSID" ) );
752 projectCrsIdElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "int" ) );
753 const QDomText srsidText = pft->dom().createTextNode( srsid );
754 projectCrsIdElem.appendChild( srsidText );
755 QDomElement projectionsEnabledElem = pft->dom().createElement( QStringLiteral( "ProjectionsEnabled" ) );
756 projectionsEnabledElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "int" ) );
757 const QDomText projectionsEnabledText = pft->dom().createTextNode( QStringLiteral( "1" ) );
758 projectionsEnabledElem.appendChild( projectionsEnabledText );
759 srsElem.appendChild( proj4Elem );
760 srsElem.appendChild( projectCrsElem );
761 srsElem.appendChild( projectCrsIdElem );
762 srsElem.appendChild( projectionsEnabledElem );
763
764 const QDomNodeList srsNodes = propsElem.elementsByTagName( QStringLiteral( "SpatialRefSys" ) );
765 for ( int i = srsNodes.count(); i >= 0; --i )
766 {
767 propsElem.removeChild( srsNodes.at( i ) );
768 }
769 propsElem.appendChild( srsElem );
770 }
771 }
772 }
773
774
775 const QDomNodeList mapLayers = pft->dom().elementsByTagName( QStringLiteral( "maplayer" ) );
776
777 for ( int mapLayerIndex = 0; mapLayerIndex < mapLayers.count(); ++mapLayerIndex )
778 {
779 QDomElement layerElem = mapLayers.at( mapLayerIndex ).toElement();
780
781 // The newly added fieldConfiguration element
782 QDomElement fieldConfigurationElement = pft->dom().createElement( QStringLiteral( "fieldConfiguration" ) );
783 layerElem.appendChild( fieldConfigurationElement );
784
785 const QDomNodeList editTypeNodes = layerElem.namedItem( QStringLiteral( "edittypes" ) ).childNodes();
786 QDomElement constraintExpressionsElem = pft->dom().createElement( QStringLiteral( "constraintExpressions" ) );
787 layerElem.appendChild( constraintExpressionsElem );
788
789 for ( int i = 0; i < editTypeNodes.size(); ++i )
790 {
791 const QDomNode editTypeNode = editTypeNodes.at( i );
792 const QDomElement editTypeElement = editTypeNode.toElement();
793
794 QDomElement fieldElement = pft->dom().createElement( QStringLiteral( "field" ) );
795 fieldConfigurationElement.appendChild( fieldElement );
796
797 const QString name = editTypeElement.attribute( QStringLiteral( "name" ) );
798 fieldElement.setAttribute( QStringLiteral( "name" ), name );
799 QDomElement constraintExpressionElem = pft->dom().createElement( QStringLiteral( "constraint" ) );
800 constraintExpressionElem.setAttribute( QStringLiteral( "field" ), name );
801 constraintExpressionsElem.appendChild( constraintExpressionElem );
802
803 QDomElement editWidgetElement = pft->dom().createElement( QStringLiteral( "editWidget" ) );
804 fieldElement.appendChild( editWidgetElement );
805
806 const QString ewv2Type = editTypeElement.attribute( QStringLiteral( "widgetv2type" ) );
807 editWidgetElement.setAttribute( QStringLiteral( "type" ), ewv2Type );
808
809 const QDomElement ewv2CfgElem = editTypeElement.namedItem( QStringLiteral( "widgetv2config" ) ).toElement();
810
811 if ( !ewv2CfgElem.isNull() )
812 {
813 QDomElement editWidgetConfigElement = pft->dom().createElement( QStringLiteral( "config" ) );
814 editWidgetElement.appendChild( editWidgetConfigElement );
815
816 QVariantMap editWidgetConfiguration;
817
818 const QDomNamedNodeMap configAttrs = ewv2CfgElem.attributes();
819 for ( int configIndex = 0; configIndex < configAttrs.count(); ++configIndex )
820 {
821 const QDomAttr configAttr = configAttrs.item( configIndex ).toAttr();
822 if ( configAttr.name() == QLatin1String( "fieldEditable" ) )
823 {
824 editWidgetConfigElement.setAttribute( QStringLiteral( "fieldEditable" ), configAttr.value() );
825 }
826 else if ( configAttr.name() == QLatin1String( "labelOnTop" ) )
827 {
828 editWidgetConfigElement.setAttribute( QStringLiteral( "labelOnTop" ), configAttr.value() );
829 }
830 else if ( configAttr.name() == QLatin1String( "notNull" ) )
831 {
832 editWidgetConfigElement.setAttribute( QStringLiteral( "notNull" ), configAttr.value() );
833 }
834 else if ( configAttr.name() == QLatin1String( "constraint" ) )
835 {
836 constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), configAttr.value() );
837 }
838 else if ( configAttr.name() == QLatin1String( "constraintDescription" ) )
839 {
840 constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), configAttr.value() );
841 }
842 else
843 {
844 editWidgetConfiguration.insert( configAttr.name(), configAttr.value() );
845 }
846 }
847
848 if ( ewv2Type == QLatin1String( "ValueMap" ) )
849 {
850 const QDomNodeList configElements = ewv2CfgElem.childNodes();
851 QVariantMap map;
852 for ( int configIndex = 0; configIndex < configElements.count(); ++configIndex )
853 {
854 const QDomElement configElem = configElements.at( configIndex ).toElement();
855 map.insert( configElem.attribute( QStringLiteral( "key" ) ), configElem.attribute( QStringLiteral( "value" ) ) );
856 }
857 editWidgetConfiguration.insert( QStringLiteral( "map" ), map );
858 }
859 else if ( ewv2Type == QLatin1String( "Photo" ) )
860 {
861 editWidgetElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "ExternalResource" ) );
862
863 editWidgetConfiguration.insert( QStringLiteral( "DocumentViewer" ), 1 );
864 editWidgetConfiguration.insert( QStringLiteral( "DocumentViewerHeight" ), editWidgetConfiguration.value( QStringLiteral( "Height" ) ) );
865 editWidgetConfiguration.insert( QStringLiteral( "DocumentViewerWidth" ), editWidgetConfiguration.value( QStringLiteral( "Width" ) ) );
866 editWidgetConfiguration.insert( QStringLiteral( "RelativeStorage" ), 1 );
867 }
868 else if ( ewv2Type == QLatin1String( "FileName" ) )
869 {
870 editWidgetElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "ExternalResource" ) );
871
872 editWidgetConfiguration.insert( QStringLiteral( "RelativeStorage" ), 1 );
873 }
874 else if ( ewv2Type == QLatin1String( "WebView" ) )
875 {
876 editWidgetElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "ExternalResource" ) );
877
878 editWidgetConfiguration.insert( QStringLiteral( "DocumentViewerHeight" ), editWidgetConfiguration.value( QStringLiteral( "Height" ) ) );
879 editWidgetConfiguration.insert( QStringLiteral( "DocumentViewerWidth" ), editWidgetConfiguration.value( QStringLiteral( "Width" ) ) );
880 editWidgetConfiguration.insert( QStringLiteral( "RelativeStorage" ), 1 );
881 }
882
883 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( editWidgetConfiguration, pft->dom() ) );
884 }
885 }
886 }
887}
888
889void QgsProjectFileTransform::convertRasterProperties( QDomDocument &doc, QDomNode &parentNode,
890 QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer )
891{
892 //no data
893 //TODO: We would need to set no data on all bands, but we don't know number of bands here
894 const QDomNode noDataNode = rasterPropertiesElem.namedItem( QStringLiteral( "mNoDataValue" ) );
895 const QDomElement noDataElement = noDataNode.toElement();
896 if ( !noDataElement.text().isEmpty() )
897 {
898 QgsDebugMsg( "mNoDataValue = " + noDataElement.text() );
899 QDomElement noDataElem = doc.createElement( QStringLiteral( "noData" ) );
900
901 QDomElement noDataRangeList = doc.createElement( QStringLiteral( "noDataRangeList" ) );
902 noDataRangeList.setAttribute( QStringLiteral( "bandNo" ), 1 );
903
904 QDomElement noDataRange = doc.createElement( QStringLiteral( "noDataRange" ) );
905 noDataRange.setAttribute( QStringLiteral( "min" ), noDataElement.text() );
906 noDataRange.setAttribute( QStringLiteral( "max" ), noDataElement.text() );
907 noDataRangeList.appendChild( noDataRange );
908
909 noDataElem.appendChild( noDataRangeList );
910
911 parentNode.appendChild( noDataElem );
912 }
913
914 QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
915 //convert general properties
916
917 //invert color
918 rasterRendererElem.setAttribute( QStringLiteral( "invertColor" ), QStringLiteral( "0" ) );
919 const QDomElement invertColorElem = rasterPropertiesElem.firstChildElement( QStringLiteral( "mInvertColor" ) );
920 if ( !invertColorElem.isNull() )
921 {
922 if ( invertColorElem.text() == QLatin1String( "true" ) )
923 {
924 rasterRendererElem.setAttribute( QStringLiteral( "invertColor" ), QStringLiteral( "1" ) );
925 }
926 }
927
928 //opacity
929 rasterRendererElem.setAttribute( QStringLiteral( "opacity" ), QStringLiteral( "1" ) );
930 const QDomElement transparencyElem = parentNode.firstChildElement( QStringLiteral( "transparencyLevelInt" ) );
931 if ( !transparencyElem.isNull() )
932 {
933 const double transparency = transparencyElem.text().toInt();
934 rasterRendererElem.setAttribute( QStringLiteral( "opacity" ), QString::number( transparency / 255.0 ) );
935 }
936
937 //alphaBand was not saved until now (bug)
938 rasterRendererElem.setAttribute( QStringLiteral( "alphaBand" ), -1 );
939
940 //gray band is used for several renderers
941 const int grayBand = rasterBandNumber( rasterPropertiesElem, QStringLiteral( "mGrayBandName" ), rlayer );
942
943 //convert renderer specific properties
944 QString drawingStyle = rasterPropertiesElem.firstChildElement( QStringLiteral( "mDrawingStyle" ) ).text();
945
946 // While PalettedColor should normally contain only integer values, usually
947 // color palette 0-255, it may happen (Tim, issue #7023) that it contains
948 // colormap classification with double values and text labels
949 // (which should normally only appear in SingleBandPseudoColor drawingStyle)
950 // => we have to check first the values and change drawingStyle if necessary
951 if ( drawingStyle == QLatin1String( "PalettedColor" ) )
952 {
953 const QDomElement customColorRampElem = rasterPropertiesElem.firstChildElement( QStringLiteral( "customColorRamp" ) );
954 const QDomNodeList colorRampEntryList = customColorRampElem.elementsByTagName( QStringLiteral( "colorRampEntry" ) );
955
956 for ( int i = 0; i < colorRampEntryList.size(); ++i )
957 {
958 const QDomElement colorRampEntryElem = colorRampEntryList.at( i ).toElement();
959 const QString strValue = colorRampEntryElem.attribute( QStringLiteral( "value" ) );
960 const double value = strValue.toDouble();
961 if ( value < 0 || value > 10000 || !qgsDoubleNear( value, static_cast< int >( value ) ) )
962 {
963 QgsDebugMsg( QStringLiteral( "forcing SingleBandPseudoColor value = %1" ).arg( value ) );
964 drawingStyle = QStringLiteral( "SingleBandPseudoColor" );
965 break;
966 }
967 }
968 }
969
970 if ( drawingStyle == QLatin1String( "SingleBandGray" ) )
971 {
972 rasterRendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "singlebandgray" ) );
973 rasterRendererElem.setAttribute( QStringLiteral( "grayBand" ), grayBand );
974 transformContrastEnhancement( doc, rasterPropertiesElem, rasterRendererElem );
975 }
976 else if ( drawingStyle == QLatin1String( "SingleBandPseudoColor" ) )
977 {
978 rasterRendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "singlebandpseudocolor" ) );
979 rasterRendererElem.setAttribute( QStringLiteral( "band" ), grayBand );
980 QDomElement newRasterShaderElem = doc.createElement( QStringLiteral( "rastershader" ) );
981 QDomElement newColorRampShaderElem = doc.createElement( QStringLiteral( "colorrampshader" ) );
982 newRasterShaderElem.appendChild( newColorRampShaderElem );
983 rasterRendererElem.appendChild( newRasterShaderElem );
984
985 //switch depending on mColorShadingAlgorithm
986 const QString colorShadingAlgorithm = rasterPropertiesElem.firstChildElement( QStringLiteral( "mColorShadingAlgorithm" ) ).text();
987 if ( colorShadingAlgorithm == QLatin1String( "PseudoColorShader" ) || colorShadingAlgorithm == QLatin1String( "FreakOutShader" ) )
988 {
989 newColorRampShaderElem.setAttribute( QStringLiteral( "colorRampType" ), QStringLiteral( "INTERPOLATED" ) );
990
991 //get minmax from rasterlayer
992 const QgsRasterBandStats rasterBandStats = rlayer->dataProvider()->bandStatistics( grayBand );
993 const double minValue = rasterBandStats.minimumValue;
994 const double maxValue = rasterBandStats.maximumValue;
995 const double breakSize = ( maxValue - minValue ) / 3;
996
997 QStringList colorList;
998 if ( colorShadingAlgorithm == QLatin1String( "FreakOutShader" ) )
999 {
1000 colorList << QStringLiteral( "#ff00ff" ) << QStringLiteral( "#00ffff" ) << QStringLiteral( "#ff0000" ) << QStringLiteral( "#00ff00" );
1001 }
1002 else //pseudocolor
1003 {
1004 colorList << QStringLiteral( "#0000ff" ) << QStringLiteral( "#00ffff" ) << QStringLiteral( "#ffff00" ) << QStringLiteral( "#ff0000" );
1005 }
1006 QStringList::const_iterator colorIt = colorList.constBegin();
1007 double boundValue = minValue;
1008 for ( ; colorIt != colorList.constEnd(); ++colorIt )
1009 {
1010 QDomElement newItemElem = doc.createElement( QStringLiteral( "item" ) );
1011 newItemElem.setAttribute( QStringLiteral( "value" ), QString::number( boundValue ) );
1012 newItemElem.setAttribute( QStringLiteral( "label" ), QString::number( boundValue ) );
1013 newItemElem.setAttribute( QStringLiteral( "color" ), *colorIt );
1014 newColorRampShaderElem.appendChild( newItemElem );
1015 boundValue += breakSize;
1016 }
1017 }
1018 else if ( colorShadingAlgorithm == QLatin1String( "ColorRampShader" ) )
1019 {
1020 const QDomElement customColorRampElem = rasterPropertiesElem.firstChildElement( QStringLiteral( "customColorRamp" ) );
1021 const QString type = customColorRampElem.firstChildElement( QStringLiteral( "colorRampType" ) ).text();
1022 newColorRampShaderElem.setAttribute( QStringLiteral( "colorRampType" ), type );
1023 const QDomNodeList colorNodeList = customColorRampElem.elementsByTagName( QStringLiteral( "colorRampEntry" ) );
1024
1025 QString value, label;
1026 QColor newColor;
1027 int red, green, blue;
1028 QDomElement currentItemElem;
1029 for ( int i = 0; i < colorNodeList.size(); ++i )
1030 {
1031 currentItemElem = colorNodeList.at( i ).toElement();
1032 value = currentItemElem.attribute( QStringLiteral( "value" ) );
1033 label = currentItemElem.attribute( QStringLiteral( "label" ) );
1034 red = currentItemElem.attribute( QStringLiteral( "red" ) ).toInt();
1035 green = currentItemElem.attribute( QStringLiteral( "green" ) ).toInt();
1036 blue = currentItemElem.attribute( QStringLiteral( "blue" ) ).toInt();
1037 newColor = QColor( red, green, blue );
1038 QDomElement newItemElem = doc.createElement( QStringLiteral( "item" ) );
1039 newItemElem.setAttribute( QStringLiteral( "value" ), value );
1040 newItemElem.setAttribute( QStringLiteral( "label" ), label );
1041 newItemElem.setAttribute( QStringLiteral( "color" ), newColor.name() );
1042 newColorRampShaderElem.appendChild( newItemElem );
1043 }
1044 }
1045 }
1046 else if ( drawingStyle == QLatin1String( "PalettedColor" ) )
1047 {
1048 rasterRendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "paletted" ) );
1049 rasterRendererElem.setAttribute( QStringLiteral( "band" ), grayBand );
1050 const QDomElement customColorRampElem = rasterPropertiesElem.firstChildElement( QStringLiteral( "customColorRamp" ) );
1051 const QDomNodeList colorRampEntryList = customColorRampElem.elementsByTagName( QStringLiteral( "colorRampEntry" ) );
1052 QDomElement newColorPaletteElem = doc.createElement( QStringLiteral( "colorPalette" ) );
1053
1054 int red = 0;
1055 int green = 0;
1056 int blue = 0;
1057 int value = 0;
1058 QDomElement colorRampEntryElem;
1059 for ( int i = 0; i < colorRampEntryList.size(); ++i )
1060 {
1061 colorRampEntryElem = colorRampEntryList.at( i ).toElement();
1062 QDomElement newPaletteElem = doc.createElement( QStringLiteral( "paletteEntry" ) );
1063 value = static_cast< int >( colorRampEntryElem.attribute( QStringLiteral( "value" ) ).toDouble() );
1064 newPaletteElem.setAttribute( QStringLiteral( "value" ), value );
1065 red = colorRampEntryElem.attribute( QStringLiteral( "red" ) ).toInt();
1066 green = colorRampEntryElem.attribute( QStringLiteral( "green" ) ).toInt();
1067 blue = colorRampEntryElem.attribute( QStringLiteral( "blue" ) ).toInt();
1068 newPaletteElem.setAttribute( QStringLiteral( "color" ), QColor( red, green, blue ).name() );
1069 const QString label = colorRampEntryElem.attribute( QStringLiteral( "label" ) );
1070 if ( !label.isEmpty() )
1071 {
1072 newPaletteElem.setAttribute( QStringLiteral( "label" ), label );
1073 }
1074 newColorPaletteElem.appendChild( newPaletteElem );
1075 }
1076 rasterRendererElem.appendChild( newColorPaletteElem );
1077 }
1078 else if ( drawingStyle == QLatin1String( "MultiBandColor" ) )
1079 {
1080 rasterRendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "multibandcolor" ) );
1081
1082 //red band, green band, blue band
1083 const int redBand = rasterBandNumber( rasterPropertiesElem, QStringLiteral( "mRedBandName" ), rlayer );
1084 const int greenBand = rasterBandNumber( rasterPropertiesElem, QStringLiteral( "mGreenBandName" ), rlayer );
1085 const int blueBand = rasterBandNumber( rasterPropertiesElem, QStringLiteral( "mBlueBandName" ), rlayer );
1086 rasterRendererElem.setAttribute( QStringLiteral( "redBand" ), redBand );
1087 rasterRendererElem.setAttribute( QStringLiteral( "greenBand" ), greenBand );
1088 rasterRendererElem.setAttribute( QStringLiteral( "blueBand" ), blueBand );
1089
1090 transformContrastEnhancement( doc, rasterPropertiesElem, rasterRendererElem );
1091 }
1092 else
1093 {
1094 return;
1095 }
1096
1097 //replace rasterproperties element with rasterrenderer element
1098 if ( !parentNode.isNull() )
1099 {
1100 parentNode.replaceChild( rasterRendererElem, rasterPropertiesElem );
1101 }
1102}
1103
1105{
1106 return mDom;
1107}
1108
1110{
1111 return mCurrentVersion;
1112}
1113
1114int rasterBandNumber( const QDomElement &rasterPropertiesElem, const QString &bandName, QgsRasterLayer *rlayer )
1115{
1116 if ( !rlayer )
1117 {
1118 return -1;
1119 }
1120
1121 const int band = -1;
1122 const QDomElement rasterBandElem = rasterPropertiesElem.firstChildElement( bandName );
1123 if ( !rasterBandElem.isNull() )
1124 {
1125 const thread_local QRegularExpression re( "(\\d+)" );
1126 const QRegularExpressionMatch match = re.match( rasterBandElem.text() );
1127 if ( match.hasMatch() )
1128 {
1129 return match.captured( 1 ).toInt();
1130 }
1131 }
1132 return band;
1133}
1134
1135void transformContrastEnhancement( QDomDocument &doc, const QDomElement &rasterproperties, QDomElement &rendererElem )
1136{
1137 if ( rasterproperties.isNull() || rendererElem.isNull() )
1138 {
1139 return;
1140 }
1141
1142 double minimumValue = 0;
1143 double maximumValue = 0;
1144 const QDomElement contrastMinMaxElem = rasterproperties.firstChildElement( QStringLiteral( "contrastEnhancementMinMaxValues" ) );
1145 if ( contrastMinMaxElem.isNull() )
1146 {
1147 return;
1148 }
1149
1150 const QDomElement contrastEnhancementAlgorithmElem = rasterproperties.firstChildElement( QStringLiteral( "mContrastEnhancementAlgorithm" ) );
1151 if ( contrastEnhancementAlgorithmElem.isNull() )
1152 {
1153 return;
1154 }
1155
1156 //convert enhancement name to enumeration
1157 int algorithmEnum = 0;
1158 const QString algorithmString = contrastEnhancementAlgorithmElem.text();
1159 if ( algorithmString == QLatin1String( "StretchToMinimumMaximum" ) )
1160 {
1161 algorithmEnum = 1;
1162 }
1163 else if ( algorithmString == QLatin1String( "StretchAndClipToMinimumMaximum" ) )
1164 {
1165 algorithmEnum = 2;
1166 }
1167 else if ( algorithmString == QLatin1String( "ClipToMinimumMaximum" ) )
1168 {
1169 algorithmEnum = 3;
1170 }
1171 else if ( algorithmString == QLatin1String( "UserDefinedEnhancement" ) )
1172 {
1173 algorithmEnum = 4;
1174 }
1175
1176 const QDomNodeList minMaxEntryList = contrastMinMaxElem.elementsByTagName( QStringLiteral( "minMaxEntry" ) );
1177 QStringList enhancementNameList;
1178 if ( minMaxEntryList.size() == 1 )
1179 {
1180 enhancementNameList << QStringLiteral( "contrastEnhancement" );
1181 }
1182 if ( minMaxEntryList.size() == 3 )
1183 {
1184 enhancementNameList << QStringLiteral( "redContrastEnhancement" ) << QStringLiteral( "greenContrastEnhancement" ) << QStringLiteral( "blueContrastEnhancement" );
1185 }
1186 if ( minMaxEntryList.size() > enhancementNameList.size() )
1187 {
1188 return;
1189 }
1190
1191 QDomElement minMaxEntryElem;
1192 for ( int i = 0; i < minMaxEntryList.size(); ++i )
1193 {
1194 minMaxEntryElem = minMaxEntryList.at( i ).toElement();
1195 const QDomElement minElem = minMaxEntryElem.firstChildElement( QStringLiteral( "min" ) );
1196 if ( minElem.isNull() )
1197 {
1198 return;
1199 }
1200 minimumValue = minElem.text().toDouble();
1201
1202 const QDomElement maxElem = minMaxEntryElem.firstChildElement( QStringLiteral( "max" ) );
1203 if ( maxElem.isNull() )
1204 {
1205 return;
1206 }
1207 maximumValue = maxElem.text().toDouble();
1208
1209 QDomElement newContrastEnhancementElem = doc.createElement( enhancementNameList.at( i ) );
1210 QDomElement newMinValElem = doc.createElement( QStringLiteral( "minValue" ) );
1211 const QDomText minText = doc.createTextNode( QString::number( minimumValue ) );
1212 newMinValElem.appendChild( minText );
1213 newContrastEnhancementElem.appendChild( newMinValElem );
1214 QDomElement newMaxValElem = doc.createElement( QStringLiteral( "maxValue" ) );
1215 const QDomText maxText = doc.createTextNode( QString::number( maximumValue ) );
1216 newMaxValElem.appendChild( maxText );
1217 newContrastEnhancementElem.appendChild( newMaxValElem );
1218
1219 QDomElement newAlgorithmElem = doc.createElement( QStringLiteral( "algorithm" ) );
1220 const QDomText newAlgorithmText = doc.createTextNode( QString::number( algorithmEnum ) );
1221 newAlgorithmElem.appendChild( newAlgorithmText );
1222 newContrastEnhancementElem.appendChild( newAlgorithmElem );
1223
1224 rendererElem.appendChild( newContrastEnhancementElem );
1225 }
1226}
Contains information about the context in which a coordinate transform is executed.
QString name
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=QgsMapLayer::ReadFlags())
Sets state from DOM document.
bool isValid
Definition: qgsmaplayer.h:81
Class to convert from older project file versions to newer.
static void convertRasterProperties(QDomDocument &doc, QDomNode &parentNode, QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer)
QgsProjectVersion currentVersion() const
The current project version.
void dump()
Prints the contents via QgsDebugMsg()
QDomDocument & dom()
The current dom document.
bool updateRevision(const QgsProjectVersion &version)
Project property value node, contains a QgsProjectPropertyKey's value.
bool writeXml(const QString &nodeName, QDomElement &element, QDomDocument &document) override
Writes the property hierarchy to a specified DOM element.
A class to describe the version of a project.
int subVersion() const
Returns the sub version number.
int majorVersion() const
Returns the major version number.
int minorVersion() const
Returns the minor version number.
bool isNull() const
Returns true if this is a NULL project version.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
The RasterBandStats struct is a container for statistics about a single raster band.
double minimumValue
The minimum cell value in the raster band.
double maximumValue
The maximum cell value in the raster band.
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
The class is used as a container of context for various read/write operations on other objects.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
This is the base class for vector data providers.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
Represents a vector layer which manages a vector based data sets.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2527
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void transform1800to1900(QgsProjectFileTransform *pft)
void transformContrastEnhancement(QDomDocument &doc, const QDomElement &rasterproperties, QDomElement &rendererElem)
void transform0110to1000(QgsProjectFileTransform *pft)
void transform1100to1200(QgsProjectFileTransform *pft)
void transform0100to0110(QgsProjectFileTransform *pft)
void transform3000(QgsProjectFileTransform *pft)
void transform2200to2300(QgsProjectFileTransform *pft)
void transform1400to1500(QgsProjectFileTransform *pft)
void transformNull(QgsProjectFileTransform *pft)
QgsProjectVersion PFV
void transform091to0100(QgsProjectFileTransform *pft)
std::vector< TransformItem > Transformers
void transform081to090(QgsProjectFileTransform *pft)
int rasterBandNumber(const QDomElement &rasterPropertiesElem, const QString &bandName, QgsRasterLayer *rlayer)
void transformRasterTransparency(QDomDocument &doc, const QDomElement &orig, QDomElement &rendererElem)
Setting options for loading vector layers.
QgsProjectVersion from
QgsProjectVersion to