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