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