QGIS API Documentation  master-59fd5e0
src/core/qgsprojectfiletransform.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           qgsprojectfiletransform.cpp  -  description
00003                              -------------------
00004     begin                : Sun 15 dec 2007
00005     copyright            : (C) 2007 by Magnus Homann
00006     email                : magnus at homann.se
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 
00019 #include "qgsprojectfiletransform.h"
00020 #include "qgsprojectversion.h"
00021 #include "qgslogger.h"
00022 #include "qgsrasterlayer.h"
00023 #include "qgsvectordataprovider.h"
00024 #include "qgsvectorlayer.h"
00025 #include <QTextStream>
00026 #include <QDomDocument>
00027 #include <QPrinter> //to find out screen resolution
00028 #include <cstdlib>
00029 #include "qgsproject.h"
00030 #include "qgsprojectproperty.h"
00031 
00032 typedef QgsProjectVersion PFV;
00033 
00034 
00035 QgsProjectFileTransform::transform QgsProjectFileTransform::transformers[] =
00036 {
00037   {PFV( 0, 8, 0 ), PFV( 0, 8, 1 ), &QgsProjectFileTransform::transformNull},
00038   {PFV( 0, 8, 1 ), PFV( 0, 9, 0 ), &QgsProjectFileTransform::transform081to090},
00039   {PFV( 0, 9, 0 ), PFV( 0, 9, 1 ), &QgsProjectFileTransform::transformNull},
00040   {PFV( 0, 9, 1 ), PFV( 0, 10, 0 ), &QgsProjectFileTransform::transform091to0100},
00041   // Following line is a hack that takes us straight from 0.9.2 to 0.11.0
00042   // due to an unknown bug in migrating 0.9.2 files which we didnt pursue (TS & GS)
00043   {PFV( 0, 9, 2 ), PFV( 0, 11, 0 ), &QgsProjectFileTransform::transformNull},
00044   {PFV( 0, 10, 0 ), PFV( 0, 11, 0 ), &QgsProjectFileTransform::transform0100to0110},
00045   {PFV( 0, 11, 0 ), PFV( 1, 0, 0 ), &QgsProjectFileTransform::transform0110to1000},
00046   {PFV( 1, 0, 0 ), PFV( 1, 1, 0 ), &QgsProjectFileTransform::transformNull},
00047   {PFV( 1, 0, 2 ), PFV( 1, 1, 0 ), &QgsProjectFileTransform::transformNull},
00048   {PFV( 1, 1, 0 ), PFV( 1, 2, 0 ), &QgsProjectFileTransform::transform1100to1200},
00049   {PFV( 1, 2, 0 ), PFV( 1, 3, 0 ), &QgsProjectFileTransform::transformNull},
00050   {PFV( 1, 3, 0 ), PFV( 1, 4, 0 ), &QgsProjectFileTransform::transformNull},
00051   {PFV( 1, 4, 0 ), PFV( 1, 5, 0 ), &QgsProjectFileTransform::transform1400to1500},
00052   {PFV( 1, 5, 0 ), PFV( 1, 6, 0 ), &QgsProjectFileTransform::transformNull},
00053   {PFV( 1, 6, 0 ), PFV( 1, 7, 0 ), &QgsProjectFileTransform::transformNull},
00054   {PFV( 1, 7, 0 ), PFV( 1, 8, 0 ), &QgsProjectFileTransform::transformNull},
00055   {PFV( 1, 8, 0 ), PFV( 1, 9, 0 ), &QgsProjectFileTransform::transform1800to1900}
00056 };
00057 
00058 bool QgsProjectFileTransform::updateRevision( QgsProjectVersion newVersion )
00059 {
00060   Q_UNUSED( newVersion );
00061   bool returnValue = false;
00062 
00063   if ( ! mDom.isNull() )
00064   {
00065     for ( std::size_t i = 0; i < sizeof( transformers ) / sizeof( transform ); i++ )
00066     {
00067       if ( transformers[i].from == mCurrentVersion )
00068       {
00069         // Run the transformer, and update the revision in every case
00070         ( this->*( transformers[i].transformFunc ) )();
00071         mCurrentVersion = transformers[i].to;
00072         returnValue = true;
00073       }
00074     }
00075   }
00076   return returnValue;
00077 }
00078 
00079 void QgsProjectFileTransform::dump()
00080 {
00081   QgsDebugMsg( QString( "Current project file version is %1.%2.%3" )
00082                .arg( mCurrentVersion.majorVersion() )
00083                .arg( mCurrentVersion.minorVersion() )
00084                .arg( mCurrentVersion.subVersion() ) );
00085 #ifdef QGISDEBUG
00086   // Using QgsDebugMsg() didn't print the entire mDom...
00087   std::cout << mDom.toString( 2 ).toLatin1().constData(); // OK
00088 #endif
00089 }
00090 
00091 /*
00092  *  Transformers below!
00093  */
00094 
00095 void QgsProjectFileTransform::transform081to090()
00096 {
00097   QgsDebugMsg( "Entering..." );
00098   if ( ! mDom.isNull() )
00099   {
00100     // Start with inserting a mapcanvas element and populate it
00101 
00102     QDomElement mapCanvas; // A null element.
00103 
00104     // there should only be one <qgis>
00105     QDomNode qgis = mDom.firstChildElement( "qgis" );
00106     if ( ! qgis.isNull() )
00107     {
00108       QgsDebugMsg( "Populating new mapcanvas" );
00109 
00110       // Create a mapcanvas
00111       mapCanvas = mDom.createElement( "mapcanvas" );
00112       // Append mapcanvas to parent 'qgis'.
00113       qgis.appendChild( mapCanvas );
00114       // Re-parent units
00115       mapCanvas.appendChild( qgis.namedItem( "units" ) );
00116       // Re-parent extent
00117       mapCanvas.appendChild( qgis.namedItem( "extent" ) );
00118 
00119       // See if we can find if projection is on.
00120 
00121       QDomElement properties = qgis.firstChildElement( "properties" );
00122       QDomElement spatial = properties.firstChildElement( "SpatialRefSys" );
00123       QDomElement hasCrsTransformEnabled = spatial.firstChildElement( "ProjectionsEnabled" );
00124       // Type is 'int', and '1' if on.
00125       // Create an element
00126       QDomElement projection = mDom.createElement( "projections" );
00127       QgsDebugMsg( QString( "Projection flag: " ) + hasCrsTransformEnabled.text() );
00128       // Set flag from ProjectionsEnabled
00129       projection.appendChild( mDom.createTextNode( hasCrsTransformEnabled.text() ) );
00130       // Set new element as child of <mapcanvas>
00131       mapCanvas.appendChild( projection );
00132 
00133     }
00134 
00135 
00136     // Transforming coordinate-transforms
00137     // Create a list of all map layers
00138     QDomNodeList mapLayers = mDom.elementsByTagName( "maplayer" );
00139     bool doneDestination = false;
00140     for ( int i = 0; i < mapLayers.count(); i++ )
00141     {
00142       QDomNode mapLayer = mapLayers.item( i );
00143       // Find the coordinatetransform
00144       QDomNode coordinateTransform = mapLayer.namedItem( "coordinatetransform" );
00145       // Find the sourcesrs
00146       QDomNode sourceCrs = coordinateTransform.namedItem( "sourcesrs" );
00147       // Rename to srs
00148       sourceCrs.toElement().setTagName( "srs" );
00149       // Re-parent to maplayer
00150       mapLayer.appendChild( sourceCrs );
00151       // Re-move coordinatetransform
00152       // Take the destination CRS of the first layer and use for mapcanvas projection
00153       if ( ! doneDestination )
00154       {
00155         // Use destination CRS from the last layer
00156         QDomNode destinationCRS = coordinateTransform.namedItem( "destinationsrs" );
00157         // Re-parent the destination CRS to the mapcanvas
00158         // If mapcanvas wasn't set, nothing will happen.
00159         mapCanvas.appendChild( destinationCRS );
00160         // Only do this once
00161         doneDestination = true;
00162       }
00163       mapLayer.removeChild( coordinateTransform );
00164       //QDomNode id = mapLayer.namedItem("id");
00165       //QgsDebugMsg(QString("Found maplayer ") + id.toElement().text());
00166 
00167     }
00168 
00169     // Set the flag 'visible' to match the status of 'checked'
00170     QDomNodeList legendLayerFiles = mDom.elementsByTagName( "legendlayerfile" );
00171     QgsDebugMsg( QString( "Legend layer file entries: " ) + QString::number( legendLayerFiles.count() ) );
00172     for ( int i = 0; i < mapLayers.count(); i++ )
00173     {
00174       // Get one maplayer element from list
00175       QDomElement mapLayer = mapLayers.item( i ).toElement();
00176       // Find it's id.
00177       QString id = mapLayer.firstChildElement( "id" ).text();
00178       QgsDebugMsg( QString( "Handling layer " + id ) );
00179       // Now, look it up in legend
00180       for ( int j = 0; j < legendLayerFiles.count(); j++ )
00181       {
00182         QDomElement legendLayerFile = legendLayerFiles.item( j ).toElement();
00183         if ( id == legendLayerFile.attribute( "layerid" ) )
00184         {
00185           // Found a the legend layer that matches the maplayer
00186           QgsDebugMsg( "Found matching id" );
00187 
00188           // Set visible flag from maplayer to legendlayer
00189           legendLayerFile.setAttribute( "visible", mapLayer.attribute( "visible" ) );
00190 
00191           // Set overview flag from maplayer to legendlayer
00192           legendLayerFile.setAttribute( "isInOverview", mapLayer.attribute( "showInOverviewFlag" ) );
00193         }
00194       }
00195     }
00196   }
00197   return;
00198 
00199 }
00200 
00201 void QgsProjectFileTransform::transform091to0100()
00202 {
00203   QgsDebugMsg( "entering" );
00204   if ( ! mDom.isNull() )
00205   {
00206     // Insert transforms here!
00207     QDomNodeList rasterPropertyList = mDom.elementsByTagName( "rasterproperties" );
00208     QgsDebugMsg( QString( "Raster properties file entries: " ) + QString::number( rasterPropertyList.count() ) );
00209     for ( int i = 0; i < rasterPropertyList.count(); i++ )
00210     {
00211       // Get one rasterproperty element from list, and rename the sub-properties.
00212       QDomNode rasterProperty = rasterPropertyList.item( i );
00213       // rasterProperty.namedItem("").toElement().setTagName("");
00214 
00215       rasterProperty.namedItem( "stdDevsToPlotDouble" ).toElement().setTagName( "mStandardDeviations" );
00216 
00217       rasterProperty.namedItem( "invertHistogramFlag" ).toElement().setTagName( "mInvertPixelsFlag" );
00218       rasterProperty.namedItem( "showDebugOverLayFlag" ).toElement().setTagName( "mDebugOverLayFlag" );
00219 
00220       rasterProperty.namedItem( "redBandNameQString" ).toElement().setTagName( "mRedBandName" );
00221       rasterProperty.namedItem( "blueBandNameQString" ).toElement().setTagName( "mBlueBandName" );
00222       rasterProperty.namedItem( "greenBandNameQString" ).toElement().setTagName( "mGreenBandName" );
00223       rasterProperty.namedItem( "grayBandNameQString" ).toElement().setTagName( "mGrayBandName" );
00224     }
00225 
00226     // Changing symbol size for hard: symbols
00227     QDomNodeList symbolPropertyList = mDom.elementsByTagName( "symbol" );
00228     for ( int i = 0; i < symbolPropertyList.count(); i++ )
00229     {
00230       // Get the <poinmtsymbol> to check for 'hard:' for each <symbol>
00231       QDomNode symbolProperty = symbolPropertyList.item( i );
00232 
00233       QDomElement pointSymbol = symbolProperty.firstChildElement( "pointsymbol" );
00234       if ( pointSymbol.text().startsWith( "hard:" ) )
00235       {
00236         // Get pointsize and line width
00237         int lineWidth = symbolProperty.firstChildElement( "outlinewidth" ).text().toInt();
00238         int pointSize = symbolProperty.firstChildElement( "pointsize" ).text().toInt();
00239         // Just a precaution, checking for 0
00240         if ( pointSize != 0 )
00241         {
00242           // int r = (s-2*lw)/2-1 --> 2r = (s-2*lw)-2 --> 2r+2 = s-2*lw
00243           // --> 2r+2+2*lw = s
00244           // where '2r' is the old size.
00245           pointSize = pointSize + 2 + 2 * lineWidth;
00246           QgsDebugMsg( QString( "Setting point size to %1" ).arg( pointSize ) );
00247           QDomElement newPointSizeProperty = mDom.createElement( "pointsize" );
00248           QDomText newPointSizeTxt = mDom.createTextNode( QString::number( pointSize ) );
00249           newPointSizeProperty.appendChild( newPointSizeTxt );
00250           symbolProperty.replaceChild( newPointSizeProperty, pointSymbol );
00251         }
00252       }
00253     }
00254 
00255   }
00256   return;
00257 
00258 }
00259 
00260 void QgsProjectFileTransform::transform0100to0110()
00261 {
00262   if ( ! mDom.isNull() )
00263   {
00264     //Change 'outlinewidth' in QgsSymbol
00265     QPrinter myPrinter( QPrinter::ScreenResolution );
00266     int screenDpi = myPrinter.resolution();
00267     double widthScaleFactor = 25.4 / screenDpi;
00268 
00269     QDomNodeList outlineWidthList = mDom.elementsByTagName( "outlinewidth" );
00270     for ( int i = 0; i < outlineWidthList.size(); ++i )
00271     {
00272       //calculate new width
00273       QDomElement currentOutlineElem = outlineWidthList.at( i ).toElement();
00274       double outlineWidth = currentOutlineElem.text().toDouble();
00275       outlineWidth *= widthScaleFactor;
00276 
00277       //replace old text node
00278       QDomNode outlineTextNode = currentOutlineElem.firstChild();
00279       QDomText newOutlineText = mDom.createTextNode( QString::number( outlineWidth ) );
00280       currentOutlineElem.replaceChild( newOutlineText, outlineTextNode );
00281 
00282     }
00283 
00284     //Change 'pointsize' in QgsSymbol
00285     QDomNodeList pointSizeList = mDom.elementsByTagName( "pointsize" );
00286     for ( int i = 0; i < pointSizeList.size(); ++i )
00287     {
00288       //calculate new size
00289       QDomElement currentPointSizeElem = pointSizeList.at( i ).toElement();
00290       double pointSize = currentPointSizeElem.text().toDouble();
00291       pointSize *= widthScaleFactor;
00292 
00293       //replace old text node
00294       QDomNode pointSizeTextNode = currentPointSizeElem.firstChild();
00295       QDomText newPointSizeText = mDom.createTextNode( QString::number(( int )pointSize ) );
00296       currentPointSizeElem.replaceChild( newPointSizeText, pointSizeTextNode );
00297     }
00298   }
00299 }
00300 
00301 void QgsProjectFileTransform::transform0110to1000()
00302 {
00303   if ( ! mDom.isNull() )
00304   {
00305     QDomNodeList layerList = mDom.elementsByTagName( "maplayer" );
00306     for ( int i = 0; i < layerList.size(); ++i )
00307     {
00308       QDomElement layerElem = layerList.at( i ).toElement();
00309       QString typeString = layerElem.attribute( "type" );
00310       if ( typeString != "vector" )
00311       {
00312         continue;
00313       }
00314 
00315       //datasource
00316       QDomNode dataSourceNode = layerElem.namedItem( "datasource" );
00317       if ( dataSourceNode.isNull() )
00318       {
00319         return;
00320       }
00321       QString dataSource = dataSourceNode.toElement().text();
00322 
00323       //provider key
00324       QDomNode providerNode = layerElem.namedItem( "provider" );
00325       if ( providerNode.isNull() )
00326       {
00327         return;
00328       }
00329       QString providerKey = providerNode.toElement().text();
00330 
00331       //create the layer to get the provider for int->fieldName conversion
00332       QgsVectorLayer* theLayer = new QgsVectorLayer( dataSource, "", providerKey, false );
00333       if ( !theLayer->isValid() )
00334       {
00335         delete theLayer;
00336         return;
00337       }
00338 
00339       QgsVectorDataProvider* theProvider = theLayer->dataProvider();
00340       if ( !theProvider )
00341       {
00342         return;
00343       }
00344       QgsFields theFields = theProvider->fields();
00345 
00346       //read classificationfield
00347       QDomNodeList classificationFieldList = layerElem.elementsByTagName( "classificationfield" );
00348       for ( int j = 0; j < classificationFieldList.size(); ++j )
00349       {
00350         QDomElement classificationFieldElem = classificationFieldList.at( j ).toElement();
00351         int fieldNumber = classificationFieldElem.text().toInt();
00352         if ( fieldNumber >= 0 && fieldNumber < theFields.count() )
00353         {
00354           QDomText fieldName = mDom.createTextNode( theFields[fieldNumber].name() );
00355           QDomNode nameNode = classificationFieldElem.firstChild();
00356           classificationFieldElem.replaceChild( fieldName, nameNode );
00357         }
00358       }
00359 
00360     }
00361   }
00362 }
00363 
00364 void QgsProjectFileTransform::transform1100to1200()
00365 {
00366   QgsDebugMsg( "Entering..." );
00367   if ( mDom.isNull() )
00368     return;
00369 
00370   QDomNode qgis = mDom.firstChildElement( "qgis" );
00371   if ( qgis.isNull() )
00372     return;
00373 
00374   QDomElement properties = qgis.firstChildElement( "properties" );
00375   if ( properties.isNull() )
00376     return;
00377 
00378   QDomElement digitizing = properties.firstChildElement( "Digitizing" );
00379   if ( digitizing.isNull() )
00380     return;
00381 
00382   QDomElement tolList = digitizing.firstChildElement( "LayerSnappingToleranceList" );
00383   if ( tolList.isNull() )
00384     return;
00385 
00386   QDomElement tolUnitList = digitizing.firstChildElement( "LayerSnappingToleranceUnitList" );
00387   if ( !tolUnitList.isNull() )
00388     return;
00389 
00390   QStringList units;
00391   for ( int i = 0; i < tolList.childNodes().count(); i++ )
00392     units << "0";
00393 
00394   QgsPropertyValue value( units );
00395   value.writeXML( "LayerSnappingToleranceUnitList", digitizing, mDom );
00396 }
00397 
00398 void QgsProjectFileTransform::transform1400to1500()
00399 {
00400   //Adapt the XML description of the composer legend model to version 1.5
00401   if ( mDom.isNull() )
00402   {
00403     return;
00404   }
00405   //Add layer id to <VectorClassificationItem>
00406   QDomNodeList layerItemList = mDom.elementsByTagName( "LayerItem" );
00407   QDomElement currentLayerItemElem;
00408   QString currentLayerId;
00409 
00410   for ( int i = 0; i < layerItemList.size(); ++i )
00411   {
00412     currentLayerItemElem = layerItemList.at( i ).toElement();
00413     if ( currentLayerItemElem.isNull() )
00414     {
00415       continue;
00416     }
00417     currentLayerId = currentLayerItemElem.attribute( "layerId" );
00418 
00419     QDomNodeList vectorClassificationList = currentLayerItemElem.elementsByTagName( "VectorClassificationItem" );
00420     QDomElement currentClassificationElem;
00421     for ( int j = 0; j < vectorClassificationList.size(); ++j )
00422     {
00423       currentClassificationElem = vectorClassificationList.at( j ).toElement();
00424       if ( !currentClassificationElem.isNull() )
00425       {
00426         currentClassificationElem.setAttribute( "layerId", currentLayerId );
00427       }
00428     }
00429 
00430     //replace the text items with VectorClassification or RasterClassification items
00431     QDomNodeList textItemList = currentLayerItemElem.elementsByTagName( "TextItem" );
00432     QDomElement currentTextItem;
00433 
00434     for ( int j = 0; j < textItemList.size(); ++j )
00435     {
00436       currentTextItem = textItemList.at( j ).toElement();
00437       if ( currentTextItem.isNull() )
00438       {
00439         continue;
00440       }
00441 
00442       QDomElement classificationElement;
00443       if ( vectorClassificationList.size() > 0 ) //we guess it is a vector layer
00444       {
00445         classificationElement = mDom.createElement( "VectorClassificationItem" );
00446       }
00447       else
00448       {
00449         classificationElement = mDom.createElement( "RasterClassificationItem" );
00450       }
00451 
00452       classificationElement.setAttribute( "layerId", currentLayerId );
00453       classificationElement.setAttribute( "text", currentTextItem.attribute( "text" ) );
00454       currentLayerItemElem.replaceChild( classificationElement, currentTextItem );
00455     }
00456   }
00457 }
00458 
00459 void QgsProjectFileTransform::transform1800to1900()
00460 {
00461   if ( mDom.isNull() )
00462   {
00463     return;
00464   }
00465 
00466   QDomNodeList layerItemList = mDom.elementsByTagName( "rasterproperties" );
00467   for ( int i = 0; i < layerItemList.size(); ++i )
00468   {
00469     QDomElement rasterPropertiesElem = layerItemList.at( i ).toElement();
00470     QDomNode layerNode = rasterPropertiesElem.parentNode();
00471     QDomElement dataSourceElem = layerNode.firstChildElement( "datasource" );
00472     QDomElement layerNameElem = layerNode.firstChildElement( "layername" );
00473     QgsRasterLayer rasterLayer;
00474     // TODO: We have to use more data from project file to read the layer it correctly,
00475     // OTOH, we should not read it until it was converted
00476     rasterLayer.readLayerXML( layerNode.toElement() );
00477     convertRasterProperties( mDom, layerNode, rasterPropertiesElem, &rasterLayer );
00478   }
00479 
00480   //composer: replace mGridAnnotationPosition with mLeftGridAnnotationPosition & co.
00481   // and mGridAnnotationDirection with mLeftGridAnnotationDirection & co.
00482   QDomNodeList composerMapList = mDom.elementsByTagName( "ComposerMap" );
00483   for ( int i = 0; i < composerMapList.size(); ++i )
00484   {
00485     QDomNodeList gridList = composerMapList.at( i ).toElement().elementsByTagName( "Grid" );
00486     for ( int j = 0; j < gridList.size(); ++j )
00487     {
00488       QDomNodeList annotationList = gridList.at( j ).toElement().elementsByTagName( "Annotation" );
00489       for ( int k = 0; k < annotationList.size(); ++k )
00490       {
00491         QDomElement annotationElem = annotationList.at( k ).toElement();
00492 
00493         //position
00494         if ( annotationElem.hasAttribute( "position" ) )
00495         {
00496           int pos = annotationElem.attribute( "position" ).toInt();
00497           annotationElem.setAttribute( "leftPosition", pos );
00498           annotationElem.setAttribute( "rightPosition", pos );
00499           annotationElem.setAttribute( "topPosition", pos );
00500           annotationElem.setAttribute( "bottomPosition", pos );
00501           annotationElem.removeAttribute( "position" );
00502         }
00503 
00504         //direction
00505         if ( annotationElem.hasAttribute( "direction" ) )
00506         {
00507           int dir = annotationElem.attribute( "direction" ).toInt();
00508           if ( dir == 2 )
00509           {
00510             annotationElem.setAttribute( "leftDirection", 0 );
00511             annotationElem.setAttribute( "rightDirection", 0 );
00512             annotationElem.setAttribute( "topDirection", 1 );
00513             annotationElem.setAttribute( "bottomDirection", 1 );
00514           }
00515           else if ( dir == 3 )
00516           {
00517             annotationElem.setAttribute( "leftDirection", 1 );
00518             annotationElem.setAttribute( "rightDirection", 1 );
00519             annotationElem.setAttribute( "topDirection", 0 );
00520             annotationElem.setAttribute( "bottomDirection", 0 );
00521           }
00522           else
00523           {
00524             annotationElem.setAttribute( "leftDirection", dir );
00525             annotationElem.setAttribute( "rightDirection", dir );
00526             annotationElem.setAttribute( "topDirection", dir );
00527             annotationElem.setAttribute( "bottomDirection", dir );
00528           }
00529           annotationElem.removeAttribute( "direction" );
00530         }
00531       }
00532     }
00533   }
00534 
00535   //Composer: move all items under Composition element
00536   QDomNodeList composerList = mDom.elementsByTagName( "Composer" );
00537   for ( int i = 0; i < composerList.size(); ++i )
00538   {
00539     QDomElement composerElem = composerList.at( i ).toElement();
00540 
00541     //find <QgsComposition element
00542     QDomElement compositionElem = composerElem.firstChildElement( "Composition" );
00543     if ( compositionElem.isNull() )
00544     {
00545       continue;
00546     }
00547 
00548     QDomNodeList composerChildren = composerElem.childNodes();
00549 
00550     if ( composerChildren.size() < 1 )
00551     {
00552       continue;
00553     }
00554 
00555     for ( int j = composerChildren.size() - 1; j >= 0; --j )
00556     {
00557       QDomElement childElem = composerChildren.at( j ).toElement();
00558       if ( childElem.tagName() == "Composition" )
00559       {
00560         continue;
00561       }
00562 
00563       composerElem.removeChild( childElem );
00564       compositionElem.appendChild( childElem );
00565 
00566     }
00567   }
00568 
00569   // SimpleFill symbol layer v2: avoid double transparency
00570   // replacing alpha value of symbol layer's color with 255 (the
00571   // transparency value is already stored as symbol transparency).
00572   QDomNodeList rendererList = mDom.elementsByTagName( "renderer-v2" );
00573   for ( int i = 0; i < rendererList.size(); ++i )
00574   {
00575     QDomNodeList layerList = rendererList.at( i ).toElement().elementsByTagName( "layer" );
00576     for ( int j = 0; j < layerList.size(); ++j )
00577     {
00578       QDomElement layerElem = layerList.at( j ).toElement();
00579       if ( layerElem.attribute( "class" ) == "SimpleFill" )
00580       {
00581         QDomNodeList propList = layerElem.elementsByTagName( "prop" );
00582         for ( int k = 0; k < propList.size(); ++k )
00583         {
00584           QDomElement propElem = propList.at( k ).toElement();
00585           if ( propElem.attribute( "k" ) == "color" || propElem.attribute( "k" ) == "color_border" )
00586           {
00587             propElem.setAttribute( "v", propElem.attribute( "v" ).section( ",", 0, 2 ) + ",255" );
00588           }
00589         }
00590       }
00591     }
00592   }
00593 
00594   QgsDebugMsg( mDom.toString() );
00595 }
00596 
00597 void QgsProjectFileTransform::convertRasterProperties( QDomDocument& doc, QDomNode& parentNode,
00598     QDomElement& rasterPropertiesElem, QgsRasterLayer* rlayer )
00599 {
00600   //no data
00601   //TODO: We would need to set no data on all bands, but we don't know number of bands here
00602   QDomNode noDataNode = rasterPropertiesElem.namedItem( "mNoDataValue" );
00603   QDomElement noDataElement = noDataNode.toElement();
00604   if ( !noDataElement.text().isEmpty() )
00605   {
00606     QgsDebugMsg( "mNoDataValue = " + noDataElement.text() );
00607     QDomElement noDataElem = doc.createElement( "noData" );
00608 
00609     QDomElement noDataRangeList = doc.createElement( "noDataRangeList" );
00610     noDataRangeList.setAttribute( "bandNo", 1 );
00611 
00612     QDomElement noDataRange =  doc.createElement( "noDataRange" );
00613     noDataRange.setAttribute( "min", noDataElement.text() );
00614     noDataRange.setAttribute( "max", noDataElement.text() );
00615     noDataRangeList.appendChild( noDataRange );
00616 
00617     noDataElem.appendChild( noDataRangeList );
00618 
00619     parentNode.appendChild( noDataElem );
00620   }
00621 
00622   QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
00623   //convert general properties
00624 
00625   //invert color
00626   rasterRendererElem.setAttribute( "invertColor", "0" );
00627   QDomElement  invertColorElem = rasterPropertiesElem.firstChildElement( "mInvertColor" );
00628   if ( !invertColorElem.isNull() )
00629   {
00630     if ( invertColorElem.text() == "true" )
00631     {
00632       rasterRendererElem.setAttribute( "invertColor", "1" );
00633     }
00634   }
00635 
00636   //opacity
00637   rasterRendererElem.setAttribute( "opacity", "1" );
00638   QDomElement transparencyElem = parentNode.firstChildElement( "transparencyLevelInt" );
00639   if ( !transparencyElem.isNull() )
00640   {
00641     double transparency = transparencyElem.text().toInt();
00642     rasterRendererElem.setAttribute( "opacity", QString::number( transparency / 255.0 ) );
00643   }
00644 
00645   //alphaBand was not saved until now (bug)
00646   rasterRendererElem.setAttribute( "alphaBand", -1 );
00647 
00648   //gray band is used for several renderers
00649   int grayBand = rasterBandNumber( rasterPropertiesElem, "mGrayBandName", rlayer );
00650 
00651   //convert renderer specific properties
00652   QString drawingStyle = rasterPropertiesElem.firstChildElement( "mDrawingStyle" ).text();
00653 
00654   // While PalettedColor should normaly contain only integer values, usually
00655   // color palette 0-255, it may happen (Tim, issue #7023) that it contains
00656   // colormap classification with double values and text labels
00657   // (which should normaly only appear in SingleBandPseudoColor drawingStyle)
00658   // => we have to check first the values and change drawingStyle if necessary
00659   if ( drawingStyle == "PalettedColor" )
00660   {
00661     QDomElement customColorRampElem = rasterPropertiesElem.firstChildElement( "customColorRamp" );
00662     QDomNodeList colorRampEntryList = customColorRampElem.elementsByTagName( "colorRampEntry" );
00663 
00664     for ( int i = 0; i < colorRampEntryList.size(); ++i )
00665     {
00666       QDomElement colorRampEntryElem = colorRampEntryList.at( i ).toElement();
00667       QString strValue = colorRampEntryElem.attribute( "value" );
00668       double value = strValue.toDouble();
00669       if ( value < 0 || value > 10000 || value != ( int )value )
00670       {
00671         QgsDebugMsg( QString( "forcing SingleBandPseudoColor value = %1" ).arg( value ) );
00672         drawingStyle = "SingleBandPseudoColor";
00673         break;
00674       }
00675     }
00676   }
00677 
00678   if ( drawingStyle == "SingleBandGray" )
00679   {
00680     rasterRendererElem.setAttribute( "type", "singlebandgray" );
00681     rasterRendererElem.setAttribute( "grayBand", grayBand );
00682     transformContrastEnhancement( doc, rasterPropertiesElem, rasterRendererElem );
00683   }
00684   else if ( drawingStyle == "SingleBandPseudoColor" )
00685   {
00686     rasterRendererElem.setAttribute( "type", "singlebandpseudocolor" );
00687     rasterRendererElem.setAttribute( "band", grayBand );
00688     QDomElement newRasterShaderElem = doc.createElement( "rastershader" );
00689     QDomElement newColorRampShaderElem = doc.createElement( "colorrampshader" );
00690     newRasterShaderElem.appendChild( newColorRampShaderElem );
00691     rasterRendererElem.appendChild( newRasterShaderElem );
00692 
00693     //switch depending on mColorShadingAlgorithm
00694     QString colorShadingAlgorithm = rasterPropertiesElem.firstChildElement( "mColorShadingAlgorithm" ).text();
00695     if ( colorShadingAlgorithm == "PseudoColorShader" || colorShadingAlgorithm == "FreakOutShader" )
00696     {
00697       newColorRampShaderElem.setAttribute( "colorRampType", "INTERPOLATED" );
00698 
00699       //get minmax from rasterlayer
00700       QgsRasterBandStats rasterBandStats = rlayer->dataProvider()->bandStatistics( grayBand );
00701       double minValue = rasterBandStats.minimumValue;
00702       double maxValue = rasterBandStats.maximumValue;
00703       double breakSize = ( maxValue - minValue ) / 3;
00704 
00705       QStringList colorList;
00706       if ( colorShadingAlgorithm == "FreakOutShader" )
00707       {
00708         colorList << "#ff00ff" << "#00ffff" << "#ff0000" << "#00ff00";
00709       }
00710       else //pseudocolor
00711       {
00712         colorList << "#0000ff" << "#00ffff" << "#ffff00" << "#ff0000";
00713       }
00714       QStringList::const_iterator colorIt = colorList.constBegin();
00715       double boundValue = minValue;
00716       for ( ; colorIt != colorList.constEnd(); ++colorIt )
00717       {
00718         QDomElement newItemElem = doc.createElement( "item" );
00719         newItemElem.setAttribute( "value", QString::number( boundValue ) );
00720         newItemElem.setAttribute( "label", QString::number( boundValue ) );
00721         newItemElem.setAttribute( "color", *colorIt );
00722         newColorRampShaderElem.appendChild( newItemElem );
00723         boundValue += breakSize;
00724       }
00725     }
00726     else if ( colorShadingAlgorithm == "ColorRampShader" )
00727     {
00728       QDomElement customColorRampElem = rasterPropertiesElem.firstChildElement( "customColorRamp" );
00729       QString type = customColorRampElem.firstChildElement( "colorRampType" ).text();
00730       newColorRampShaderElem.setAttribute( "colorRampType", type );
00731       QDomNodeList colorNodeList = customColorRampElem.elementsByTagName( "colorRampEntry" );
00732 
00733       QString value, label;
00734       QColor newColor;
00735       int red, green, blue;
00736       QDomElement currentItemElem;
00737       for ( int i = 0; i < colorNodeList.size(); ++i )
00738       {
00739         currentItemElem = colorNodeList.at( i ).toElement();
00740         value = currentItemElem.attribute( "value" );
00741         label = currentItemElem.attribute( "label" );
00742         red = currentItemElem.attribute( "red" ).toInt();
00743         green = currentItemElem.attribute( "green" ).toInt();
00744         blue = currentItemElem.attribute( "blue" ).toInt();
00745         newColor = QColor( red, green, blue );
00746         QDomElement newItemElem = doc.createElement( "item" );
00747         newItemElem.setAttribute( "value", value );
00748         newItemElem.setAttribute( "label", label );
00749         newItemElem.setAttribute( "color", newColor.name() );
00750         newColorRampShaderElem.appendChild( newItemElem );
00751       }
00752     }
00753   }
00754   else if ( drawingStyle == "PalettedColor" )
00755   {
00756     rasterRendererElem.setAttribute( "type", "paletted" );
00757     rasterRendererElem.setAttribute( "band", grayBand );
00758     QDomElement customColorRampElem = rasterPropertiesElem.firstChildElement( "customColorRamp" );
00759     QDomNodeList colorRampEntryList = customColorRampElem.elementsByTagName( "colorRampEntry" );
00760     QDomElement newColorPaletteElem = doc.createElement( "colorPalette" );
00761 
00762     int red = 0;
00763     int green = 0;
00764     int blue = 0;
00765     int value = 0;
00766     QDomElement colorRampEntryElem;
00767     for ( int i = 0; i < colorRampEntryList.size(); ++i )
00768     {
00769       colorRampEntryElem = colorRampEntryList.at( i ).toElement();
00770       QDomElement newPaletteElem = doc.createElement( "paletteEntry" );
00771       value = ( int )( colorRampEntryElem.attribute( "value" ).toDouble() );
00772       newPaletteElem.setAttribute( "value", value );
00773       red = colorRampEntryElem.attribute( "red" ).toInt();
00774       green = colorRampEntryElem.attribute( "green" ).toInt();
00775       blue = colorRampEntryElem.attribute( "blue" ).toInt();
00776       newPaletteElem.setAttribute( "color", QColor( red, green, blue ).name() );
00777       newColorPaletteElem.appendChild( newPaletteElem );
00778     }
00779     rasterRendererElem.appendChild( newColorPaletteElem );
00780   }
00781   else if ( drawingStyle == "MultiBandColor" )
00782   {
00783     rasterRendererElem.setAttribute( "type", "multibandcolor" );
00784 
00785     //red band, green band, blue band
00786     int redBand = rasterBandNumber( rasterPropertiesElem, "mRedBandName", rlayer );
00787     int greenBand = rasterBandNumber( rasterPropertiesElem, "mGreenBandName", rlayer );
00788     int blueBand = rasterBandNumber( rasterPropertiesElem, "mBlueBandName", rlayer );
00789     rasterRendererElem.setAttribute( "redBand", redBand );
00790     rasterRendererElem.setAttribute( "greenBand", greenBand );
00791     rasterRendererElem.setAttribute( "blueBand", blueBand );
00792 
00793     transformContrastEnhancement( doc, rasterPropertiesElem, rasterRendererElem );
00794   }
00795   else
00796   {
00797     return;
00798   }
00799 
00800   //replace rasterproperties element with rasterrenderer element
00801   if ( !parentNode.isNull() )
00802   {
00803     parentNode.replaceChild( rasterRendererElem, rasterPropertiesElem );
00804   }
00805 }
00806 
00807 int QgsProjectFileTransform::rasterBandNumber( const QDomElement& rasterPropertiesElem, const QString bandName,
00808     QgsRasterLayer* rlayer )
00809 {
00810   if ( !rlayer )
00811   {
00812     return -1;
00813   }
00814 
00815   int band = -1;
00816   QDomElement rasterBandElem = rasterPropertiesElem.firstChildElement( bandName );
00817   if ( !rasterBandElem.isNull() )
00818   {
00819     for ( int i = 1; i <= rlayer->bandCount(); i++ )
00820     {
00821       if ( rlayer->bandName( i ) == rasterBandElem.text() )
00822       {
00823         band = i;
00824         break;
00825       }
00826     }
00827   }
00828   return band;
00829 }
00830 
00831 void QgsProjectFileTransform::transformContrastEnhancement( QDomDocument& doc, const QDomElement& rasterproperties, QDomElement& rendererElem )
00832 {
00833   if ( rasterproperties.isNull() || rendererElem.isNull() )
00834   {
00835     return;
00836   }
00837 
00838   double minimumValue = 0;
00839   double maximumValue = 0;
00840   QDomElement contrastMinMaxElem = rasterproperties.firstChildElement( "contrastEnhancementMinMaxValues" );
00841   if ( contrastMinMaxElem.isNull() )
00842   {
00843     return;
00844   }
00845 
00846   QDomElement contrastEnhancementAlgorithmElem = rasterproperties.firstChildElement( "mContrastEnhancementAlgorithm" );
00847   if ( contrastEnhancementAlgorithmElem.isNull() )
00848   {
00849     return;
00850   }
00851 
00852   //convert enhancement name to enumeration
00853   int algorithmEnum = 0;
00854   QString algorithmString = contrastEnhancementAlgorithmElem.text();
00855   if ( algorithmString == "StretchToMinimumMaximum" )
00856   {
00857     algorithmEnum = 1;
00858   }
00859   else if ( algorithmString == "StretchAndClipToMinimumMaximum" )
00860   {
00861     algorithmEnum = 2;
00862   }
00863   else if ( algorithmString == "ClipToMinimumMaximum" )
00864   {
00865     algorithmEnum = 3;
00866   }
00867   else if ( algorithmString == "UserDefinedEnhancement" )
00868   {
00869     algorithmEnum = 4;
00870   }
00871 
00872   QDomNodeList minMaxEntryList = contrastMinMaxElem.elementsByTagName( "minMaxEntry" );
00873   QStringList enhancementNameList;
00874   if ( minMaxEntryList.size() == 1 )
00875   {
00876     enhancementNameList << "contrastEnhancement";
00877   }
00878   if ( minMaxEntryList.size() ==  3 )
00879   {
00880     enhancementNameList << "redContrastEnhancement" << "greenContrastEnhancement" << "blueContrastEnhancement";
00881   }
00882   if ( minMaxEntryList.size() > enhancementNameList.size() )
00883   {
00884     return;
00885   }
00886 
00887   QDomElement minMaxEntryElem;
00888   for ( int i = 0; i < minMaxEntryList.size(); ++i )
00889   {
00890     minMaxEntryElem = minMaxEntryList.at( i ).toElement();
00891     QDomElement minElem = minMaxEntryElem.firstChildElement( "min" );
00892     if ( minElem.isNull() )
00893     {
00894       return;
00895     }
00896     minimumValue = minElem.text().toDouble();
00897 
00898     QDomElement maxElem = minMaxEntryElem.firstChildElement( "max" );
00899     if ( maxElem.isNull() )
00900     {
00901       return;
00902     }
00903     maximumValue = maxElem.text().toDouble();
00904 
00905     QDomElement newContrastEnhancementElem = doc.createElement( enhancementNameList.at( i ) );
00906     QDomElement newMinValElem = doc.createElement( "minValue" );
00907     QDomText minText = doc.createTextNode( QString::number( minimumValue ) );
00908     newMinValElem.appendChild( minText );
00909     newContrastEnhancementElem.appendChild( newMinValElem );
00910     QDomElement newMaxValElem = doc.createElement( "maxValue" );
00911     QDomText maxText = doc.createTextNode( QString::number( maximumValue ) );
00912     newMaxValElem.appendChild( maxText );
00913     newContrastEnhancementElem.appendChild( newMaxValElem );
00914 
00915     QDomElement newAlgorithmElem = doc.createElement( "algorithm" );
00916     QDomText newAlgorithmText = doc.createTextNode( QString::number( algorithmEnum ) );
00917     newAlgorithmElem.appendChild( newAlgorithmText );
00918     newContrastEnhancementElem.appendChild( newAlgorithmElem );
00919 
00920     rendererElem.appendChild( newContrastEnhancementElem );
00921   }
00922 }
00923 
00924 void QgsProjectFileTransform::transformRasterTransparency( QDomDocument& doc, const QDomElement& orig, QDomElement& rendererElem )
00925 {
00926   //soon...
00927   Q_UNUSED( doc );
00928   Q_UNUSED( orig );
00929   Q_UNUSED( rendererElem );
00930 }
00931 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines