QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsrasterlayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterlayer.cpp - description
3  -------------------
4 begin : Sat Jun 22 2002
5 copyright : (C) 2003 by Tim Sutton, Steve Halasz and Gary E.Sherman
6 email : tim at linfiniti.com
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 #include "qgsapplication.h"
18 #include "qgscolorrampshader.h"
20 #include "qgscoordinatetransform.h"
21 #include "qgsdatasourceuri.h"
22 #include "qgslogger.h"
23 #include "qgsmaplayerlegend.h"
24 #include "qgsmaplayerregistry.h"
25 #include "qgsmaptopixel.h"
26 #include "qgsmessagelog.h"
30 #include "qgsproviderregistry.h"
31 #include "qgspseudocolorshader.h"
32 #include "qgsrasterdrawer.h"
33 #include "qgsrasteriterator.h"
34 #include "qgsrasterlayer.h"
35 #include "qgsrasterlayerrenderer.h"
36 #include "qgsrasterprojector.h"
37 #include "qgsrasterrange.h"
39 #include "qgsrectangle.h"
40 #include "qgsrendercontext.h"
44 
45 #include <cmath>
46 #include <cstdio>
47 #include <limits>
48 #include <typeinfo>
49 
50 #include <QApplication>
51 #include <QCursor>
52 #include <QDomElement>
53 #include <QDomNode>
54 #include <QFile>
55 #include <QFileInfo>
56 #include <QFont>
57 #include <QFontMetrics>
58 #include <QFrame>
59 #include <QImage>
60 #include <QLabel>
61 #include <QLibrary>
62 #include <QList>
63 #include <QMatrix>
64 #include <QMessageBox>
65 #include <QPainter>
66 #include <QPixmap>
67 #include <QRegExp>
68 #include <QSettings>
69 #include <QSlider>
70 #include <QTime>
71 
72 // typedefs for provider plugin functions of interest
73 typedef bool isvalidrasterfilename_t( QString const & theFileNameQString, QString & retErrMsg );
74 
75 #define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer")
76 
77 const double QgsRasterLayer::CUMULATIVE_CUT_LOWER = 0.02;
78 const double QgsRasterLayer::CUMULATIVE_CUT_UPPER = 0.98;
79 const double QgsRasterLayer::SAMPLE_SIZE = 250000;
80 
82  : QgsMapLayer( RasterLayer )
83  , QSTRING_NOT_SET( "Not Set" )
84  , TRSTRING_NOT_SET( tr( "Not Set" ) )
85  , mDataProvider( 0 )
86 {
87  init();
88  mValid = false;
89 }
90 
92  QString const & path,
93  QString const & baseName,
94  bool loadDefaultStyleFlag )
95  : QgsMapLayer( RasterLayer, baseName, path )
96  , QSTRING_NOT_SET( "Not Set" )
97  , TRSTRING_NOT_SET( tr( "Not Set" ) )
98  , mDataProvider( 0 )
99 {
100  QgsDebugMsg( "Entered" );
101 
102  // TODO, call constructor with provider key
103  init();
104  setDataProvider( "gdal" );
105  if ( !mValid ) return;
106 
107  bool defaultLoadedFlag = false;
108  if ( mValid && loadDefaultStyleFlag )
109  {
110  loadDefaultStyle( defaultLoadedFlag );
111  }
112  if ( !defaultLoadedFlag )
113  {
115  }
116  return;
117 } // QgsRasterLayer ctor
118 
123 QgsRasterLayer::QgsRasterLayer( const QString & uri,
124  const QString & baseName,
125  const QString & providerKey,
126  bool loadDefaultStyleFlag )
127  : QgsMapLayer( RasterLayer, baseName, uri )
128  // Constant that signals property not used.
129  , QSTRING_NOT_SET( "Not Set" )
130  , TRSTRING_NOT_SET( tr( "Not Set" ) )
131  , mDataProvider( 0 )
132  , mProviderKey( providerKey )
133 {
134  QgsDebugMsg( "Entered" );
135  init();
136  setDataProvider( providerKey );
137  if ( !mValid ) return;
138 
139  // load default style
140  bool defaultLoadedFlag = false;
141  if ( mValid && loadDefaultStyleFlag )
142  {
143  loadDefaultStyle( defaultLoadedFlag );
144  }
145  if ( !defaultLoadedFlag )
146  {
148  }
149 
150  // TODO: Connect signals from the dataprovider to the qgisapp
151 
152  emit statusChanged( tr( "QgsRasterLayer created" ) );
153 } // QgsRasterLayer ctor
154 
156 {
157  mValid = false;
158  // Note: provider and other interfaces are owned and deleted by pipe
159 }
160 
162 //
163 // Static Methods and members
164 //
166 
170 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString, QString & retErrMsg )
171 {
172  isvalidrasterfilename_t *pValid = ( isvalidrasterfilename_t * ) cast_to_fptr( QgsProviderRegistry::instance()->function( "gdal", "isValidRasterFileName" ) );
173  if ( ! pValid )
174  {
175  QgsDebugMsg( "Could not resolve isValidRasterFileName in gdal provider library" );
176  return false;
177  }
178 
179  bool myIsValid = pValid( theFileNameQString, retErrMsg );
180  return myIsValid;
181 }
182 
183 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString )
184 {
185  QString retErrMsg;
186  return isValidRasterFileName( theFileNameQString, retErrMsg );
187 }
188 
189 QDateTime QgsRasterLayer::lastModified( QString const & name )
190 {
191  QgsDebugMsg( "name=" + name );
192  QDateTime t;
193 
194  QFileInfo fi( name );
195 
196  // Is it file?
197  if ( !fi.exists() )
198  return t;
199 
200  t = fi.lastModified();
201 
202  QgsDebugMsg( "last modified = " + t.toString() );
203 
204  return t;
205 }
206 
207 // typedef for the QgsDataProvider class factory
208 typedef QgsDataProvider * classFactoryFunction_t( const QString * );
209 
211 //
212 // Non Static Public methods
213 //
215 
217 {
218  if ( !mDataProvider ) return 0;
219  return mDataProvider->bandCount();
220 }
221 
222 const QString QgsRasterLayer::bandName( int theBandNo )
223 {
224  return dataProvider()->generateBandName( theBandNo );
225 }
226 
227 void QgsRasterLayer::setRendererForDrawingStyle( const QgsRaster::DrawingStyle & theDrawingStyle )
228 {
229  setRenderer( QgsRasterRendererRegistry::instance()->defaultRendererForDrawingStyle( theDrawingStyle, mDataProvider ) );
230 }
231 
236 {
237  return mDataProvider;
238 }
239 
244 {
245  return mDataProvider;
246 }
247 
249 {
250  if ( mDataProvider )
251  {
252  mDataProvider->reloadData();
253  }
254 }
255 
257 {
258  return new QgsRasterLayerRenderer( this, rendererContext );
259 }
260 
261 bool QgsRasterLayer::draw( QgsRenderContext& rendererContext )
262 {
263  QgsDebugMsg( "entered. (renderContext)" );
264 
265  QgsDebugMsg( "checking timestamp." );
266 
267  // Check timestamp
268  if ( !update() )
269  {
270  return false;
271  }
272 
273  QgsRasterLayerRenderer renderer( this, rendererContext );
274  return renderer.render();
275 }
276 
277 void QgsRasterLayer::draw( QPainter * theQPainter,
278  QgsRasterViewPort * theRasterViewPort,
279  const QgsMapToPixel* theQgsMapToPixel )
280 {
281  QgsDebugMsg( " 3 arguments" );
282  QTime time;
283  time.start();
284  //
285  //
286  // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
287  // so that we can maximise performance of the rendering process. So now we check which drawing
288  // procedure to use :
289  //
290 
291  QgsRasterProjector *projector = mPipe.projector();
292 
293  // TODO add a method to interface to get provider and get provider
294  // params in QgsRasterProjector
295  if ( projector )
296  {
297  projector->setCRS( theRasterViewPort->mSrcCRS, theRasterViewPort->mDestCRS, theRasterViewPort->mSrcDatumTransform, theRasterViewPort->mDestDatumTransform );
298  }
299 
300  // Drawer to pipe?
301  QgsRasterIterator iterator( mPipe.last() );
302  QgsRasterDrawer drawer( &iterator );
303  drawer.draw( theQPainter, theRasterViewPort, theQgsMapToPixel );
304 
305  QgsDebugMsg( QString( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ) );
306 } //end of draw method
307 
309 {
310  QList< QPair< QString, QColor > > symbolList;
312  if ( renderer )
313  {
314  renderer->legendSymbologyItems( symbolList );
315  }
316  return symbolList;
317 }
318 
320 {
321  QString myMetadata;
322  myMetadata += "<p class=\"glossy\">" + tr( "Driver" ) + "</p>\n";
323  myMetadata += "<p>";
324  myMetadata += mDataProvider->description();
325  myMetadata += "</p>\n";
326 
327  // Insert provider-specific (e.g. WMS-specific) metadata
328  // crashing
329  myMetadata += mDataProvider->metadata();
330 
331  myMetadata += "<p class=\"glossy\">";
332  myMetadata += tr( "No Data Value" );
333  myMetadata += "</p>\n";
334  myMetadata += "<p>";
335  // TODO: all bands
336  if ( mDataProvider->srcHasNoDataValue( 1 ) )
337  {
338  myMetadata += QString::number( mDataProvider->srcNoDataValue( 1 ) );
339  }
340  else
341  {
342  myMetadata += "*" + tr( "NoDataValue not set" ) + "*";
343  }
344  myMetadata += "</p>\n";
345 
346  myMetadata += "</p>\n";
347  myMetadata += "<p class=\"glossy\">";
348  myMetadata += tr( "Data Type" );
349  myMetadata += "</p>\n";
350  myMetadata += "<p>";
351  //just use the first band
352  switch ( mDataProvider->srcDataType( 1 ) )
353  {
354  case QGis::Byte:
355  myMetadata += tr( "Byte - Eight bit unsigned integer" );
356  break;
357  case QGis::UInt16:
358  myMetadata += tr( "UInt16 - Sixteen bit unsigned integer " );
359  break;
360  case QGis::Int16:
361  myMetadata += tr( "Int16 - Sixteen bit signed integer " );
362  break;
363  case QGis::UInt32:
364  myMetadata += tr( "UInt32 - Thirty two bit unsigned integer " );
365  break;
366  case QGis::Int32:
367  myMetadata += tr( "Int32 - Thirty two bit signed integer " );
368  break;
369  case QGis::Float32:
370  myMetadata += tr( "Float32 - Thirty two bit floating point " );
371  break;
372  case QGis::Float64:
373  myMetadata += tr( "Float64 - Sixty four bit floating point " );
374  break;
375  case QGis::CInt16:
376  myMetadata += tr( "CInt16 - Complex Int16 " );
377  break;
378  case QGis::CInt32:
379  myMetadata += tr( "CInt32 - Complex Int32 " );
380  break;
381  case QGis::CFloat32:
382  myMetadata += tr( "CFloat32 - Complex Float32 " );
383  break;
384  case QGis::CFloat64:
385  myMetadata += tr( "CFloat64 - Complex Float64 " );
386  break;
387  default:
388  myMetadata += tr( "Could not determine raster data type." );
389  }
390  myMetadata += "</p>\n";
391 
392  myMetadata += "<p class=\"glossy\">";
393  myMetadata += tr( "Pyramid overviews" );
394  myMetadata += "</p>\n";
395  myMetadata += "<p>";
396 
397  myMetadata += "<p class=\"glossy\">";
398  myMetadata += tr( "Layer Spatial Reference System" );
399  myMetadata += "</p>\n";
400  myMetadata += "<p>";
401  myMetadata += crs().toProj4();
402  myMetadata += "</p>\n";
403 
404  myMetadata += "<p class=\"glossy\">";
405  myMetadata += tr( "Layer Extent (layer original source projection)" );
406  myMetadata += "</p>\n";
407  myMetadata += "<p>";
408  myMetadata += mDataProvider->extent().toString();
409  myMetadata += "</p>\n";
410 
411  // output coordinate system
412  // TODO: this is not related to layer, to be removed? [MD]
413 #if 0
414  myMetadata += "<tr><td class=\"glossy\">";
415  myMetadata += tr( "Project Spatial Reference System" );
416  myMetadata += "</p>\n";
417  myMetadata += "<p>";
418  myMetadata += mCoordinateTransform->destCRS().toProj4();
419  myMetadata += "</p>\n";
420 #endif
421 
422  //
423  // Add the stats for each band to the output table
424  //
425  int myBandCountInt = bandCount();
426  for ( int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
427  {
428  QgsDebugMsg( "Raster properties : checking if band " + QString::number( myIteratorInt ) + " has stats? " );
429  //band name
430  myMetadata += "<p class=\"glossy\">\n";
431  myMetadata += tr( "Band" );
432  myMetadata += "</p>\n";
433  myMetadata += "<p>";
434  myMetadata += bandName( myIteratorInt );
435  myMetadata += "</p>\n";
436  //band number
437  myMetadata += "<p>";
438  myMetadata += tr( "Band No" );
439  myMetadata += "</p>\n";
440  myMetadata += "<p>\n";
441  myMetadata += QString::number( myIteratorInt );
442  myMetadata += "</p>\n";
443 
444  //check if full stats for this layer have already been collected
445  if ( !dataProvider()->hasStatistics( myIteratorInt ) ) //not collected
446  {
447  QgsDebugMsg( ".....no" );
448 
449  myMetadata += "<p>";
450  myMetadata += tr( "No Stats" );
451  myMetadata += "</p>\n";
452  myMetadata += "<p>\n";
453  myMetadata += tr( "No stats collected yet" );
454  myMetadata += "</p>\n";
455  }
456  else // collected - show full detail
457  {
458  QgsDebugMsg( ".....yes" );
459 
460  QgsRasterBandStats myRasterBandStats = dataProvider()->bandStatistics( myIteratorInt );
461  //Min Val
462  myMetadata += "<p>";
463  myMetadata += tr( "Min Val" );
464  myMetadata += "</p>\n";
465  myMetadata += "<p>\n";
466  myMetadata += QString::number( myRasterBandStats.minimumValue, 'f', 10 );
467  myMetadata += "</p>\n";
468 
469  // Max Val
470  myMetadata += "<p>";
471  myMetadata += tr( "Max Val" );
472  myMetadata += "</p>\n";
473  myMetadata += "<p>\n";
474  myMetadata += QString::number( myRasterBandStats.maximumValue, 'f', 10 );
475  myMetadata += "</p>\n";
476 
477  // Range
478  myMetadata += "<p>";
479  myMetadata += tr( "Range" );
480  myMetadata += "</p>\n";
481  myMetadata += "<p>\n";
482  myMetadata += QString::number( myRasterBandStats.range, 'f', 10 );
483  myMetadata += "</p>\n";
484 
485  // Mean
486  myMetadata += "<p>";
487  myMetadata += tr( "Mean" );
488  myMetadata += "</p>\n";
489  myMetadata += "<p>\n";
490  myMetadata += QString::number( myRasterBandStats.mean, 'f', 10 );
491  myMetadata += "</p>\n";
492 
493  //sum of squares
494  myMetadata += "<p>";
495  myMetadata += tr( "Sum of squares" );
496  myMetadata += "</p>\n";
497  myMetadata += "<p>\n";
498  myMetadata += QString::number( myRasterBandStats.sumOfSquares, 'f', 10 );
499  myMetadata += "</p>\n";
500 
501  //standard deviation
502  myMetadata += "<p>";
503  myMetadata += tr( "Standard Deviation" );
504  myMetadata += "</p>\n";
505  myMetadata += "<p>\n";
506  myMetadata += QString::number( myRasterBandStats.stdDev, 'f', 10 );
507  myMetadata += "</p>\n";
508 
509  //sum of all cells
510  myMetadata += "<p>";
511  myMetadata += tr( "Sum of all cells" );
512  myMetadata += "</p>\n";
513  myMetadata += "<p>\n";
514  myMetadata += QString::number( myRasterBandStats.sum, 'f', 10 );
515  myMetadata += "</p>\n";
516 
517  //number of cells
518  myMetadata += "<p>";
519  myMetadata += tr( "Cell Count" );
520  myMetadata += "</p>\n";
521  myMetadata += "<p>\n";
522  myMetadata += QString::number( myRasterBandStats.elementCount );
523  myMetadata += "</p>\n";
524  }
525  }
526 
527  QgsDebugMsg( myMetadata );
528  return myMetadata;
529 }
530 
535 QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber )
536 {
537  //TODO: This function should take dimensions
538  QgsDebugMsg( "entered." );
539 
540  // Only do this for the GDAL provider?
541  // Maybe WMS can do this differently using QImage::numColors and QImage::color()
542  if ( mDataProvider->colorInterpretation( theBandNumber ) == QgsRaster::PaletteIndex )
543  {
544  QgsDebugMsg( "....found paletted image" );
545  QgsColorRampShader myShader;
546  QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( theBandNumber );
547  if ( myColorRampItemList.size() > 0 )
548  {
549  QgsDebugMsg( "....got color ramp item list" );
550  myShader.setColorRampItemList( myColorRampItemList );
552  // Draw image
553  int mySize = 100;
554  QPixmap myPalettePixmap( mySize, mySize );
555  QPainter myQPainter( &myPalettePixmap );
556 
557  QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
558  myQImage.fill( 0 );
559  myPalettePixmap.fill();
560 
561  double myStep = (( double )myColorRampItemList.size() - 1 ) / ( double )( mySize * mySize );
562  double myValue = 0.0;
563  for ( int myRow = 0; myRow < mySize; myRow++ )
564  {
565  QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow );
566  for ( int myCol = 0; myCol < mySize; myCol++ )
567  {
568  myValue = myStep * ( double )( myCol + myRow * mySize );
569  int c1, c2, c3, c4;
570  myShader.shade( myValue, &c1, &c2, &c3, &c4 );
571  myLineBuffer[ myCol ] = qRgba( c1, c2, c3, c4 );
572  }
573  }
574 
575  myQPainter.drawImage( 0, 0, myQImage );
576  return myPalettePixmap;
577  }
578  QPixmap myNullPixmap;
579  return myNullPixmap;
580  }
581  else
582  {
583  //invalid layer was requested
584  QPixmap myNullPixmap;
585  return myNullPixmap;
586  }
587 }
588 
590 {
591  return mProviderKey;
592 }
593 
598 {
599 // We return one raster pixel per map unit pixel
600 // One raster pixel can have several raster units...
601 
602 // We can only use one of the mGeoTransform[], so go with the
603 // horisontal one.
604 
605  if ( mDataProvider->capabilities() & QgsRasterDataProvider::Size && mDataProvider->xSize() > 0 )
606  {
607  return mDataProvider->extent().width() / mDataProvider->xSize();
608  }
609  return 1;
610 }
611 
613 {
614  if ( mDataProvider->capabilities() & QgsRasterDataProvider::Size && mDataProvider->xSize() > 0 )
615  {
616  return mDataProvider->extent().height() / mDataProvider->ySize();
617  }
618  return 1;
619 }
620 
621 void QgsRasterLayer::init()
622 {
623  mRasterType = QgsRasterLayer::GrayOrUndefined;
624 
626 
627  setRendererForDrawingStyle( QgsRaster::UndefinedDrawingStyle );
628 
629  //Initialize the last view port structure, should really be a class
630  mLastViewPort.mWidth = 0;
631  mLastViewPort.mHeight = 0;
632 }
633 
634 void QgsRasterLayer::setDataProvider( QString const & provider )
635 {
636  QgsDebugMsg( "Entered" );
637  mValid = false; // assume the layer is invalid until we determine otherwise
638 
639  mPipe.remove( mDataProvider ); // deletes if exists
640  mDataProvider = 0;
641 
642  // XXX should I check for and possibly delete any pre-existing providers?
643  // XXX How often will that scenario occur?
644 
645  mProviderKey = provider;
646  // set the layer name (uppercase first character)
647  if ( ! mLayerName.isEmpty() ) // XXX shouldn't this happen in parent?
648  {
650  }
651 
652  //mBandCount = 0;
653 
654  mDataProvider = ( QgsRasterDataProvider* )QgsProviderRegistry::instance()->provider( mProviderKey, mDataSource );
655  if ( !mDataProvider )
656  {
657  //QgsMessageLog::logMessage( tr( "Cannot instantiate the data provider" ), tr( "Raster" ) );
658  appendError( ERR( tr( "Cannot instantiate the '%1' data provider" ).arg( mProviderKey ) ) );
659  return;
660  }
661  QgsDebugMsg( "Data provider created" );
662 
663  // Set data provider into pipe even if not valid so that it is deleted with pipe (with layer)
664  mPipe.set( mDataProvider );
665  if ( !mDataProvider->isValid() )
666  {
667  setError( mDataProvider->error() );
668  appendError( ERR( tr( "Provider is not valid (provider: %1, URI: %2" ).arg( mProviderKey ).arg( mDataSource ) ) );
669  return;
670  }
671 
672  if ( provider == "gdal" )
673  {
674  // make sure that the /vsigzip or /vsizip is added to uri, if applicable
675  mDataSource = mDataProvider->dataSourceUri();
676  }
677 
678  // get the extent
679  QgsRectangle mbr = mDataProvider->extent();
680 
681  // show the extent
682  QString s = mbr.toString();
683  QgsDebugMsg( "Extent of layer: " + s );
684  // store the extent
685  setExtent( mbr );
686 
687  // upper case the first letter of the layer name
688  QgsDebugMsg( "mLayerName: " + name() );
689 
690  // set up the raster drawing style
691  // Do not set any 'sensible' style here, the style is set later
692 
693  // Setup source CRS
694  setCrs( QgsCoordinateReferenceSystem( mDataProvider->crs() ) );
695 
696  QString mySourceWkt = crs().toWkt();
697 
698  QgsDebugMsg( "using wkt:\n" + mySourceWkt );
699 
700  //defaults - Needs to be set after the Contrast list has been build
701  //Try to read the default contrast enhancement from the config file
702 
703  QSettings myQSettings;
704 
705  //decide what type of layer this is...
706  //TODO Change this to look at the color interp and palette interp to decide which type of layer it is
707  QgsDebugMsg( "bandCount = " + QString::number( mDataProvider->bandCount() ) );
708  QgsDebugMsg( "dataType = " + QString::number( mDataProvider->dataType( 1 ) ) );
709  if (( mDataProvider->bandCount() > 1 ) )
710  {
711  mRasterType = Multiband;
712  }
713  else if ( mDataProvider->dataType( 1 ) == QGis::ARGB32
714  || mDataProvider->dataType( 1 ) == QGis::ARGB32_Premultiplied )
715  {
716  mRasterType = ColorLayer;
717  }
718  else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex )
719  {
720  mRasterType = Palette;
721  }
722  else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette )
723  {
724  mRasterType = Palette;
725  }
726  else
727  {
728  mRasterType = GrayOrUndefined;
729  }
730 
731  QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) );
732  if ( mRasterType == ColorLayer )
733  {
734  QgsDebugMsg( "Setting drawing style to SingleBandColorDataStyle " + QString::number( QgsRaster::SingleBandColorDataStyle ) );
735  setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
736  }
737  else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex )
738  {
739  setRendererForDrawingStyle( QgsRaster::PalettedColor ); //sensible default
740  }
741  else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette )
742  {
743  setRendererForDrawingStyle( QgsRaster::SingleBandPseudoColor );
744  // Load color table
745  QList<QgsColorRampShader::ColorRampItem> colorTable = mDataProvider->colorTable( 1 );
747  if ( r )
748  {
749  // TODO: this should go somewhere else
750  QgsRasterShader* shader = new QgsRasterShader();
751  QgsColorRampShader* colorRampShader = new QgsColorRampShader();
753  colorRampShader->setColorRampItemList( colorTable );
754  shader->setRasterShaderFunction( colorRampShader );
755  r->setShader( shader );
756  }
757  }
758  else if ( mRasterType == Multiband )
759  {
760  setRendererForDrawingStyle( QgsRaster::MultiBandColor ); //sensible default
761  }
762  else //GrayOrUndefined
763  {
764  setRendererForDrawingStyle( QgsRaster::SingleBandGray ); //sensible default
765  }
766 
767  // Auto set alpha band
768  for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
769  {
770  if ( mDataProvider->colorInterpretation( bandNo ) == QgsRaster::AlphaBand )
771  {
772  if ( mPipe.renderer() )
773  {
774  mPipe.renderer()->setAlphaBand( bandNo );
775  }
776  break;
777  }
778  }
779 
780  // brightness filter
782  mPipe.set( brightnessFilter );
783 
784  // hue/saturation filter
786  mPipe.set( hueSaturationFilter );
787 
788  //resampler (must be after renderer)
790  mPipe.set( resampleFilter );
791 
792  // projector (may be anywhere in pipe)
793  QgsRasterProjector * projector = new QgsRasterProjector;
794  mPipe.set( projector );
795 
796  // Set default identify format - use the richest format available
797  int capabilities = mDataProvider->capabilities();
799  if ( capabilities & QgsRasterInterface::IdentifyHtml )
800  {
801  // HTML is usually richest
802  identifyFormat = QgsRaster::IdentifyFormatHtml;
803  }
804  else if ( capabilities & QgsRasterInterface::IdentifyFeature )
805  {
806  identifyFormat = QgsRaster::IdentifyFormatFeature;
807  }
808  else if ( capabilities & QgsRasterInterface::IdentifyText )
809  {
810  identifyFormat = QgsRaster::IdentifyFormatText;
811  }
812  else if ( capabilities & QgsRasterInterface::IdentifyValue )
813  {
814  identifyFormat = QgsRaster::IdentifyFormatValue;
815  }
816  setCustomProperty( "identify/format", QgsRasterDataProvider::identifyFormatName( identifyFormat ) );
817 
818  // Store timestamp
819  // TODO move to provider
820  mLastModified = lastModified( mDataSource );
821 
822  // Connect provider signals
823  connect(
824  mDataProvider, SIGNAL( progress( int, double, QString ) ),
825  this, SLOT( onProgress( int, double, QString ) )
826  );
827 
828  // Do a passthrough for the status bar text
829  connect(
830  mDataProvider, SIGNAL( statusChanged( QString ) ),
831  this, SIGNAL( statusChanged( QString ) )
832  );
833 
834  //mark the layer as valid
835  mValid = true;
836 
837  QgsDebugMsg( "exiting." );
838 } // QgsRasterLayer::setDataProvider
839 
840 void QgsRasterLayer::closeDataProvider()
841 {
842  mValid = false;
843  mPipe.remove( mDataProvider );
844  mDataProvider = 0;
845 }
846 
847 void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, QgsRaster::ContrastEnhancementLimits theLimits, QgsRectangle theExtent, int theSampleSize, bool theGenerateLookupTableFlag )
848 {
849  QgsDebugMsg( QString( "theAlgorithm = %1 theLimits = %2 theExtent.isEmpty() = %3" ).arg( theAlgorithm ).arg( theLimits ).arg( theExtent.isEmpty() ) );
850  if ( !mPipe.renderer() || !mDataProvider )
851  {
852  return;
853  }
854 
855  QList<int> myBands;
856  QList<QgsContrastEnhancement*> myEnhancements;
857  QgsSingleBandGrayRenderer* myGrayRenderer = 0;
858  QgsMultiBandColorRenderer* myMultiBandRenderer = 0;
859  QString rendererType = mPipe.renderer()->type();
860  if ( rendererType == "singlebandgray" )
861  {
862  myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( mPipe.renderer() );
863  if ( !myGrayRenderer ) return;
864  myBands << myGrayRenderer->grayBand();
865  }
866  else if ( rendererType == "multibandcolor" )
867  {
868  myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( mPipe.renderer() );
869  if ( !myMultiBandRenderer ) return;
870  myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand();
871  }
872 
873  foreach ( int myBand, myBands )
874  {
875  if ( myBand != -1 )
876  {
877  QGis::DataType myType = ( QGis::DataType )mDataProvider->dataType( myBand );
878  QgsContrastEnhancement* myEnhancement = new QgsContrastEnhancement(( QGis::DataType )myType );
879  myEnhancement->setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag );
880 
881  double myMin = std::numeric_limits<double>::quiet_NaN();
882  double myMax = std::numeric_limits<double>::quiet_NaN();
883 
884  if ( theLimits == QgsRaster::ContrastEnhancementMinMax )
885  {
886  QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, theExtent, theSampleSize );
887  myMin = myRasterBandStats.minimumValue;
888  myMax = myRasterBandStats.maximumValue;
889  }
890  else if ( theLimits == QgsRaster::ContrastEnhancementStdDev )
891  {
892  double myStdDev = 1; // make optional?
893  QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( myBand, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, theExtent, theSampleSize );
894  myMin = myRasterBandStats.mean - ( myStdDev * myRasterBandStats.stdDev );
895  myMax = myRasterBandStats.mean + ( myStdDev * myRasterBandStats.stdDev );
896  }
897  else if ( theLimits == QgsRaster::ContrastEnhancementCumulativeCut )
898  {
899  QSettings mySettings;
900  double myLower = mySettings.value( "/Raster/cumulativeCutLower", QString::number( CUMULATIVE_CUT_LOWER ) ).toDouble();
901  double myUpper = mySettings.value( "/Raster/cumulativeCutUpper", QString::number( CUMULATIVE_CUT_UPPER ) ).toDouble();
902  QgsDebugMsg( QString( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ) );
903  mDataProvider->cumulativeCut( myBand, myLower, myUpper, myMin, myMax, theExtent, theSampleSize );
904  }
905 
906  QgsDebugMsg( QString( "myBand = %1 myMin = %2 myMax = %3" ).arg( myBand ).arg( myMin ).arg( myMax ) );
907  myEnhancement->setMinimumValue( myMin );
908  myEnhancement->setMaximumValue( myMax );
909  myEnhancements.append( myEnhancement );
910  }
911  else
912  {
913  myEnhancements.append( 0 );
914  }
915  }
916 
917  if ( rendererType == "singlebandgray" )
918  {
919  if ( myEnhancements.value( 0 ) ) myGrayRenderer->setContrastEnhancement( myEnhancements.value( 0 ) );
920  }
921  else if ( rendererType == "multibandcolor" )
922  {
923  if ( myEnhancements.value( 0 ) ) myMultiBandRenderer->setRedContrastEnhancement( myEnhancements.value( 0 ) );
924  if ( myEnhancements.value( 1 ) ) myMultiBandRenderer->setGreenContrastEnhancement( myEnhancements.value( 1 ) );
925  if ( myEnhancements.value( 2 ) ) myMultiBandRenderer->setBlueContrastEnhancement( myEnhancements.value( 2 ) );
926  }
927 
928  emit repaintRequested();
929 }
930 
932 {
933  QgsDebugMsg( "Entered" );
934 
935  QSettings mySettings;
936 
937  QString myKey;
938  QString myDefault;
939 
940  // TODO: we should not test renderer class here, move it somehow to renderers
941  if ( dynamic_cast<QgsSingleBandGrayRenderer*>( renderer() ) )
942  {
943  myKey = "singleBand";
944  myDefault = "StretchToMinimumMaximum";
945  }
946  else if ( dynamic_cast<QgsMultiBandColorRenderer*>( renderer() ) )
947  {
948  if ( QgsRasterBlock::typeSize( dataProvider()->srcDataType( 1 ) ) == 1 )
949  {
950  myKey = "multiBandSingleByte";
951  myDefault = "NoEnhancement";
952  }
953  else
954  {
955  myKey = "multiBandMultiByte";
956  myDefault = "StretchToMinimumMaximum";
957  }
958  }
959 
960  if ( myKey.isEmpty() )
961  {
962  QgsDebugMsg( "No default contrast enhancement for this drawing style" );
963  }
964  QgsDebugMsg( "myKey = " + myKey );
965 
966  QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + myKey, myDefault ).toString();
967  QgsDebugMsg( "myAlgorithmString = " + myAlgorithmString );
968 
970 
971  if ( myAlgorithm == QgsContrastEnhancement::NoEnhancement )
972  {
973  return;
974  }
975 
976  QString myLimitsString = mySettings.value( "/Raster/defaultContrastEnhancementLimits", "CumulativeCut" ).toString();
978 
979  setContrastEnhancement( myAlgorithm, myLimits );
980 }
981 
987 void QgsRasterLayer::setDrawingStyle( QString const & theDrawingStyleQString )
988 {
989  QgsDebugMsg( "DrawingStyle = " + theDrawingStyleQString );
990  QgsRaster::DrawingStyle drawingStyle;
991  if ( theDrawingStyleQString == "SingleBandGray" )//no need to tr() this its not shown in ui
992  {
993  drawingStyle = QgsRaster::SingleBandGray;
994  }
995  else if ( theDrawingStyleQString == "SingleBandPseudoColor" )//no need to tr() this its not shown in ui
996  {
997  drawingStyle = QgsRaster::SingleBandPseudoColor;
998  }
999  else if ( theDrawingStyleQString == "PalettedColor" )//no need to tr() this its not shown in ui
1000  {
1001  drawingStyle = QgsRaster::PalettedColor;
1002  }
1003  else if ( theDrawingStyleQString == "PalettedSingleBandGray" )//no need to tr() this its not shown in ui
1004  {
1005  drawingStyle = QgsRaster::PalettedSingleBandGray;
1006  }
1007  else if ( theDrawingStyleQString == "PalettedSingleBandPseudoColor" )//no need to tr() this its not shown in ui
1008  {
1010  }
1011  else if ( theDrawingStyleQString == "PalettedMultiBandColor" )//no need to tr() this its not shown in ui
1012  {
1013  drawingStyle = QgsRaster::PalettedMultiBandColor;
1014  }
1015  else if ( theDrawingStyleQString == "MultiBandSingleBandGray" )//no need to tr() this its not shown in ui
1016  {
1017  drawingStyle = QgsRaster::MultiBandSingleBandGray;
1018  }
1019  else if ( theDrawingStyleQString == "MultiBandSingleBandPseudoColor" )//no need to tr() this its not shown in ui
1020  {
1022  }
1023  else if ( theDrawingStyleQString == "MultiBandColor" )//no need to tr() this its not shown in ui
1024  {
1025  drawingStyle = QgsRaster::MultiBandColor;
1026  }
1027  else if ( theDrawingStyleQString == "SingleBandColorDataStyle" )//no need to tr() this its not shown in ui
1028  {
1029  QgsDebugMsg( "Setting drawingStyle to SingleBandColorDataStyle " + QString::number( QgsRaster::SingleBandColorDataStyle ) );
1030  drawingStyle = QgsRaster::SingleBandColorDataStyle;
1031  QgsDebugMsg( "Setted drawingStyle to " + QString::number( drawingStyle ) );
1032  }
1033  else
1034  {
1035  drawingStyle = QgsRaster::UndefinedDrawingStyle;
1036  }
1037  setRendererForDrawingStyle( drawingStyle );
1038 }
1039 
1040 void QgsRasterLayer::setLayerOrder( QStringList const & layers )
1041 {
1042  QgsDebugMsg( "entered." );
1043 
1044  if ( mDataProvider )
1045  {
1046  QgsDebugMsg( "About to mDataProvider->setLayerOrder(layers)." );
1047  mDataProvider->setLayerOrder( layers );
1048  }
1049 
1050 }
1051 
1052 void QgsRasterLayer::setSubLayerVisibility( QString name, bool vis )
1053 {
1054 
1055  if ( mDataProvider )
1056  {
1057  QgsDebugMsg( "About to mDataProvider->setSubLayerVisibility(name, vis)." );
1058  mDataProvider->setSubLayerVisibility( name, vis );
1059  }
1060 
1061 }
1062 
1064 {
1065  QgsDebugMsg( "Entered" );
1066  if ( !theRenderer ) { return; }
1067  mPipe.set( theRenderer );
1068  emit rendererChanged();
1069 }
1070 
1071 void QgsRasterLayer::showProgress( int theValue )
1072 {
1073  emit progressUpdate( theValue );
1074 }
1075 
1076 
1077 void QgsRasterLayer::showStatusMessage( QString const & theMessage )
1078 {
1079  // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
1080 
1081  // Pass-through
1082  // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc.
1083  emit statusChanged( theMessage );
1084 }
1085 
1086 QStringList QgsRasterLayer::subLayers() const
1087 {
1088  return mDataProvider->subLayers();
1089 }
1090 
1091 QPixmap QgsRasterLayer::previewAsPixmap( QSize size, QColor bgColor )
1092 {
1093  QPixmap myQPixmap( size );
1094 
1095  myQPixmap.fill( bgColor ); //defaults to white, set to transparent for rendering on a map
1096 
1097  QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
1098 
1099  double myMapUnitsPerPixel;
1100  double myX = 0.0;
1101  double myY = 0.0;
1102  QgsRectangle myExtent = mDataProvider->extent();
1103  if ( myExtent.width() / myExtent.height() >= ( double )myQPixmap.width() / myQPixmap.height() )
1104  {
1105  myMapUnitsPerPixel = myExtent.width() / myQPixmap.width();
1106  myY = ( myQPixmap.height() - myExtent.height() / myMapUnitsPerPixel ) / 2;
1107  }
1108  else
1109  {
1110  myMapUnitsPerPixel = myExtent.height() / myQPixmap.height();
1111  myX = ( myQPixmap.width() - myExtent.width() / myMapUnitsPerPixel ) / 2;
1112  }
1113 
1114  double myPixelWidth = myExtent.width() / myMapUnitsPerPixel;
1115  double myPixelHeight = myExtent.height() / myMapUnitsPerPixel;
1116 
1117  myRasterViewPort->mTopLeftPoint = QgsPoint( myX, myY );
1118  myRasterViewPort->mBottomRightPoint = QgsPoint( myPixelWidth, myPixelHeight );
1119  myRasterViewPort->mWidth = myQPixmap.width();
1120  myRasterViewPort->mHeight = myQPixmap.height();
1121 
1122  myRasterViewPort->mDrawnExtent = myExtent;
1123  myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
1124  myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
1125  myRasterViewPort->mSrcDatumTransform = -1;
1126  myRasterViewPort->mDestDatumTransform = -1;
1127 
1128  QgsMapToPixel *myMapToPixel = new QgsMapToPixel( myMapUnitsPerPixel );
1129 
1130  QPainter * myQPainter = new QPainter( &myQPixmap );
1131  draw( myQPainter, myRasterViewPort, myMapToPixel );
1132  delete myRasterViewPort;
1133  delete myMapToPixel;
1134  myQPainter->end();
1135  delete myQPainter;
1136 
1137  return myQPixmap;
1138 }
1139 
1140 // this function should be used when rendering with the MTR engine introduced in 2.3, as QPixmap is not thread safe (see bug #9626)
1141 // note: previewAsImage and previewAsPixmap should use a common low-level fct QgsRasterLayer::previewOnPaintDevice( QSize size, QColor bgColor, QPaintDevice &device )
1142 QImage QgsRasterLayer::previewAsImage( QSize size, QColor bgColor, QImage::Format format )
1143 {
1144  QImage myQImage( size, format );
1145 
1146  myQImage.setColor( 0, bgColor.rgba() );
1147  myQImage.fill( 0 ); //defaults to white, set to transparent for rendering on a map
1148 
1149  QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
1150 
1151  double myMapUnitsPerPixel;
1152  double myX = 0.0;
1153  double myY = 0.0;
1154  QgsRectangle myExtent = mDataProvider->extent();
1155  if ( myExtent.width() / myExtent.height() >= ( double )myQImage.width() / myQImage.height() )
1156  {
1157  myMapUnitsPerPixel = myExtent.width() / myQImage.width();
1158  myY = ( myQImage.height() - myExtent.height() / myMapUnitsPerPixel ) / 2;
1159  }
1160  else
1161  {
1162  myMapUnitsPerPixel = myExtent.height() / myQImage.height();
1163  myX = ( myQImage.width() - myExtent.width() / myMapUnitsPerPixel ) / 2;
1164  }
1165 
1166  double myPixelWidth = myExtent.width() / myMapUnitsPerPixel;
1167  double myPixelHeight = myExtent.height() / myMapUnitsPerPixel;
1168 
1169  myRasterViewPort->mTopLeftPoint = QgsPoint( myX, myY );
1170  myRasterViewPort->mBottomRightPoint = QgsPoint( myPixelWidth, myPixelHeight );
1171  myRasterViewPort->mWidth = myQImage.width();
1172  myRasterViewPort->mHeight = myQImage.height();
1173 
1174  myRasterViewPort->mDrawnExtent = myExtent;
1175  myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
1176  myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
1177  myRasterViewPort->mSrcDatumTransform = -1;
1178  myRasterViewPort->mDestDatumTransform = -1;
1179 
1180  QgsMapToPixel *myMapToPixel = new QgsMapToPixel( myMapUnitsPerPixel );
1181 
1182  QPainter * myQPainter = new QPainter( &myQImage );
1183  draw( myQPainter, myRasterViewPort, myMapToPixel );
1184  delete myRasterViewPort;
1185  delete myMapToPixel;
1186  myQPainter->end();
1187  delete myQPainter;
1188 
1189  return myQImage;
1190 }
1191 
1192 void QgsRasterLayer::updateProgress( int theProgress, int theMax )
1193 {
1194  Q_UNUSED( theProgress );
1195  Q_UNUSED( theMax );
1196 }
1197 
1198 void QgsRasterLayer::onProgress( int theType, double theProgress, QString theMessage )
1199 {
1200  Q_UNUSED( theType );
1201  Q_UNUSED( theMessage );
1202  QgsDebugMsg( QString( "theProgress = %1" ).arg( theProgress ) );
1203  emit progressUpdate(( int )theProgress );
1204 }
1205 
1207 //
1208 // Protected methods
1209 //
1211 /*
1212  * @param QDomNode node that will contain the symbology definition for this layer.
1213  * @param errorMessage reference to string that will be updated with any error messages
1214  * @return true in case of success.
1215  */
1216 bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMessage )
1217 {
1218  Q_UNUSED( errorMessage );
1219  QDomElement rasterRendererElem;
1220 
1221  // pipe element was introduced in the end of 1.9 development when there were
1222  // already many project files in use so we support 1.9 backward compatibility
1223  // even it was never officialy released -> use pipe element if present, otherwise
1224  // use layer node
1225  QDomNode pipeNode = layer_node.firstChildElement( "pipe" );
1226  if ( pipeNode.isNull() ) // old project
1227  {
1228  pipeNode = layer_node;
1229  }
1230 
1231  //rasterlayerproperties element there -> old format (1.8 and early 1.9)
1232  if ( !layer_node.firstChildElement( "rasterproperties" ).isNull() )
1233  {
1234  //copy node because layer_node is const
1235  QDomNode layerNodeCopy = layer_node.cloneNode();
1236  QDomDocument doc = layerNodeCopy.ownerDocument();
1237  QDomElement rasterPropertiesElem = layerNodeCopy.firstChildElement( "rasterproperties" );
1238  QgsProjectFileTransform::convertRasterProperties( doc, layerNodeCopy, rasterPropertiesElem,
1239  this );
1240  rasterRendererElem = layerNodeCopy.firstChildElement( "rasterrenderer" );
1241  QgsDebugMsg( doc.toString() );
1242  }
1243  else
1244  {
1245  rasterRendererElem = pipeNode.firstChildElement( "rasterrenderer" );
1246  }
1247 
1248  if ( !rasterRendererElem.isNull() )
1249  {
1250  QString rendererType = rasterRendererElem.attribute( "type" );
1251  QgsRasterRendererRegistryEntry rendererEntry;
1252  if ( QgsRasterRendererRegistry::instance()->rendererData( rendererType, rendererEntry ) )
1253  {
1254  QgsRasterRenderer *renderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() );
1255  mPipe.set( renderer );
1256  }
1257  }
1258 
1259  //brightness
1261  mPipe.set( brightnessFilter );
1262 
1263  //brightness coefficient
1264  QDomElement brightnessElem = pipeNode.firstChildElement( "brightnesscontrast" );
1265  if ( !brightnessElem.isNull() )
1266  {
1267  brightnessFilter->readXML( brightnessElem );
1268  }
1269 
1270  //hue/saturation
1272  mPipe.set( hueSaturationFilter );
1273 
1274  //saturation coefficient
1275  QDomElement hueSaturationElem = pipeNode.firstChildElement( "huesaturation" );
1276  if ( !hueSaturationElem.isNull() )
1277  {
1278  hueSaturationFilter->readXML( hueSaturationElem );
1279  }
1280 
1281  //resampler
1283  mPipe.set( resampleFilter );
1284 
1285  //max oversampling
1286  QDomElement resampleElem = pipeNode.firstChildElement( "rasterresampler" );
1287  if ( !resampleElem.isNull() )
1288  {
1289  resampleFilter->readXML( resampleElem );
1290  }
1291 
1292  // get and set the blend mode if it exists
1293  QDomNode blendModeNode = layer_node.namedItem( "blendMode" );
1294  if ( !blendModeNode.isNull() )
1295  {
1296  QDomElement e = blendModeNode.toElement();
1298  }
1299 
1300  return true;
1301 } //readSymbology
1302 
1309 bool QgsRasterLayer::readXml( const QDomNode& layer_node )
1310 {
1311  QgsDebugMsg( "Entered" );
1313 
1314  //process provider key
1315  QDomNode pkeyNode = layer_node.namedItem( "provider" );
1316 
1317  if ( pkeyNode.isNull() )
1318  {
1319  mProviderKey = "gdal";
1320  }
1321  else
1322  {
1323  QDomElement pkeyElt = pkeyNode.toElement();
1324  mProviderKey = pkeyElt.text();
1325  if ( mProviderKey.isEmpty() )
1326  {
1327  mProviderKey = "gdal";
1328  }
1329  }
1330 
1331  // Open the raster source based on provider and datasource
1332 
1333  // Go down the raster-data-provider paradigm
1334 
1335  // Collect provider-specific information
1336 
1337  QDomNode rpNode = layer_node.namedItem( "rasterproperties" );
1338 
1339  if ( mProviderKey == "wms" )
1340  {
1341  // >>> BACKWARD COMPATIBILITY < 1.9
1342  // The old WMS URI format does not contain all the information, we add them here.
1343  if ( !mDataSource.contains( "crs=" ) && !mDataSource.contains( "format=" ) )
1344  {
1345  QgsDebugMsg( "Old WMS URI format detected -> adding params" );
1346  QgsDataSourceURI uri;
1347  uri.setEncodedUri( mDataSource );
1348  QDomElement layerElement = rpNode.firstChildElement( "wmsSublayer" );
1349  while ( !layerElement.isNull() )
1350  {
1351  // TODO: sublayer visibility - post-0.8 release timeframe
1352 
1353  // collect name for the sublayer
1354  uri.setParam( "layers", layerElement.namedItem( "name" ).toElement().text() );
1355 
1356  // collect style for the sublayer
1357  uri.setParam( "styles", layerElement.namedItem( "style" ).toElement().text() );
1358 
1359  layerElement = layerElement.nextSiblingElement( "wmsSublayer" );
1360  }
1361 
1362  // Collect format
1363  QDomNode formatNode = rpNode.namedItem( "wmsFormat" );
1364  uri.setParam( "format", rpNode.namedItem( "wmsFormat" ).toElement().text() );
1365 
1366  // WMS CRS URL param should not be mixed with that assigned to the layer.
1367  // In the old WMS URI version there was no CRS and layer crs().authid() was used.
1368  uri.setParam( "crs", crs().authid() );
1369  mDataSource = uri.encodedUri();
1370  }
1371  // <<< BACKWARD COMPATIBILITY < 1.9
1372  }
1373 
1374  setDataProvider( mProviderKey );
1375  if ( !mValid ) return false;
1376 
1377  QString theError;
1378  bool res = readSymbology( layer_node, theError );
1379 
1380  // old wms settings we need to correct
1381  if ( res && mProviderKey == "wms" && ( !renderer() || renderer()->type() != "singlebandcolordata" ) )
1382  {
1383  setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
1384  }
1385 
1386  // Check timestamp
1387  // This was probably introduced to reload completely raster if data changed and
1388  // reset completly symbology to reflect new data type etc. It creates however
1389  // problems, because user defined symbology is complete lost if data file time
1390  // changed (the content may be the same). See also 6900.
1391 #if 0
1392  QDomNode stampNode = layer_node.namedItem( "timestamp" );
1393  if ( !stampNode.isNull() )
1394  {
1395  QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate );
1396  // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static?
1397  if ( stamp < mDataProvider->dataTimestamp() )
1398  {
1399  QgsDebugMsg( "data changed, reload provider" );
1400  closeDataProvider();
1401  init();
1402  setDataProvider( mProviderKey );
1403  if ( !mValid ) return false;
1404  }
1405  }
1406 #endif
1407 
1408  // Load user no data value
1409  QDomElement noDataElement = layer_node.firstChildElement( "noData" );
1410 
1411  QDomNodeList noDataBandList = noDataElement.elementsByTagName( "noDataList" );
1412 
1413  for ( int i = 0; i < noDataBandList.size(); ++i )
1414  {
1415  QDomElement bandElement = noDataBandList.at( i ).toElement();
1416  bool ok;
1417  int bandNo = bandElement.attribute( "bandNo" ).toInt( &ok );
1418  QgsDebugMsg( QString( "bandNo = %1" ).arg( bandNo ) );
1419  if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) )
1420  {
1421  mDataProvider->setUseSrcNoDataValue( bandNo, bandElement.attribute( "useSrcNoData" ).toInt() );
1422  QgsRasterRangeList myNoDataRangeList;
1423 
1424  QDomNodeList rangeList = bandElement.elementsByTagName( "noDataRange" );
1425 
1426  for ( int j = 0; j < rangeList.size(); ++j )
1427  {
1428  QDomElement rangeElement = rangeList.at( j ).toElement();
1429  QgsRasterRange myNoDataRange( rangeElement.attribute( "min" ).toDouble(),
1430  rangeElement.attribute( "max" ).toDouble() );
1431  QgsDebugMsg( QString( "min = %1 %2" ).arg( rangeElement.attribute( "min" ) ).arg( myNoDataRange.min() ) );
1432  myNoDataRangeList << myNoDataRange;
1433  }
1434  mDataProvider->setUserNoDataValue( bandNo, myNoDataRangeList );
1435  }
1436  }
1437 
1438  readStyleManager( layer_node );
1439 
1440  return res;
1441 } // QgsRasterLayer::readXml( QDomNode & layer_node )
1442 
1443 /*
1444  * @param QDomNode the node that will have the style element added to it.
1445  * @param QDomDocument the document that will have the QDomNode added.
1446  * @param errorMessage reference to string that will be updated with any error messages
1447  * @return true in case of success.
1448  */
1449 bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & document, QString& errorMessage ) const
1450 {
1451  Q_UNUSED( errorMessage );
1452  QDomElement layerElem = layer_node.toElement();
1453 
1454  // Store pipe members (except provider) into pipe element, in future, it will be
1455  // possible to add custom filters into the pipe
1456  QDomElement pipeElement = document.createElement( "pipe" );
1457 
1458  for ( int i = 1; i < mPipe.size(); i++ )
1459  {
1460  QgsRasterInterface * interface = mPipe.at( i );
1461  if ( !interface ) continue;
1462  interface->writeXML( document, pipeElement );
1463  }
1464 
1465  layer_node.appendChild( pipeElement );
1466 
1467  // add blend mode node
1468  QDomElement blendModeElement = document.createElement( "blendMode" );
1469  QDomText blendModeText = document.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( blendMode() ) ) );
1470  blendModeElement.appendChild( blendModeText );
1471  layer_node.appendChild( blendModeElement );
1472 
1473  return true;
1474 } // bool QgsRasterLayer::writeSymbology
1475 
1476 /*
1477  * virtual
1478  * @note Called by QgsMapLayer::writeXML().
1479  */
1480 bool QgsRasterLayer::writeXml( QDomNode & layer_node,
1481  QDomDocument & document )
1482 {
1483  // first get the layer element so that we can append the type attribute
1484 
1485  QDomElement mapLayerNode = layer_node.toElement();
1486 
1487  if ( mapLayerNode.isNull() || "maplayer" != mapLayerNode.nodeName() )
1488  {
1489  QgsMessageLog::logMessage( tr( "<maplayer> not found." ), tr( "Raster" ) );
1490  return false;
1491  }
1492 
1493  mapLayerNode.setAttribute( "type", "raster" );
1494 
1495  // add provider node
1496 
1497  QDomElement provider = document.createElement( "provider" );
1498  QDomText providerText = document.createTextNode( mProviderKey );
1499  provider.appendChild( providerText );
1500  layer_node.appendChild( provider );
1501 
1502  // User no data
1503  QDomElement noData = document.createElement( "noData" );
1504 
1505  for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
1506  {
1507  QDomElement noDataRangeList = document.createElement( "noDataList" );
1508  noDataRangeList.setAttribute( "bandNo", bandNo );
1509  noDataRangeList.setAttribute( "useSrcNoData", mDataProvider->useSrcNoDataValue( bandNo ) );
1510 
1511  foreach ( QgsRasterRange range, mDataProvider->userNoDataValues( bandNo ) )
1512  {
1513  QDomElement noDataRange = document.createElement( "noDataRange" );
1514 
1515  noDataRange.setAttribute( "min", range.min() );
1516  noDataRange.setAttribute( "max", range.max() );
1517  noDataRangeList.appendChild( noDataRange );
1518  }
1519 
1520  noData.appendChild( noDataRangeList );
1521 
1522  }
1523  if ( noData.hasChildNodes() )
1524  {
1525  layer_node.appendChild( noData );
1526  }
1527 
1528  writeStyleManager( layer_node, document );
1529 
1530  //write out the symbology
1531  QString errorMsg;
1532  return writeSymbology( layer_node, document, errorMsg );
1533 }
1534 
1536 {
1537  if ( !mDataProvider ) return 0;
1538  return mDataProvider->xSize();
1539 }
1540 
1542 {
1543  if ( !mDataProvider ) return 0;
1544  return mDataProvider->ySize();
1545 }
1546 
1548 //
1549 // Private methods
1550 //
1552 bool QgsRasterLayer::update()
1553 {
1554  QgsDebugMsg( "entered." );
1555  // Check if data changed
1556  if ( mDataProvider->dataTimestamp() > mDataProvider->timestamp() )
1557  {
1558  QgsDebugMsg( "reload data" );
1559  closeDataProvider();
1560  init();
1561  setDataProvider( mProviderKey );
1562  emit dataChanged();
1563  }
1564  return mValid;
1565 }