LCOV - code coverage report
Current view: top level - core/raster - qgsrasterlayer.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 1392 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       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 "qgsbrightnesscontrastfilter.h"
      19                 :            : #include "qgscolorrampshader.h"
      20                 :            : #include "qgscoordinatereferencesystem.h"
      21                 :            : #include "qgscoordinatetransform.h"
      22                 :            : #include "qgsdatasourceuri.h"
      23                 :            : #include "qgshuesaturationfilter.h"
      24                 :            : #include "qgslayermetadataformatter.h"
      25                 :            : #include "qgslogger.h"
      26                 :            : #include "qgsmaplayerlegend.h"
      27                 :            : #include "qgsmaptopixel.h"
      28                 :            : #include "qgsmessagelog.h"
      29                 :            : #include "qgsmultibandcolorrenderer.h"
      30                 :            : #include "qgspainting.h"
      31                 :            : #include "qgspalettedrasterrenderer.h"
      32                 :            : #include "qgspathresolver.h"
      33                 :            : #include "qgsprojectfiletransform.h"
      34                 :            : #include "qgsproviderregistry.h"
      35                 :            : #include "qgsrasterdataprovider.h"
      36                 :            : #include "qgsrasterdrawer.h"
      37                 :            : #include "qgsrasteriterator.h"
      38                 :            : #include "qgsrasterlayer.h"
      39                 :            : #include "qgsrasterlayerrenderer.h"
      40                 :            : #include "qgsrasterprojector.h"
      41                 :            : #include "qgsrasterrange.h"
      42                 :            : #include "qgsrasterrendererregistry.h"
      43                 :            : #include "qgsrasterresamplefilter.h"
      44                 :            : #include "qgsrastershader.h"
      45                 :            : #include "qgsreadwritecontext.h"
      46                 :            : #include "qgsrectangle.h"
      47                 :            : #include "qgsrendercontext.h"
      48                 :            : #include "qgssinglebandcolordatarenderer.h"
      49                 :            : #include "qgssinglebandgrayrenderer.h"
      50                 :            : #include "qgssinglebandpseudocolorrenderer.h"
      51                 :            : #include "qgssettings.h"
      52                 :            : #include "qgssymbollayerutils.h"
      53                 :            : #include "qgsgdalprovider.h"
      54                 :            : #include "qgsbilinearrasterresampler.h"
      55                 :            : #include "qgscubicrasterresampler.h"
      56                 :            : #include "qgsrasterlayertemporalproperties.h"
      57                 :            : #include "qgsruntimeprofiler.h"
      58                 :            : #include "qgsmaplayerfactory.h"
      59                 :            : 
      60                 :            : #include <cmath>
      61                 :            : #include <cstdio>
      62                 :            : #include <limits>
      63                 :            : #include <typeinfo>
      64                 :            : 
      65                 :            : #include <QApplication>
      66                 :            : #include <QCursor>
      67                 :            : #include <QDir>
      68                 :            : #include <QDomElement>
      69                 :            : #include <QDomNode>
      70                 :            : #include <QFile>
      71                 :            : #include <QFileInfo>
      72                 :            : #include <QFont>
      73                 :            : #include <QFontMetrics>
      74                 :            : #include <QFrame>
      75                 :            : #include <QImage>
      76                 :            : #include <QLabel>
      77                 :            : #include <QList>
      78                 :            : #include <QMatrix>
      79                 :            : #include <QMessageBox>
      80                 :            : #include <QPainter>
      81                 :            : #include <QPixmap>
      82                 :            : #include <QRegExp>
      83                 :            : #include <QSlider>
      84                 :            : #include <QUrl>
      85                 :            : 
      86                 :            : #define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer")
      87                 :            : 
      88                 :            : const double QgsRasterLayer::SAMPLE_SIZE = 250000;
      89                 :            : 
      90                 :            : const QgsContrastEnhancement::ContrastEnhancementAlgorithm
      91                 :            : QgsRasterLayer::SINGLE_BAND_ENHANCEMENT_ALGORITHM = QgsContrastEnhancement::StretchToMinimumMaximum;
      92                 :            : const QgsContrastEnhancement::ContrastEnhancementAlgorithm
      93                 :            : QgsRasterLayer::MULTIPLE_BAND_SINGLE_BYTE_ENHANCEMENT_ALGORITHM = QgsContrastEnhancement::NoEnhancement;
      94                 :            : const QgsContrastEnhancement::ContrastEnhancementAlgorithm
      95                 :            : QgsRasterLayer::MULTIPLE_BAND_MULTI_BYTE_ENHANCEMENT_ALGORITHM = QgsContrastEnhancement::StretchToMinimumMaximum;
      96                 :            : 
      97                 :            : const QgsRasterMinMaxOrigin::Limits
      98                 :            : QgsRasterLayer::SINGLE_BAND_MIN_MAX_LIMITS = QgsRasterMinMaxOrigin::MinMax;
      99                 :            : const QgsRasterMinMaxOrigin::Limits
     100                 :            : QgsRasterLayer::MULTIPLE_BAND_SINGLE_BYTE_MIN_MAX_LIMITS = QgsRasterMinMaxOrigin::MinMax;
     101                 :            : const QgsRasterMinMaxOrigin::Limits
     102                 :            : QgsRasterLayer::MULTIPLE_BAND_MULTI_BYTE_MIN_MAX_LIMITS = QgsRasterMinMaxOrigin::CumulativeCut;
     103                 :            : 
     104                 :          0 : QgsRasterLayer::QgsRasterLayer()
     105                 :          0 :   : QgsMapLayer( QgsMapLayerType::RasterLayer )
     106                 :          0 :   , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
     107                 :          0 :   , TRSTRING_NOT_SET( tr( "Not Set" ) )
     108                 :          0 :   , mTemporalProperties( new QgsRasterLayerTemporalProperties( this ) )
     109                 :            : 
     110                 :          0 : {
     111                 :          0 :   init();
     112                 :          0 :   setValid( false );
     113                 :          0 : }
     114                 :            : 
     115                 :          0 : QgsRasterLayer::QgsRasterLayer( const QString &uri,
     116                 :            :                                 const QString &baseName,
     117                 :            :                                 const QString &providerKey,
     118                 :            :                                 const LayerOptions &options )
     119                 :          0 :   : QgsMapLayer( QgsMapLayerType::RasterLayer, baseName, uri )
     120                 :            :     // Constant that signals property not used.
     121                 :          0 :   , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
     122                 :          0 :   , TRSTRING_NOT_SET( tr( "Not Set" ) )
     123                 :          0 :   , mTemporalProperties( new QgsRasterLayerTemporalProperties( this ) )
     124                 :          0 : {
     125                 :          0 :   mShouldValidateCrs = !options.skipCrsValidation;
     126                 :            : 
     127                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
     128                 :          0 :   setProviderType( providerKey );
     129                 :            : 
     130                 :          0 :   QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
     131                 :            : 
     132                 :          0 :   setDataSource( uri, baseName, providerKey, providerOptions, options.loadDefaultStyle );
     133                 :            : 
     134                 :          0 :   if ( isValid() )
     135                 :            :   {
     136                 :          0 :     mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
     137                 :          0 :   }
     138                 :            : 
     139                 :          0 : } // QgsRasterLayer ctor
     140                 :            : 
     141                 :          0 : QgsRasterLayer::~QgsRasterLayer()
     142                 :          0 : {
     143                 :          0 :   emit willBeDeleted();
     144                 :            : 
     145                 :          0 :   setValid( false );
     146                 :            :   // Note: provider and other interfaces are owned and deleted by pipe
     147                 :          0 : }
     148                 :            : 
     149                 :          0 : QgsRasterLayer *QgsRasterLayer::clone() const
     150                 :            : {
     151                 :          0 :   QgsRasterLayer::LayerOptions options;
     152                 :          0 :   if ( mDataProvider )
     153                 :            :   {
     154                 :          0 :     options.transformContext = mDataProvider->transformContext();
     155                 :          0 :   }
     156                 :          0 :   QgsRasterLayer *layer = new QgsRasterLayer( source(), name(), mProviderKey, options );
     157                 :          0 :   QgsMapLayer::clone( layer );
     158                 :            : 
     159                 :            :   // do not clone data provider which is the first element in pipe
     160                 :          0 :   for ( int i = 1; i < mPipe.size(); i++ )
     161                 :            :   {
     162                 :          0 :     if ( mPipe.at( i ) )
     163                 :          0 :       layer->pipe()->set( mPipe.at( i )->clone() );
     164                 :          0 :   }
     165                 :            : 
     166                 :          0 :   return layer;
     167                 :          0 : }
     168                 :            : 
     169                 :            : //////////////////////////////////////////////////////////
     170                 :            : //
     171                 :            : // Static Methods and members
     172                 :            : //
     173                 :            : /////////////////////////////////////////////////////////
     174                 :            : 
     175                 :          0 : bool QgsRasterLayer::isValidRasterFileName( const QString &fileNameQString, QString &retErrMsg )
     176                 :            : {
     177                 :          0 :   bool myIsValid = QgsGdalProvider::isValidRasterFileName( fileNameQString, retErrMsg );
     178                 :          0 :   return myIsValid;
     179                 :            : }
     180                 :            : 
     181                 :          0 : bool QgsRasterLayer::isValidRasterFileName( QString const &fileNameQString )
     182                 :            : {
     183                 :          0 :   QString retErrMsg;
     184                 :          0 :   return isValidRasterFileName( fileNameQString, retErrMsg );
     185                 :          0 : }
     186                 :            : 
     187                 :          0 : QDateTime QgsRasterLayer::lastModified( QString const &name )
     188                 :            : {
     189                 :          0 :   QgsDebugMsgLevel( "name=" + name, 4 );
     190                 :          0 :   QDateTime t;
     191                 :            : 
     192                 :          0 :   QFileInfo fi( name );
     193                 :            : 
     194                 :            :   // Is it file?
     195                 :          0 :   if ( !fi.exists() )
     196                 :          0 :     return t;
     197                 :            : 
     198                 :          0 :   t = fi.lastModified();
     199                 :            : 
     200                 :          0 :   QgsDebugMsgLevel( "last modified = " + t.toString(), 4 );
     201                 :            : 
     202                 :          0 :   return t;
     203                 :          0 : }
     204                 :            : 
     205                 :          0 : void QgsRasterLayer::setDataProvider( const QString &provider )
     206                 :            : {
     207                 :          0 :   setDataProvider( provider, QgsDataProvider::ProviderOptions() );
     208                 :          0 : }
     209                 :            : 
     210                 :            : // typedef for the QgsDataProvider class factory
     211                 :            : typedef QgsDataProvider *classFactoryFunction_t( const QString *, const QgsDataProvider::ProviderOptions &options );
     212                 :            : 
     213                 :            : //////////////////////////////////////////////////////////
     214                 :            : //
     215                 :            : // Non Static Public methods
     216                 :            : //
     217                 :            : /////////////////////////////////////////////////////////
     218                 :            : 
     219                 :          0 : int QgsRasterLayer::bandCount() const
     220                 :            : {
     221                 :          0 :   if ( !mDataProvider ) return 0;
     222                 :          0 :   return mDataProvider->bandCount();
     223                 :          0 : }
     224                 :            : 
     225                 :          0 : QString QgsRasterLayer::bandName( int bandNo ) const
     226                 :            : {
     227                 :          0 :   if ( !mDataProvider ) return QString();
     228                 :          0 :   return mDataProvider->generateBandName( bandNo );
     229                 :          0 : }
     230                 :            : 
     231                 :          0 : void QgsRasterLayer::setRendererForDrawingStyle( QgsRaster::DrawingStyle drawingStyle )
     232                 :            : {
     233                 :          0 :   setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( drawingStyle, mDataProvider ) );
     234                 :          0 : }
     235                 :            : 
     236                 :          0 : QgsRasterDataProvider *QgsRasterLayer::dataProvider()
     237                 :            : {
     238                 :          0 :   return mDataProvider;
     239                 :            : }
     240                 :            : 
     241                 :          0 : const QgsRasterDataProvider *QgsRasterLayer::dataProvider() const
     242                 :            : {
     243                 :          0 :   return mDataProvider;
     244                 :            : }
     245                 :            : 
     246                 :          0 : void QgsRasterLayer::reload()
     247                 :            : {
     248                 :          0 :   if ( mDataProvider )
     249                 :            :   {
     250                 :          0 :     mDataProvider->reloadData();
     251                 :          0 :   }
     252                 :          0 : }
     253                 :            : 
     254                 :          0 : QgsMapLayerRenderer *QgsRasterLayer::createMapRenderer( QgsRenderContext &rendererContext )
     255                 :            : {
     256                 :          0 :   return new QgsRasterLayerRenderer( this, rendererContext );
     257                 :          0 : }
     258                 :            : 
     259                 :            : 
     260                 :          0 : void QgsRasterLayer::draw( QPainter *theQPainter,
     261                 :            :                            QgsRasterViewPort *rasterViewPort,
     262                 :            :                            const QgsMapToPixel *qgsMapToPixel )
     263                 :            : {
     264                 :          0 :   QgsDebugMsgLevel( QStringLiteral( " 3 arguments" ), 4 );
     265                 :          0 :   QElapsedTimer time;
     266                 :          0 :   time.start();
     267                 :            :   //
     268                 :            :   //
     269                 :            :   // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
     270                 :            :   // so that we can maximise performance of the rendering process. So now we check which drawing
     271                 :            :   // procedure to use :
     272                 :            :   //
     273                 :            : 
     274                 :          0 :   QgsRasterProjector *projector = mPipe.projector();
     275                 :          0 :   bool restoreOldResamplingStage = false;
     276                 :          0 :   QgsRasterPipe::ResamplingStage oldResamplingState = resamplingStage();
     277                 :            :   // TODO add a method to interface to get provider and get provider
     278                 :            :   // params in QgsRasterProjector
     279                 :            : 
     280                 :          0 :   if ( projector )
     281                 :            :   {
     282                 :            :     // Force provider resampling if reprojection is needed
     283                 :          0 :     if ( mDataProvider != nullptr &&
     284                 :          0 :          ( mDataProvider->providerCapabilities() & QgsRasterDataProvider::ProviderHintCanPerformProviderResampling ) &&
     285                 :          0 :          rasterViewPort->mSrcCRS != rasterViewPort->mDestCRS &&
     286                 :          0 :          oldResamplingState != QgsRasterPipe::ResamplingStage::Provider )
     287                 :            :     {
     288                 :          0 :       restoreOldResamplingStage = true;
     289                 :          0 :       setResamplingStage( QgsRasterPipe::ResamplingStage::Provider );
     290                 :          0 :     }
     291                 :          0 :     projector->setCrs( rasterViewPort->mSrcCRS, rasterViewPort->mDestCRS, rasterViewPort->mTransformContext );
     292                 :          0 :   }
     293                 :            : 
     294                 :            :   // Drawer to pipe?
     295                 :          0 :   QgsRasterIterator iterator( mPipe.last() );
     296                 :          0 :   QgsRasterDrawer drawer( &iterator );
     297                 :          0 :   drawer.draw( theQPainter, rasterViewPort, qgsMapToPixel );
     298                 :            : 
     299                 :          0 :   if ( restoreOldResamplingStage )
     300                 :            :   {
     301                 :          0 :     setResamplingStage( oldResamplingState );
     302                 :          0 :   }
     303                 :            : 
     304                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "total raster draw time (ms):     %1" ).arg( time.elapsed(), 5 ), 4 );
     305                 :          0 : }
     306                 :            : 
     307                 :          0 : QgsLegendColorList QgsRasterLayer::legendSymbologyItems() const
     308                 :            : {
     309                 :          0 :   QgsRasterRenderer *renderer = mPipe.renderer();
     310                 :          0 :   return renderer ? renderer->legendSymbologyItems() : QList< QPair< QString, QColor > >();;
     311                 :            : }
     312                 :            : 
     313                 :          0 : QString QgsRasterLayer::htmlMetadata() const
     314                 :            : {
     315                 :          0 :   QgsLayerMetadataFormatter htmlFormatter( metadata() );
     316                 :          0 :   QString myMetadata = QStringLiteral( "<html><head></head>\n<body>\n" );
     317                 :            : 
     318                 :            :   // Begin Provider section
     319                 :          0 :   myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" ) %
     320                 :          0 :                 QStringLiteral( "<table class=\"list-view\">\n" ) %
     321                 :            : 
     322                 :            :                 // name
     323                 :          0 :                 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Name" ) % QStringLiteral( "</td><td>" ) % name() % QStringLiteral( "</td></tr>\n" );
     324                 :            : 
     325                 :            :   // local path
     326                 :          0 :   QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
     327                 :          0 :   QString path;
     328                 :          0 :   bool isLocalPath = false;
     329                 :          0 :   if ( uriComponents.contains( QStringLiteral( "path" ) ) )
     330                 :            :   {
     331                 :          0 :     path = uriComponents[QStringLiteral( "path" )].toString();
     332                 :          0 :     if ( QFile::exists( path ) )
     333                 :            :     {
     334                 :          0 :       isLocalPath = true;
     335                 :          0 :       myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Path" ) % QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( path ).toString(), QDir::toNativeSeparators( path ) ) ) + QStringLiteral( "</td></tr>\n" );
     336                 :          0 :     }
     337                 :          0 :   }
     338                 :          0 :   if ( uriComponents.contains( QStringLiteral( "url" ) ) )
     339                 :            :   {
     340                 :          0 :     const QString url = uriComponents[QStringLiteral( "url" )].toString();
     341                 :          0 :     myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "URL" ) % QStringLiteral( "</td><td>%1" ).arg( QStringLiteral( "<a href=\"%1\">%2</a>" ).arg( QUrl( url ).toString(), url ) ) + QStringLiteral( "</td></tr>\n" );
     342                 :          0 :   }
     343                 :            : 
     344                 :            :   // data source
     345                 :          0 :   if ( publicSource() != path || !isLocalPath )
     346                 :          0 :     myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() != path ? publicSource() : path ) + QStringLiteral( "</td></tr>\n" );
     347                 :            : 
     348                 :            :   // EPSG
     349                 :          0 :   myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "CRS" ) + QStringLiteral( "</td><td>" );
     350                 :          0 :   if ( crs().isValid() )
     351                 :            :   {
     352                 :          0 :     myMetadata += crs().userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) % QStringLiteral( " - " );
     353                 :          0 :     if ( crs().isGeographic() )
     354                 :          0 :       myMetadata += tr( "Geographic" );
     355                 :            :     else
     356                 :          0 :       myMetadata += tr( "Projected" );
     357                 :          0 :   }
     358                 :          0 :   myMetadata += QStringLiteral( "</td></tr>\n" ) %
     359                 :            : 
     360                 :            :                 // Extent
     361                 :          0 :                 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Extent" ) % QStringLiteral( "</td><td>" ) % extent().toString() % QStringLiteral( "</td></tr>\n" ) %
     362                 :            : 
     363                 :            :                 // unit
     364                 :          0 :                 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Unit" ) % QStringLiteral( "</td><td>" ) % QgsUnitTypes::toString( crs().mapUnits() ) % QStringLiteral( "</td></tr>\n" ) %
     365                 :            : 
     366                 :            :                 // Raster Width
     367                 :          0 :                 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Width" ) % QStringLiteral( "</td><td>" );
     368                 :          0 :   if ( dataProvider()->capabilities() & QgsRasterDataProvider::Size )
     369                 :          0 :     myMetadata += QString::number( width() );
     370                 :            :   else
     371                 :          0 :     myMetadata += tr( "n/a" );
     372                 :          0 :   myMetadata += QStringLiteral( "</td></tr>\n" ) %
     373                 :            : 
     374                 :            :                 // Raster height
     375                 :          0 :                 QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Height" ) + QStringLiteral( "</td><td>" );
     376                 :          0 :   if ( dataProvider()->capabilities() & QgsRasterDataProvider::Size )
     377                 :          0 :     myMetadata += QString::number( height() );
     378                 :            :   else
     379                 :          0 :     myMetadata += tr( "n/a" );
     380                 :          0 :   myMetadata += QStringLiteral( "</td></tr>\n" ) %
     381                 :            : 
     382                 :            :                 // Data type
     383                 :          0 :                 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Data type" ) % QStringLiteral( "</td><td>" );
     384                 :            :   // Just use the first band
     385                 :          0 :   switch ( mDataProvider->sourceDataType( 1 ) )
     386                 :            :   {
     387                 :            :     case Qgis::Byte:
     388                 :          0 :       myMetadata += tr( "Byte - Eight bit unsigned integer" );
     389                 :          0 :       break;
     390                 :            :     case Qgis::UInt16:
     391                 :          0 :       myMetadata += tr( "UInt16 - Sixteen bit unsigned integer " );
     392                 :          0 :       break;
     393                 :            :     case Qgis::Int16:
     394                 :          0 :       myMetadata += tr( "Int16 - Sixteen bit signed integer " );
     395                 :          0 :       break;
     396                 :            :     case Qgis::UInt32:
     397                 :          0 :       myMetadata += tr( "UInt32 - Thirty two bit unsigned integer " );
     398                 :          0 :       break;
     399                 :            :     case Qgis::Int32:
     400                 :          0 :       myMetadata += tr( "Int32 - Thirty two bit signed integer " );
     401                 :          0 :       break;
     402                 :            :     case Qgis::Float32:
     403                 :          0 :       myMetadata += tr( "Float32 - Thirty two bit floating point " );
     404                 :          0 :       break;
     405                 :            :     case Qgis::Float64:
     406                 :          0 :       myMetadata += tr( "Float64 - Sixty four bit floating point " );
     407                 :          0 :       break;
     408                 :            :     case Qgis::CInt16:
     409                 :          0 :       myMetadata += tr( "CInt16 - Complex Int16 " );
     410                 :          0 :       break;
     411                 :            :     case Qgis::CInt32:
     412                 :          0 :       myMetadata += tr( "CInt32 - Complex Int32 " );
     413                 :          0 :       break;
     414                 :            :     case Qgis::CFloat32:
     415                 :          0 :       myMetadata += tr( "CFloat32 - Complex Float32 " );
     416                 :          0 :       break;
     417                 :            :     case Qgis::CFloat64:
     418                 :          0 :       myMetadata += tr( "CFloat64 - Complex Float64 " );
     419                 :          0 :       break;
     420                 :            :     default:
     421                 :          0 :       myMetadata += tr( "Could not determine raster data type." );
     422                 :          0 :   }
     423                 :          0 :   myMetadata += QStringLiteral( "</td></tr>\n" ) %
     424                 :            : 
     425                 :            :                 // Insert provider-specific (e.g. WMS-specific) metadata
     426                 :          0 :                 mDataProvider->htmlMetadata() %
     427                 :            : 
     428                 :            :                 // End Provider section
     429                 :          0 :                 QStringLiteral( "</table>\n<br><br>" ) %
     430                 :            : 
     431                 :            :                 // Identification section
     432                 :          0 :                 QStringLiteral( "<h1>" ) % tr( "Identification" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
     433                 :          0 :                 htmlFormatter.identificationSectionHtml() %
     434                 :          0 :                 QStringLiteral( "<br><br>\n" ) %
     435                 :            : 
     436                 :            :                 // extent section
     437                 :          0 :                 QStringLiteral( "<h1>" ) % tr( "Extent" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
     438                 :          0 :                 htmlFormatter.extentSectionHtml( ) %
     439                 :          0 :                 QStringLiteral( "<br><br>\n" ) %
     440                 :            : 
     441                 :            :                 // Start the Access section
     442                 :          0 :                 QStringLiteral( "<h1>" ) % tr( "Access" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
     443                 :          0 :                 htmlFormatter.accessSectionHtml( ) %
     444                 :          0 :                 QStringLiteral( "<br><br>\n" ) %
     445                 :            : 
     446                 :            :                 // Bands section
     447                 :          0 :                 QStringLiteral( "</table>\n<br><br><h1>" ) % tr( "Bands" ) % QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" ) %
     448                 :            : 
     449                 :            :                 // Band count
     450                 :          0 :                 QStringLiteral( "<tr><td class=\"highlight\">" ) % tr( "Band count" ) % QStringLiteral( "</td><td>" ) % QString::number( bandCount() ) % QStringLiteral( "</td></tr>\n" );
     451                 :            : 
     452                 :            :   // Band table
     453                 :          0 :   myMetadata += QStringLiteral( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" ) %
     454                 :          0 :                 QStringLiteral( "<tr><th>" ) % tr( "Number" ) % QStringLiteral( "</th><th>" ) % tr( "Band" ) % QStringLiteral( "</th><th>" ) % tr( "No-Data" ) % QStringLiteral( "</th><th>" ) %
     455                 :          0 :                 tr( "Min" ) % QStringLiteral( "</th><th>" ) % tr( "Max" ) % QStringLiteral( "</th></tr>\n" );
     456                 :            : 
     457                 :          0 :   QgsRasterDataProvider *provider = const_cast< QgsRasterDataProvider * >( mDataProvider );
     458                 :          0 :   for ( int i = 1; i <= bandCount(); i++ )
     459                 :            :   {
     460                 :          0 :     QString rowClass;
     461                 :          0 :     if ( i % 2 )
     462                 :          0 :       rowClass = QStringLiteral( "class=\"odd-row\"" );
     463                 :            : 
     464                 :          0 :     myMetadata += QStringLiteral( "<tr " ) % rowClass % QStringLiteral( "><td>" ) % QString::number( i ) % QStringLiteral( "</td><td>" ) % bandName( i ) % QStringLiteral( "</td><td>" );
     465                 :            : 
     466                 :          0 :     if ( dataProvider()->sourceHasNoDataValue( i ) )
     467                 :          0 :       myMetadata += QString::number( dataProvider()->sourceNoDataValue( i ) );
     468                 :            :     else
     469                 :          0 :       myMetadata += tr( "n/a" );
     470                 :          0 :     myMetadata += QLatin1String( "</td>" );
     471                 :            : 
     472                 :          0 :     if ( provider->hasStatistics( i ) )
     473                 :            :     {
     474                 :          0 :       QgsRasterBandStats myRasterBandStats = provider->bandStatistics( i );
     475                 :          0 :       myMetadata += QStringLiteral( "<td>" ) % QString::number( myRasterBandStats.minimumValue, 'f', 10 ) % QStringLiteral( "</td>" ) %
     476                 :          0 :                     QStringLiteral( "<td>" ) % QString::number( myRasterBandStats.maximumValue, 'f', 10 ) % QStringLiteral( "</td>" );
     477                 :          0 :     }
     478                 :            :     else
     479                 :            :     {
     480                 :          0 :       myMetadata += QStringLiteral( "<td>" ) % tr( "n/a" ) % QStringLiteral( "</td><td>" ) % tr( "n/a" ) % QStringLiteral( "</td>" );
     481                 :            :     }
     482                 :            : 
     483                 :          0 :     myMetadata += QLatin1String( "</tr>\n" );
     484                 :          0 :   }
     485                 :            : 
     486                 :            :   //close previous bands table
     487                 :          0 :   myMetadata +=  QStringLiteral( "</table>\n<br><br>" ) %
     488                 :            : 
     489                 :            :                  // Start the contacts section
     490                 :          0 :                  QStringLiteral( "<h1>" ) % tr( "Contacts" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
     491                 :          0 :                  htmlFormatter.contactsSectionHtml( ) %
     492                 :          0 :                  QStringLiteral( "<br><br>\n" ) %
     493                 :            : 
     494                 :            :                  // Start the links section
     495                 :          0 :                  QStringLiteral( "<h1>" ) % tr( "References" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
     496                 :          0 :                  htmlFormatter.linksSectionHtml( ) %
     497                 :          0 :                  QStringLiteral( "<br><br>\n" ) %
     498                 :            : 
     499                 :            :                  // Start the history section
     500                 :          0 :                  QStringLiteral( "<h1>" ) % tr( "History" ) % QStringLiteral( "</h1>\n<hr>\n" ) %
     501                 :          0 :                  htmlFormatter.historySectionHtml( ) %
     502                 :          0 :                  QStringLiteral( "<br><br>\n" ) %
     503                 :            : 
     504                 :          0 :                  QStringLiteral( "\n</body>\n</html>\n" );
     505                 :          0 :   return myMetadata;
     506                 :          0 : }
     507                 :            : 
     508                 :          0 : QPixmap QgsRasterLayer::paletteAsPixmap( int bandNumber )
     509                 :            : {
     510                 :            :   //TODO: This function should take dimensions
     511                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
     512                 :            : 
     513                 :            :   // Only do this for the GDAL provider?
     514                 :            :   // Maybe WMS can do this differently using QImage::numColors and QImage::color()
     515                 :          0 :   if ( mDataProvider &&
     516                 :          0 :        mDataProvider->colorInterpretation( bandNumber ) == QgsRaster::PaletteIndex )
     517                 :            :   {
     518                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "....found paletted image" ), 4 );
     519                 :          0 :     QgsColorRampShader myShader;
     520                 :          0 :     QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( bandNumber );
     521                 :          0 :     if ( !myColorRampItemList.isEmpty() )
     522                 :            :     {
     523                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "....got color ramp item list" ), 4 );
     524                 :          0 :       myShader.setColorRampItemList( myColorRampItemList );
     525                 :          0 :       myShader.setColorRampType( QgsColorRampShader::Discrete );
     526                 :            :       // Draw image
     527                 :          0 :       int mySize = 100;
     528                 :          0 :       QPixmap myPalettePixmap( mySize, mySize );
     529                 :          0 :       QPainter myQPainter( &myPalettePixmap );
     530                 :            : 
     531                 :          0 :       QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 );
     532                 :          0 :       myQImage.fill( 0 );
     533                 :          0 :       myPalettePixmap.fill();
     534                 :            : 
     535                 :          0 :       double myStep = ( static_cast< double >( myColorRampItemList.size() ) - 1 ) / static_cast< double >( mySize * mySize );
     536                 :          0 :       double myValue = 0.0;
     537                 :          0 :       for ( int myRow = 0; myRow < mySize; myRow++ )
     538                 :            :       {
     539                 :          0 :         QRgb *myLineBuffer = reinterpret_cast< QRgb * >( myQImage.scanLine( myRow ) );
     540                 :          0 :         for ( int myCol = 0; myCol < mySize; myCol++ )
     541                 :            :         {
     542                 :          0 :           myValue = myStep * static_cast< double >( myCol + myRow * mySize );
     543                 :            :           int c1, c2, c3, c4;
     544                 :          0 :           myShader.shade( myValue, &c1, &c2, &c3, &c4 );
     545                 :          0 :           myLineBuffer[ myCol ] = qRgba( c1, c2, c3, c4 );
     546                 :          0 :         }
     547                 :          0 :       }
     548                 :            : 
     549                 :          0 :       myQPainter.drawImage( 0, 0, myQImage );
     550                 :          0 :       return myPalettePixmap;
     551                 :          0 :     }
     552                 :          0 :     QPixmap myNullPixmap;
     553                 :          0 :     return myNullPixmap;
     554                 :          0 :   }
     555                 :            :   else
     556                 :            :   {
     557                 :            :     //invalid layer  was requested
     558                 :          0 :     QPixmap myNullPixmap;
     559                 :          0 :     return myNullPixmap;
     560                 :          0 :   }
     561                 :          0 : }
     562                 :            : 
     563                 :          0 : QString QgsRasterLayer::providerType() const
     564                 :            : {
     565                 :          0 :   return mProviderKey;
     566                 :            : }
     567                 :            : 
     568                 :          0 : double QgsRasterLayer::rasterUnitsPerPixelX() const
     569                 :            : {
     570                 :            : // We return one raster pixel per map unit pixel
     571                 :            : // One raster pixel can have several raster units...
     572                 :            : 
     573                 :            : // We can only use one of the mGeoTransform[], so go with the
     574                 :            : // horisontal one.
     575                 :            : 
     576                 :          0 :   if ( mDataProvider &&
     577                 :          0 :        mDataProvider->capabilities() & QgsRasterDataProvider::Size && !qgsDoubleNear( mDataProvider->xSize(), 0.0 ) )
     578                 :            :   {
     579                 :          0 :     return mDataProvider->extent().width() / mDataProvider->xSize();
     580                 :            :   }
     581                 :          0 :   return 1;
     582                 :          0 : }
     583                 :            : 
     584                 :          0 : double QgsRasterLayer::rasterUnitsPerPixelY() const
     585                 :            : {
     586                 :          0 :   if ( mDataProvider &&
     587                 :          0 :        mDataProvider->capabilities() & QgsRasterDataProvider::Size && !qgsDoubleNear( mDataProvider->ySize(), 0.0 ) )
     588                 :            :   {
     589                 :          0 :     return mDataProvider->extent().height() / mDataProvider->ySize();
     590                 :            :   }
     591                 :          0 :   return 1;
     592                 :          0 : }
     593                 :            : 
     594                 :          0 : void QgsRasterLayer::setOpacity( double opacity )
     595                 :            : {
     596                 :          0 :   if ( !mPipe.renderer() || mPipe.renderer()->opacity() == opacity )
     597                 :          0 :     return;
     598                 :            : 
     599                 :          0 :   mPipe.renderer()->setOpacity( opacity );
     600                 :          0 :   emit opacityChanged( opacity );
     601                 :          0 :   emit styleChanged();
     602                 :          0 : }
     603                 :            : 
     604                 :          0 : double QgsRasterLayer::opacity() const
     605                 :            : {
     606                 :          0 :   return mPipe.renderer() ? mPipe.renderer()->opacity() : 1.0;
     607                 :            : }
     608                 :            : 
     609                 :          0 : void QgsRasterLayer::init()
     610                 :            : {
     611                 :          0 :   mRasterType = QgsRasterLayer::GrayOrUndefined;
     612                 :            : 
     613                 :          0 :   setLegend( QgsMapLayerLegend::defaultRasterLegend( this ) );
     614                 :            : 
     615                 :          0 :   setRendererForDrawingStyle( QgsRaster::UndefinedDrawingStyle );
     616                 :            : 
     617                 :            :   //Initialize the last view port structure, should really be a class
     618                 :          0 :   mLastViewPort.mWidth = 0;
     619                 :          0 :   mLastViewPort.mHeight = 0;
     620                 :          0 : }
     621                 :            : 
     622                 :          0 : void QgsRasterLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
     623                 :            : {
     624                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
     625                 :          0 :   setValid( false ); // assume the layer is invalid until we determine otherwise
     626                 :            : 
     627                 :          0 :   mPipe.remove( mDataProvider ); // deletes if exists
     628                 :          0 :   mDataProvider = nullptr;
     629                 :            : 
     630                 :            :   // XXX should I check for and possibly delete any pre-existing providers?
     631                 :            :   // XXX How often will that scenario occur?
     632                 :            : 
     633                 :          0 :   mProviderKey = provider;
     634                 :            :   // set the layer name (uppercase first character)
     635                 :          0 :   if ( ! mLayerName.isEmpty() )   // XXX shouldn't this happen in parent?
     636                 :            :   {
     637                 :          0 :     setName( mLayerName );
     638                 :          0 :   }
     639                 :            : 
     640                 :            :   //mBandCount = 0;
     641                 :            : 
     642                 :          0 :   std::unique_ptr< QgsScopedRuntimeProfile > profile;
     643                 :          0 :   if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
     644                 :          0 :     profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
     645                 :            : 
     646                 :          0 :   mDataProvider = qobject_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( mProviderKey, mDataSource, options, flags ) );
     647                 :          0 :   if ( !mDataProvider )
     648                 :            :   {
     649                 :            :     //QgsMessageLog::logMessage( tr( "Cannot instantiate the data provider" ), tr( "Raster" ) );
     650                 :          0 :     appendError( ERR( tr( "Cannot instantiate the '%1' data provider" ).arg( mProviderKey ) ) );
     651                 :          0 :     return;
     652                 :            :   }
     653                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Data provider created" ), 4 );
     654                 :          0 :   mDataProvider->setParent( this );
     655                 :            : 
     656                 :            :   // Set data provider into pipe even if not valid so that it is deleted with pipe (with layer)
     657                 :          0 :   mPipe.set( mDataProvider );
     658                 :          0 :   if ( !mDataProvider->isValid() )
     659                 :            :   {
     660                 :          0 :     setError( mDataProvider->error() );
     661                 :          0 :     appendError( ERR( tr( "Provider is not valid (provider: %1, URI: %2" ).arg( mProviderKey, mDataSource ) ) );
     662                 :          0 :     return;
     663                 :            :   }
     664                 :            : 
     665                 :          0 :   if ( mDataProvider->providerCapabilities() & QgsRasterDataProvider::ReadLayerMetadata )
     666                 :            :   {
     667                 :          0 :     setMetadata( mDataProvider->layerMetadata() );
     668                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
     669                 :          0 :   }
     670                 :            : 
     671                 :          0 :   if ( provider == QLatin1String( "gdal" ) )
     672                 :            :   {
     673                 :            :     // make sure that the /vsigzip or /vsizip is added to uri, if applicable
     674                 :          0 :     mDataSource = mDataProvider->dataSourceUri();
     675                 :          0 :   }
     676                 :            : 
     677                 :            :   // get the extent
     678                 :          0 :   QgsRectangle mbr = mDataProvider->extent();
     679                 :            : 
     680                 :            :   // show the extent
     681                 :          0 :   QgsDebugMsgLevel( "Extent of layer: " + mbr.toString(), 4 );
     682                 :            :   // store the extent
     683                 :          0 :   setExtent( mbr );
     684                 :            : 
     685                 :            :   // upper case the first letter of the layer name
     686                 :          0 :   QgsDebugMsgLevel( "mLayerName: " + name(), 4 );
     687                 :            : 
     688                 :            :   // set up the raster drawing style
     689                 :            :   // Do not set any 'sensible' style here, the style is set later
     690                 :            : 
     691                 :            :   // Setup source CRS
     692                 :          0 :   setCrs( QgsCoordinateReferenceSystem( mDataProvider->crs() ) );
     693                 :            : 
     694                 :          0 :   QgsDebugMsgLevel( "using wkt:\n" + crs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ), 4 );
     695                 :            : 
     696                 :            :   //defaults - Needs to be set after the Contrast list has been build
     697                 :            :   //Try to read the default contrast enhancement from the config file
     698                 :            : 
     699                 :            :   //decide what type of layer this is...
     700                 :            :   //TODO Change this to look at the color interp and palette interp to decide which type of layer it is
     701                 :          0 :   QgsDebugMsgLevel( "bandCount = " + QString::number( mDataProvider->bandCount() ), 4 );
     702                 :          0 :   QgsDebugMsgLevel( "dataType = " + QString::number( mDataProvider->dataType( 1 ) ), 4 );
     703                 :          0 :   if ( ( mDataProvider->bandCount() > 1 ) )
     704                 :            :   {
     705                 :            :     // handle singleband gray with alpha
     706                 :          0 :     if ( mDataProvider->bandCount() == 2
     707                 :          0 :          && ( ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::GrayIndex
     708                 :          0 :                 && mDataProvider->colorInterpretation( 2 ) == QgsRaster::AlphaBand )
     709                 :          0 :               || ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::AlphaBand
     710                 :          0 :                    && mDataProvider->colorInterpretation( 2 ) == QgsRaster::GrayIndex ) ) )
     711                 :            :     {
     712                 :          0 :       mRasterType = GrayOrUndefined;
     713                 :          0 :     }
     714                 :            :     else
     715                 :            :     {
     716                 :          0 :       mRasterType = Multiband;
     717                 :            :     }
     718                 :          0 :   }
     719                 :          0 :   else if ( mDataProvider->dataType( 1 ) == Qgis::ARGB32
     720                 :          0 :             ||  mDataProvider->dataType( 1 ) == Qgis::ARGB32_Premultiplied )
     721                 :            :   {
     722                 :          0 :     mRasterType = ColorLayer;
     723                 :          0 :   }
     724                 :          0 :   else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex )
     725                 :            :   {
     726                 :          0 :     mRasterType = Palette;
     727                 :          0 :   }
     728                 :          0 :   else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette )
     729                 :            :   {
     730                 :          0 :     mRasterType = Palette;
     731                 :          0 :   }
     732                 :            :   else
     733                 :            :   {
     734                 :          0 :     mRasterType = GrayOrUndefined;
     735                 :            :   }
     736                 :            : 
     737                 :          0 :   QgsDebugMsgLevel( "mRasterType = " + QString::number( mRasterType ), 4 );
     738                 :          0 :   if ( mRasterType == ColorLayer )
     739                 :            :   {
     740                 :          0 :     QgsDebugMsgLevel( "Setting drawing style to SingleBandColorDataStyle " + QString::number( QgsRaster::SingleBandColorDataStyle ), 4 );
     741                 :          0 :     setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
     742                 :          0 :   }
     743                 :          0 :   else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex )
     744                 :            :   {
     745                 :          0 :     setRendererForDrawingStyle( QgsRaster::PalettedColor ); //sensible default
     746                 :          0 :   }
     747                 :          0 :   else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette )
     748                 :            :   {
     749                 :          0 :     setRendererForDrawingStyle( QgsRaster::SingleBandPseudoColor );
     750                 :            :     // Load color table
     751                 :          0 :     QList<QgsColorRampShader::ColorRampItem> colorTable = mDataProvider->colorTable( 1 );
     752                 :          0 :     QgsSingleBandPseudoColorRenderer *r = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( renderer() );
     753                 :          0 :     if ( r )
     754                 :            :     {
     755                 :            :       // TODO: this should go somewhere else
     756                 :          0 :       QgsRasterShader *shader = new QgsRasterShader();
     757                 :          0 :       QgsColorRampShader *colorRampShader = new QgsColorRampShader();
     758                 :          0 :       colorRampShader->setColorRampType( QgsColorRampShader::Interpolated );
     759                 :          0 :       colorRampShader->setColorRampItemList( colorTable );
     760                 :          0 :       shader->setRasterShaderFunction( colorRampShader );
     761                 :          0 :       r->setShader( shader );
     762                 :          0 :     }
     763                 :          0 :   }
     764                 :          0 :   else if ( mRasterType == Multiband )
     765                 :            :   {
     766                 :          0 :     setRendererForDrawingStyle( QgsRaster::MultiBandColor );  //sensible default
     767                 :          0 :   }
     768                 :            :   else                        //GrayOrUndefined
     769                 :            :   {
     770                 :          0 :     setRendererForDrawingStyle( QgsRaster::SingleBandGray );  //sensible default
     771                 :            :   }
     772                 :            : 
     773                 :            :   // Auto set alpha band
     774                 :          0 :   for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
     775                 :            :   {
     776                 :          0 :     if ( mDataProvider->colorInterpretation( bandNo ) == QgsRaster::AlphaBand )
     777                 :            :     {
     778                 :          0 :       if ( auto *lRenderer = mPipe.renderer() )
     779                 :            :       {
     780                 :          0 :         lRenderer->setAlphaBand( bandNo );
     781                 :          0 :       }
     782                 :          0 :       break;
     783                 :            :     }
     784                 :          0 :   }
     785                 :            : 
     786                 :            :   // brightness filter
     787                 :          0 :   QgsBrightnessContrastFilter *brightnessFilter = new QgsBrightnessContrastFilter();
     788                 :          0 :   mPipe.set( brightnessFilter );
     789                 :            : 
     790                 :            :   // hue/saturation filter
     791                 :          0 :   QgsHueSaturationFilter *hueSaturationFilter = new QgsHueSaturationFilter();
     792                 :          0 :   mPipe.set( hueSaturationFilter );
     793                 :            : 
     794                 :            :   // resampler (must be after renderer)
     795                 :          0 :   QgsRasterResampleFilter *resampleFilter = new QgsRasterResampleFilter();
     796                 :          0 :   mPipe.set( resampleFilter );
     797                 :            : 
     798                 :          0 :   if ( mDataProvider->providerCapabilities() & QgsRasterDataProvider::ProviderHintBenefitsFromResampling )
     799                 :            :   {
     800                 :          0 :     QgsSettings settings;
     801                 :          0 :     QString resampling = settings.value( QStringLiteral( "/Raster/defaultZoomedInResampling" ), QStringLiteral( "nearest neighbour" ) ).toString();
     802                 :          0 :     if ( resampling == QLatin1String( "bilinear" ) )
     803                 :            :     {
     804                 :          0 :       resampleFilter->setZoomedInResampler( new QgsBilinearRasterResampler() );
     805                 :          0 :       mDataProvider->setZoomedInResamplingMethod( QgsRasterDataProvider::ResamplingMethod::Bilinear );
     806                 :          0 :     }
     807                 :          0 :     else if ( resampling == QLatin1String( "cubic" ) )
     808                 :            :     {
     809                 :          0 :       resampleFilter->setZoomedInResampler( new QgsCubicRasterResampler() );
     810                 :          0 :       mDataProvider->setZoomedInResamplingMethod( QgsRasterDataProvider::ResamplingMethod::Cubic );
     811                 :          0 :     }
     812                 :          0 :     resampling = settings.value( QStringLiteral( "/Raster/defaultZoomedOutResampling" ), QStringLiteral( "nearest neighbour" ) ).toString();
     813                 :          0 :     if ( resampling == QLatin1String( "bilinear" ) )
     814                 :            :     {
     815                 :          0 :       resampleFilter->setZoomedOutResampler( new QgsBilinearRasterResampler() );
     816                 :          0 :       mDataProvider->setZoomedOutResamplingMethod( QgsRasterDataProvider::ResamplingMethod::Bilinear );
     817                 :          0 :     }
     818                 :            : 
     819                 :          0 :     const double maxOversampling = settings.value( QStringLiteral( "/Raster/defaultOversampling" ), 2.0 ).toDouble();
     820                 :          0 :     resampleFilter->setMaxOversampling( maxOversampling );
     821                 :          0 :     mDataProvider->setMaxOversampling( maxOversampling );
     822                 :            : 
     823                 :          0 :     if ( ( mDataProvider->providerCapabilities() & QgsRasterDataProvider::ProviderHintCanPerformProviderResampling ) &&
     824                 :          0 :          settings.value( QStringLiteral( "/Raster/defaultEarlyResampling" ), false ).toBool() )
     825                 :            :     {
     826                 :          0 :       setResamplingStage( QgsRasterPipe::ResamplingStage::Provider );
     827                 :          0 :     }
     828                 :            :     else
     829                 :            :     {
     830                 :          0 :       setResamplingStage( QgsRasterPipe::ResamplingStage::ResampleFilter );
     831                 :            :     }
     832                 :          0 :   }
     833                 :            : 
     834                 :            :   // projector (may be anywhere in pipe)
     835                 :          0 :   QgsRasterProjector *projector = new QgsRasterProjector;
     836                 :          0 :   mPipe.set( projector );
     837                 :            : 
     838                 :            :   // Set default identify format - use the richest format available
     839                 :          0 :   int capabilities = mDataProvider->capabilities();
     840                 :          0 :   QgsRaster::IdentifyFormat identifyFormat = QgsRaster::IdentifyFormatUndefined;
     841                 :          0 :   if ( capabilities & QgsRasterInterface::IdentifyHtml )
     842                 :            :   {
     843                 :            :     // HTML is usually richest
     844                 :          0 :     identifyFormat = QgsRaster::IdentifyFormatHtml;
     845                 :          0 :   }
     846                 :          0 :   else if ( capabilities & QgsRasterInterface::IdentifyFeature )
     847                 :            :   {
     848                 :          0 :     identifyFormat = QgsRaster::IdentifyFormatFeature;
     849                 :          0 :   }
     850                 :          0 :   else if ( capabilities & QgsRasterInterface::IdentifyText )
     851                 :            :   {
     852                 :          0 :     identifyFormat = QgsRaster::IdentifyFormatText;
     853                 :          0 :   }
     854                 :          0 :   else if ( capabilities & QgsRasterInterface::IdentifyValue )
     855                 :            :   {
     856                 :          0 :     identifyFormat = QgsRaster::IdentifyFormatValue;
     857                 :          0 :   }
     858                 :          0 :   setCustomProperty( QStringLiteral( "identify/format" ), QgsRasterDataProvider::identifyFormatName( identifyFormat ) );
     859                 :            : 
     860                 :            :   // Store timestamp
     861                 :            :   // TODO move to provider
     862                 :          0 :   mLastModified = lastModified( mDataSource );
     863                 :            : 
     864                 :            :   // Do a passthrough for the status bar text
     865                 :          0 :   connect( mDataProvider, &QgsRasterDataProvider::statusChanged, this, &QgsRasterLayer::statusChanged );
     866                 :            : 
     867                 :            :   //mark the layer as valid
     868                 :          0 :   setValid( true );
     869                 :            : 
     870                 :          0 :   if ( mDataProvider->supportsSubsetString() )
     871                 :          0 :     connect( this, &QgsRasterLayer::subsetStringChanged, this, &QgsMapLayer::configChanged, Qt::UniqueConnection );
     872                 :            :   else
     873                 :          0 :     disconnect( this, &QgsRasterLayer::subsetStringChanged, this, &QgsMapLayer::configChanged );
     874                 :            : 
     875                 :            : 
     876                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "exiting." ), 4 );
     877                 :            : 
     878                 :          0 : }
     879                 :            : 
     880                 :          0 : void QgsRasterLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
     881                 :            : {
     882                 :          0 :   bool hadRenderer( renderer() );
     883                 :            : 
     884                 :          0 :   QDomImplementation domImplementation;
     885                 :          0 :   QDomDocumentType documentType;
     886                 :          0 :   QString errorMsg;
     887                 :            : 
     888                 :            :   // Store the original style
     889                 :          0 :   if ( hadRenderer && ! loadDefaultStyleFlag )
     890                 :            :   {
     891                 :          0 :     documentType = domImplementation.createDocumentType(
     892                 :          0 :                      QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
     893                 :            : 
     894                 :          0 :     QDomDocument doc = QDomDocument( documentType );
     895                 :          0 :     QDomElement styleElem = doc.createElement( QStringLiteral( "qgis" ) );
     896                 :          0 :     styleElem.setAttribute( QStringLiteral( "version" ), Qgis::version() );
     897                 :          0 :     QgsReadWriteContext writeContext;
     898                 :          0 :     if ( ! writeSymbology( styleElem, doc, errorMsg, writeContext ) )
     899                 :            :     {
     900                 :          0 :       QgsDebugMsg( QStringLiteral( "Could not store symbology for layer %1: %2" )
     901                 :            :                    .arg( name(),
     902                 :            :                          errorMsg ) );
     903                 :          0 :     }
     904                 :            :     else
     905                 :            :     {
     906                 :          0 :       doc.appendChild( styleElem );
     907                 :            : 
     908                 :          0 :       mOriginalStyleDocument = doc;
     909                 :          0 :       mOriginalStyleElement = styleElem;
     910                 :            :     }
     911                 :          0 :   }
     912                 :            : 
     913                 :          0 :   if ( mDataProvider )
     914                 :          0 :     closeDataProvider();
     915                 :            : 
     916                 :          0 :   init();
     917                 :            : 
     918                 :          0 :   for ( int i = mPipe.size() - 1; i >= 0; --i )
     919                 :            :   {
     920                 :          0 :     mPipe.remove( i );
     921                 :          0 :   }
     922                 :            : 
     923                 :          0 :   mDataSource = dataSource;
     924                 :          0 :   mLayerName = baseName;
     925                 :            : 
     926                 :          0 :   QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
     927                 :          0 :   if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
     928                 :            :   {
     929                 :          0 :     flags |= QgsDataProvider::FlagTrustDataSource;
     930                 :          0 :   }
     931                 :            : 
     932                 :          0 :   setDataProvider( provider, options, flags );
     933                 :            : 
     934                 :          0 :   if ( mDataProvider )
     935                 :          0 :     mDataProvider->setDataSourceUri( mDataSource );
     936                 :            : 
     937                 :          0 :   if ( isValid() )
     938                 :            :   {
     939                 :            :     // load default style
     940                 :          0 :     bool defaultLoadedFlag = false;
     941                 :          0 :     bool restoredStyle = false;
     942                 :          0 :     if ( loadDefaultStyleFlag )
     943                 :            :     {
     944                 :          0 :       loadDefaultStyle( defaultLoadedFlag );
     945                 :          0 :     }
     946                 :          0 :     else if ( !mOriginalStyleElement.isNull() )  // Restore the style
     947                 :            :     {
     948                 :          0 :       QgsReadWriteContext readContext;
     949                 :          0 :       if ( ! readSymbology( mOriginalStyleElement, errorMsg, readContext ) )
     950                 :            :       {
     951                 :          0 :         QgsDebugMsg( QStringLiteral( "Could not restore symbology for layer %1: %2" )
     952                 :            :                      .arg( name() )
     953                 :            :                      .arg( errorMsg ) );
     954                 :            : 
     955                 :          0 :       }
     956                 :            :       else
     957                 :            :       {
     958                 :          0 :         restoredStyle = true;
     959                 :          0 :         emit repaintRequested();
     960                 :          0 :         emit styleChanged();
     961                 :          0 :         emit rendererChanged();
     962                 :            :       }
     963                 :          0 :     }
     964                 :            : 
     965                 :          0 :     if ( !defaultLoadedFlag && !restoredStyle )
     966                 :            :     {
     967                 :          0 :       setDefaultContrastEnhancement();
     968                 :          0 :     }
     969                 :          0 :   }
     970                 :          0 :   emit dataSourceChanged();
     971                 :          0 :   emit dataChanged();
     972                 :          0 : }
     973                 :            : 
     974                 :          0 : void QgsRasterLayer::closeDataProvider()
     975                 :            : {
     976                 :          0 :   setValid( false );
     977                 :          0 :   mPipe.remove( mDataProvider );
     978                 :          0 :   mDataProvider = nullptr;
     979                 :          0 : }
     980                 :            : 
     981                 :          0 : void QgsRasterLayer::computeMinMax( int band,
     982                 :            :                                     const QgsRasterMinMaxOrigin &mmo,
     983                 :            :                                     QgsRasterMinMaxOrigin::Limits limits,
     984                 :            :                                     const QgsRectangle &extent,
     985                 :            :                                     int sampleSize,
     986                 :            :                                     double &min, double &max )
     987                 :            : {
     988                 :            : 
     989                 :          0 :   min = std::numeric_limits<double>::quiet_NaN();
     990                 :          0 :   max = std::numeric_limits<double>::quiet_NaN();
     991                 :          0 :   if ( !mDataProvider )
     992                 :          0 :     return;
     993                 :            : 
     994                 :          0 :   if ( limits == QgsRasterMinMaxOrigin::MinMax )
     995                 :            :   {
     996                 :          0 :     QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Min | QgsRasterBandStats::Max, extent, sampleSize );
     997                 :            :     // Check if statistics were actually gathered, None means a failure
     998                 :          0 :     if ( myRasterBandStats.statsGathered == QgsRasterBandStats::Stats::None )
     999                 :            :     {
    1000                 :            :       // Best guess we can do
    1001                 :          0 :       switch ( mDataProvider->dataType( band ) )
    1002                 :            :       {
    1003                 :            :         case Qgis::DataType::Byte:
    1004                 :            :         {
    1005                 :          0 :           myRasterBandStats.minimumValue = 0;
    1006                 :          0 :           myRasterBandStats.maximumValue = 255;
    1007                 :          0 :           break;
    1008                 :            :         }
    1009                 :            :         case Qgis::DataType::UInt16:
    1010                 :            :         {
    1011                 :          0 :           myRasterBandStats.minimumValue = 0;
    1012                 :          0 :           myRasterBandStats.maximumValue = std::numeric_limits<uint16_t>::max();
    1013                 :          0 :           break;
    1014                 :            :         }
    1015                 :            :         case Qgis::DataType::UInt32:
    1016                 :            :         {
    1017                 :          0 :           myRasterBandStats.minimumValue = 0;
    1018                 :          0 :           myRasterBandStats.maximumValue = std::numeric_limits<uint32_t>::max();
    1019                 :          0 :           break;
    1020                 :            :         }
    1021                 :            :         case Qgis::DataType::Int16:
    1022                 :            :         case Qgis::DataType::CInt16:
    1023                 :            :         {
    1024                 :          0 :           myRasterBandStats.minimumValue = std::numeric_limits<int16_t>::lowest();
    1025                 :          0 :           myRasterBandStats.maximumValue = std::numeric_limits<int16_t>::max();
    1026                 :          0 :           break;
    1027                 :            :         }
    1028                 :            :         case Qgis::DataType::Int32:
    1029                 :            :         case Qgis::DataType::CInt32:
    1030                 :            :         {
    1031                 :          0 :           myRasterBandStats.minimumValue = std::numeric_limits<int32_t>::lowest();
    1032                 :          0 :           myRasterBandStats.maximumValue = std::numeric_limits<int32_t>::max();
    1033                 :          0 :           break;
    1034                 :            :         }
    1035                 :            :         case Qgis::DataType::Float32:
    1036                 :            :         case Qgis::DataType::CFloat32:
    1037                 :            :         {
    1038                 :          0 :           myRasterBandStats.minimumValue = std::numeric_limits<float_t>::lowest();
    1039                 :          0 :           myRasterBandStats.maximumValue = std::numeric_limits<float_t>::max();
    1040                 :          0 :           break;
    1041                 :            :         }
    1042                 :            :         case Qgis::DataType::Float64:
    1043                 :            :         case Qgis::DataType::CFloat64:
    1044                 :            :         {
    1045                 :          0 :           myRasterBandStats.minimumValue = std::numeric_limits<double_t>::lowest();
    1046                 :          0 :           myRasterBandStats.maximumValue = std::numeric_limits<double_t>::max();
    1047                 :          0 :           break;
    1048                 :            :         }
    1049                 :            :         case Qgis::DataType::ARGB32:
    1050                 :            :         case Qgis::DataType::ARGB32_Premultiplied:
    1051                 :            :         case Qgis::DataType::UnknownDataType:
    1052                 :            :         {
    1053                 :            :           // Nothing to guess
    1054                 :          0 :           break;
    1055                 :            :         }
    1056                 :            :       }
    1057                 :          0 :     }
    1058                 :          0 :     min = myRasterBandStats.minimumValue;
    1059                 :          0 :     max = myRasterBandStats.maximumValue;
    1060                 :          0 :   }
    1061                 :          0 :   else if ( limits == QgsRasterMinMaxOrigin::StdDev )
    1062                 :            :   {
    1063                 :          0 :     QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, extent, sampleSize );
    1064                 :          0 :     min = myRasterBandStats.mean - ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
    1065                 :          0 :     max = myRasterBandStats.mean + ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
    1066                 :          0 :   }
    1067                 :          0 :   else if ( limits == QgsRasterMinMaxOrigin::CumulativeCut )
    1068                 :            :   {
    1069                 :          0 :     const double myLower = mmo.cumulativeCutLower();
    1070                 :          0 :     const double myUpper = mmo.cumulativeCutUpper();
    1071                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ), 4 );
    1072                 :          0 :     mDataProvider->cumulativeCut( band, myLower, myUpper, min, max, extent, sampleSize );
    1073                 :          0 :   }
    1074                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "band = %1 min = %2 max = %3" ).arg( band ).arg( min ).arg( max ), 4 );
    1075                 :            : 
    1076                 :          0 : }
    1077                 :            : 
    1078                 :          0 : bool QgsRasterLayer::ignoreExtents() const
    1079                 :            : {
    1080                 :          0 :   return mDataProvider ? mDataProvider->ignoreExtents() : false;
    1081                 :            : }
    1082                 :            : 
    1083                 :          0 : QgsMapLayerTemporalProperties *QgsRasterLayer::temporalProperties()
    1084                 :            : {
    1085                 :          0 :   return mTemporalProperties;
    1086                 :            : }
    1087                 :            : 
    1088                 :          0 : void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm algorithm, QgsRasterMinMaxOrigin::Limits limits, const QgsRectangle &extent, int sampleSize, bool generateLookupTableFlag )
    1089                 :            : {
    1090                 :          0 :   setContrastEnhancement( algorithm,
    1091                 :          0 :                           limits,
    1092                 :          0 :                           extent,
    1093                 :          0 :                           sampleSize,
    1094                 :          0 :                           generateLookupTableFlag,
    1095                 :          0 :                           mPipe.renderer() );
    1096                 :          0 : }
    1097                 :            : 
    1098                 :          0 : void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm algorithm,
    1099                 :            :     QgsRasterMinMaxOrigin::Limits limits,
    1100                 :            :     const QgsRectangle &extent,
    1101                 :            :     int sampleSize,
    1102                 :            :     bool generateLookupTableFlag,
    1103                 :            :     QgsRasterRenderer *rasterRenderer )
    1104                 :            : {
    1105                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "theAlgorithm = %1 limits = %2 extent.isEmpty() = %3" ).arg( algorithm ).arg( limits ).arg( extent.isEmpty() ), 4 );
    1106                 :          0 :   if ( !rasterRenderer || !mDataProvider )
    1107                 :            :   {
    1108                 :          0 :     return;
    1109                 :            :   }
    1110                 :            : 
    1111                 :          0 :   QList<int> myBands;
    1112                 :          0 :   QList<QgsContrastEnhancement *> myEnhancements;
    1113                 :          0 :   QgsRasterMinMaxOrigin myMinMaxOrigin;
    1114                 :          0 :   QgsRasterRenderer *myRasterRenderer = nullptr;
    1115                 :          0 :   QgsSingleBandGrayRenderer *myGrayRenderer = nullptr;
    1116                 :          0 :   QgsSingleBandPseudoColorRenderer *myPseudoColorRenderer = nullptr;
    1117                 :          0 :   QgsMultiBandColorRenderer *myMultiBandRenderer = nullptr;
    1118                 :          0 :   QString rendererType  = rasterRenderer->type();
    1119                 :          0 :   if ( rendererType == QLatin1String( "singlebandgray" ) )
    1120                 :            :   {
    1121                 :          0 :     myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( rasterRenderer );
    1122                 :          0 :     if ( !myGrayRenderer )
    1123                 :            :     {
    1124                 :          0 :       return;
    1125                 :            :     }
    1126                 :          0 :     myBands << myGrayRenderer->grayBand();
    1127                 :          0 :     myRasterRenderer = myGrayRenderer;
    1128                 :          0 :     myMinMaxOrigin = myGrayRenderer->minMaxOrigin();
    1129                 :          0 :   }
    1130                 :          0 :   else if ( rendererType == QLatin1String( "multibandcolor" ) )
    1131                 :            :   {
    1132                 :          0 :     myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( rasterRenderer );
    1133                 :          0 :     if ( !myMultiBandRenderer )
    1134                 :            :     {
    1135                 :          0 :       return;
    1136                 :            :     }
    1137                 :          0 :     myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand();
    1138                 :          0 :     myRasterRenderer = myMultiBandRenderer;
    1139                 :          0 :     myMinMaxOrigin = myMultiBandRenderer->minMaxOrigin();
    1140                 :          0 :   }
    1141                 :          0 :   else if ( rendererType == QLatin1String( "singlebandpseudocolor" ) )
    1142                 :            :   {
    1143                 :          0 :     myPseudoColorRenderer = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( rasterRenderer );
    1144                 :          0 :     if ( !myPseudoColorRenderer )
    1145                 :            :     {
    1146                 :          0 :       return;
    1147                 :            :     }
    1148                 :          0 :     myBands << myPseudoColorRenderer->band();
    1149                 :          0 :     myRasterRenderer = myPseudoColorRenderer;
    1150                 :          0 :     myMinMaxOrigin = myPseudoColorRenderer->minMaxOrigin();
    1151                 :          0 :   }
    1152                 :            :   else
    1153                 :            :   {
    1154                 :          0 :     return;
    1155                 :            :   }
    1156                 :            : 
    1157                 :          0 :   const auto constMyBands = myBands;
    1158                 :          0 :   for ( int myBand : constMyBands )
    1159                 :            :   {
    1160                 :          0 :     if ( myBand != -1 )
    1161                 :            :     {
    1162                 :          0 :       Qgis::DataType myType = static_cast< Qgis::DataType >( mDataProvider->dataType( myBand ) );
    1163                 :          0 :       std::unique_ptr<QgsContrastEnhancement> myEnhancement( new QgsContrastEnhancement( static_cast< Qgis::DataType >( myType ) ) );
    1164                 :          0 :       myEnhancement->setContrastEnhancementAlgorithm( algorithm, generateLookupTableFlag );
    1165                 :            : 
    1166                 :            :       double min;
    1167                 :            :       double max;
    1168                 :          0 :       computeMinMax( myBand, myMinMaxOrigin, limits, extent, sampleSize, min, max );
    1169                 :            : 
    1170                 :          0 :       if ( rendererType == QLatin1String( "singlebandpseudocolor" ) )
    1171                 :            :       {
    1172                 :          0 :         myPseudoColorRenderer->setClassificationMin( min );
    1173                 :          0 :         myPseudoColorRenderer->setClassificationMax( max );
    1174                 :          0 :         if ( myPseudoColorRenderer->shader() )
    1175                 :            :         {
    1176                 :          0 :           QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( myPseudoColorRenderer->shader()->rasterShaderFunction() );
    1177                 :          0 :           if ( colorRampShader )
    1178                 :            :           {
    1179                 :          0 :             colorRampShader->classifyColorRamp( myPseudoColorRenderer->band(), extent, myPseudoColorRenderer->input() );
    1180                 :          0 :           }
    1181                 :          0 :         }
    1182                 :          0 :       }
    1183                 :            :       else
    1184                 :            :       {
    1185                 :          0 :         myEnhancement->setMinimumValue( min );
    1186                 :          0 :         myEnhancement->setMaximumValue( max );
    1187                 :          0 :         myEnhancements.append( myEnhancement.release() );
    1188                 :            :       }
    1189                 :          0 :     }
    1190                 :            :     else
    1191                 :            :     {
    1192                 :          0 :       myEnhancements.append( nullptr );
    1193                 :            :     }
    1194                 :            :   }
    1195                 :            : 
    1196                 :          0 :   if ( rendererType == QLatin1String( "singlebandgray" ) )
    1197                 :            :   {
    1198                 :          0 :     if ( myEnhancements.first() ) myGrayRenderer->setContrastEnhancement( myEnhancements.takeFirst() );
    1199                 :          0 :   }
    1200                 :          0 :   else if ( rendererType == QLatin1String( "multibandcolor" ) )
    1201                 :            :   {
    1202                 :          0 :     if ( myEnhancements.first() ) myMultiBandRenderer->setRedContrastEnhancement( myEnhancements.takeFirst() );
    1203                 :          0 :     if ( myEnhancements.first() ) myMultiBandRenderer->setGreenContrastEnhancement( myEnhancements.takeFirst() );
    1204                 :          0 :     if ( myEnhancements.first() ) myMultiBandRenderer->setBlueContrastEnhancement( myEnhancements.takeFirst() );
    1205                 :          0 :   }
    1206                 :            : 
    1207                 :            :   //delete all remaining unused enhancements
    1208                 :          0 :   qDeleteAll( myEnhancements );
    1209                 :            : 
    1210                 :          0 :   myMinMaxOrigin.setLimits( limits );
    1211                 :          0 :   if ( extent != QgsRectangle() &&
    1212                 :          0 :        myMinMaxOrigin.extent() == QgsRasterMinMaxOrigin::WholeRaster )
    1213                 :            :   {
    1214                 :          0 :     myMinMaxOrigin.setExtent( QgsRasterMinMaxOrigin::CurrentCanvas );
    1215                 :          0 :   }
    1216                 :          0 :   if ( myRasterRenderer )
    1217                 :            :   {
    1218                 :          0 :     myRasterRenderer->setMinMaxOrigin( myMinMaxOrigin );
    1219                 :          0 :   }
    1220                 :            : 
    1221                 :          0 :   if ( rasterRenderer == renderer() )
    1222                 :            :   {
    1223                 :          0 :     emit repaintRequested();
    1224                 :          0 :     emit styleChanged();
    1225                 :          0 :     emit rendererChanged();
    1226                 :          0 :   }
    1227                 :          0 : }
    1228                 :            : 
    1229                 :          0 : void QgsRasterLayer::refreshContrastEnhancement( const QgsRectangle &extent )
    1230                 :            : {
    1231                 :          0 :   QgsSingleBandGrayRenderer *singleBandRenderer = nullptr;
    1232                 :          0 :   QgsMultiBandColorRenderer *multiBandRenderer = nullptr;
    1233                 :          0 :   const QgsContrastEnhancement *ce = nullptr;
    1234                 :          0 :   if ( ( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer() ) ) )
    1235                 :            :   {
    1236                 :          0 :     ce = singleBandRenderer->contrastEnhancement();
    1237                 :          0 :   }
    1238                 :          0 :   else if ( ( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( renderer() ) ) )
    1239                 :            :   {
    1240                 :          0 :     ce = multiBandRenderer->redContrastEnhancement();
    1241                 :          0 :   }
    1242                 :            : 
    1243                 :          0 :   if ( ce )
    1244                 :            :   {
    1245                 :          0 :     setContrastEnhancement( ce->contrastEnhancementAlgorithm() == QgsContrastEnhancement::NoEnhancement ?
    1246                 :          0 :                             QgsContrastEnhancement::StretchToMinimumMaximum : ce->contrastEnhancementAlgorithm(),
    1247                 :          0 :                             renderer()->minMaxOrigin().limits() == QgsRasterMinMaxOrigin::None ?
    1248                 :          0 :                             QgsRasterMinMaxOrigin::MinMax : renderer()->minMaxOrigin().limits(),
    1249                 :          0 :                             extent,
    1250                 :            :                             SAMPLE_SIZE,
    1251                 :            :                             true,
    1252                 :          0 :                             renderer() );
    1253                 :          0 :   }
    1254                 :            :   else
    1255                 :            :   {
    1256                 :            :     QgsContrastEnhancement::ContrastEnhancementAlgorithm myAlgorithm;
    1257                 :            :     QgsRasterMinMaxOrigin::Limits myLimits;
    1258                 :          0 :     if ( defaultContrastEnhancementSettings( myAlgorithm, myLimits ) )
    1259                 :            :     {
    1260                 :          0 :       setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum,
    1261                 :          0 :                               myLimits,
    1262                 :          0 :                               extent,
    1263                 :            :                               SAMPLE_SIZE,
    1264                 :            :                               true,
    1265                 :          0 :                               renderer() );
    1266                 :          0 :     }
    1267                 :            :   }
    1268                 :          0 : }
    1269                 :            : 
    1270                 :          0 : void QgsRasterLayer::refreshRendererIfNeeded( QgsRasterRenderer *rasterRenderer,
    1271                 :            :     const QgsRectangle &extent )
    1272                 :            : {
    1273                 :          0 :   if ( mDataProvider &&
    1274                 :          0 :        mLastRectangleUsedByRefreshContrastEnhancementIfNeeded != extent &&
    1275                 :          0 :        rasterRenderer->minMaxOrigin().limits() != QgsRasterMinMaxOrigin::None &&
    1276                 :          0 :        rasterRenderer->minMaxOrigin().extent() == QgsRasterMinMaxOrigin::UpdatedCanvas )
    1277                 :            :   {
    1278                 :          0 :     refreshRenderer( rasterRenderer, extent );
    1279                 :          0 :   }
    1280                 :          0 : }
    1281                 :            : 
    1282                 :          0 : void QgsRasterLayer::refreshRenderer( QgsRasterRenderer *rasterRenderer, const QgsRectangle &extent )
    1283                 :            : {
    1284                 :          0 :   if ( mDataProvider )
    1285                 :            :   {
    1286                 :          0 :     QgsSingleBandGrayRenderer *singleBandRenderer = nullptr;
    1287                 :          0 :     QgsMultiBandColorRenderer *multiBandRenderer = nullptr;
    1288                 :          0 :     QgsSingleBandPseudoColorRenderer *sbpcr = nullptr;
    1289                 :          0 :     const QgsContrastEnhancement *ce = nullptr;
    1290                 :          0 :     if ( ( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer *>( rasterRenderer ) ) )
    1291                 :            :     {
    1292                 :          0 :       ce = singleBandRenderer->contrastEnhancement();
    1293                 :          0 :     }
    1294                 :          0 :     else if ( ( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer *>( rasterRenderer ) ) )
    1295                 :            :     {
    1296                 :          0 :       ce = multiBandRenderer->redContrastEnhancement();
    1297                 :          0 :     }
    1298                 :          0 :     else if ( ( sbpcr = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( rasterRenderer ) ) )
    1299                 :            :     {
    1300                 :          0 :       mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = extent;
    1301                 :            :       double min;
    1302                 :            :       double max;
    1303                 :          0 :       computeMinMax( sbpcr->band(),
    1304                 :          0 :                      rasterRenderer->minMaxOrigin(),
    1305                 :          0 :                      rasterRenderer->minMaxOrigin().limits(), extent,
    1306                 :            :                      SAMPLE_SIZE, min, max );
    1307                 :          0 :       sbpcr->setClassificationMin( min );
    1308                 :          0 :       sbpcr->setClassificationMax( max );
    1309                 :            : 
    1310                 :          0 :       if ( sbpcr->shader() )
    1311                 :            :       {
    1312                 :          0 :         QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( sbpcr->shader()->rasterShaderFunction() );
    1313                 :          0 :         if ( colorRampShader )
    1314                 :            :         {
    1315                 :          0 :           colorRampShader->classifyColorRamp( sbpcr->band(), extent, rasterRenderer->input() );
    1316                 :          0 :         }
    1317                 :          0 :       }
    1318                 :            : 
    1319                 :          0 :       QgsSingleBandPseudoColorRenderer *r = dynamic_cast<QgsSingleBandPseudoColorRenderer *>( renderer() );
    1320                 :          0 :       r->setClassificationMin( min );
    1321                 :          0 :       r->setClassificationMax( max );
    1322                 :            : 
    1323                 :          0 :       if ( r->shader() )
    1324                 :            :       {
    1325                 :          0 :         QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( r->shader()->rasterShaderFunction() );
    1326                 :          0 :         if ( colorRampShader )
    1327                 :            :         {
    1328                 :          0 :           colorRampShader->classifyColorRamp( sbpcr->band(), extent, rasterRenderer->input() );
    1329                 :          0 :         }
    1330                 :          0 :       }
    1331                 :            : 
    1332                 :          0 :       emit repaintRequested();
    1333                 :          0 :       emit styleChanged();
    1334                 :          0 :       emit rendererChanged();
    1335                 :          0 :       return;
    1336                 :            :     }
    1337                 :            : 
    1338                 :          0 :     if ( ce &&
    1339                 :          0 :          ce->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement )
    1340                 :            :     {
    1341                 :          0 :       mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = extent;
    1342                 :            : 
    1343                 :          0 :       setContrastEnhancement( ce->contrastEnhancementAlgorithm(),
    1344                 :          0 :                               rasterRenderer->minMaxOrigin().limits(),
    1345                 :          0 :                               extent,
    1346                 :            :                               SAMPLE_SIZE,
    1347                 :            :                               true,
    1348                 :          0 :                               rasterRenderer );
    1349                 :            : 
    1350                 :            :       // Update main renderer so that the legends get updated
    1351                 :          0 :       if ( singleBandRenderer )
    1352                 :          0 :         static_cast<QgsSingleBandGrayRenderer *>( renderer() )->setContrastEnhancement( new QgsContrastEnhancement( * singleBandRenderer->contrastEnhancement() ) );
    1353                 :          0 :       else if ( multiBandRenderer )
    1354                 :            :       {
    1355                 :          0 :         if ( multiBandRenderer->redContrastEnhancement() )
    1356                 :            :         {
    1357                 :          0 :           static_cast<QgsMultiBandColorRenderer *>( renderer() )->setRedContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->redContrastEnhancement() ) );
    1358                 :          0 :         }
    1359                 :          0 :         if ( multiBandRenderer->greenContrastEnhancement() )
    1360                 :            :         {
    1361                 :          0 :           static_cast<QgsMultiBandColorRenderer *>( renderer() )->setGreenContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->greenContrastEnhancement() ) );
    1362                 :          0 :         }
    1363                 :          0 :         if ( multiBandRenderer->blueContrastEnhancement() )
    1364                 :            :         {
    1365                 :          0 :           static_cast<QgsMultiBandColorRenderer *>( renderer() )->setBlueContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->blueContrastEnhancement() ) );
    1366                 :          0 :         }
    1367                 :          0 :       }
    1368                 :            : 
    1369                 :          0 :       emit styleChanged();
    1370                 :          0 :       emit rendererChanged();
    1371                 :          0 :     }
    1372                 :          0 :   }
    1373                 :          0 : }
    1374                 :            : 
    1375                 :          0 : QString QgsRasterLayer::subsetString() const
    1376                 :            : {
    1377                 :          0 :   if ( !isValid() || !mDataProvider )
    1378                 :            :   {
    1379                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
    1380                 :          0 :     return customProperty( QStringLiteral( "storedSubsetString" ) ).toString();
    1381                 :            :   }
    1382                 :          0 :   if ( !mDataProvider->supportsSubsetString() )
    1383                 :            :   {
    1384                 :          0 :     return QString();
    1385                 :            :   }
    1386                 :          0 :   return mDataProvider->subsetString();
    1387                 :          0 : }
    1388                 :            : 
    1389                 :          0 : bool QgsRasterLayer::setSubsetString( const QString &subset )
    1390                 :            : {
    1391                 :          0 :   if ( !isValid() || !mDataProvider )
    1392                 :            :   {
    1393                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider or while editing" ), 3 );
    1394                 :          0 :     setCustomProperty( QStringLiteral( "storedSubsetString" ), subset );
    1395                 :          0 :     return false;
    1396                 :            :   }
    1397                 :            : 
    1398                 :          0 :   if ( !mDataProvider->supportsSubsetString() )
    1399                 :            :   {
    1400                 :          0 :     return false;
    1401                 :            :   }
    1402                 :            : 
    1403                 :          0 :   if ( subset == mDataProvider->subsetString() )
    1404                 :          0 :     return true;
    1405                 :            : 
    1406                 :          0 :   bool res = mDataProvider->setSubsetString( subset );
    1407                 :            : 
    1408                 :            :   // get the updated data source string from the provider
    1409                 :          0 :   mDataSource = mDataProvider->dataSourceUri();
    1410                 :            : 
    1411                 :          0 :   if ( res )
    1412                 :            :   {
    1413                 :          0 :     setExtent( mDataProvider->extent() );
    1414                 :          0 :     refreshRenderer( renderer(), extent() );
    1415                 :          0 :     emit subsetStringChanged();
    1416                 :          0 :   }
    1417                 :            : 
    1418                 :          0 :   return res;
    1419                 :          0 : }
    1420                 :            : 
    1421                 :          0 : bool QgsRasterLayer::defaultContrastEnhancementSettings(
    1422                 :            :   QgsContrastEnhancement::ContrastEnhancementAlgorithm &myAlgorithm,
    1423                 :            :   QgsRasterMinMaxOrigin::Limits &myLimits ) const
    1424                 :            : {
    1425                 :          0 :   QgsSettings mySettings;
    1426                 :            : 
    1427                 :          0 :   QString key;
    1428                 :          0 :   QString defaultAlg;
    1429                 :          0 :   QString defaultLimits;
    1430                 :            : 
    1431                 :            :   // TODO: we should not test renderer class here, move it somehow to renderers
    1432                 :          0 :   if ( dynamic_cast<QgsSingleBandGrayRenderer *>( renderer() ) )
    1433                 :            :   {
    1434                 :          0 :     key = QStringLiteral( "singleBand" );
    1435                 :          0 :     defaultAlg = QgsContrastEnhancement::contrastEnhancementAlgorithmString(
    1436                 :            :                    SINGLE_BAND_ENHANCEMENT_ALGORITHM );
    1437                 :          0 :     defaultLimits = QgsRasterMinMaxOrigin::limitsString(
    1438                 :            :                       SINGLE_BAND_MIN_MAX_LIMITS );
    1439                 :          0 :   }
    1440                 :          0 :   else if ( dynamic_cast<QgsMultiBandColorRenderer *>( renderer() ) )
    1441                 :            :   {
    1442                 :          0 :     if ( QgsRasterBlock::typeSize( dataProvider()->sourceDataType( 1 ) ) == 1 )
    1443                 :            :     {
    1444                 :          0 :       key = QStringLiteral( "multiBandSingleByte" );
    1445                 :          0 :       defaultAlg = QgsContrastEnhancement::contrastEnhancementAlgorithmString(
    1446                 :            :                      MULTIPLE_BAND_SINGLE_BYTE_ENHANCEMENT_ALGORITHM );
    1447                 :          0 :       defaultLimits = QgsRasterMinMaxOrigin::limitsString(
    1448                 :            :                         MULTIPLE_BAND_SINGLE_BYTE_MIN_MAX_LIMITS );
    1449                 :          0 :     }
    1450                 :            :     else
    1451                 :            :     {
    1452                 :          0 :       key = QStringLiteral( "multiBandMultiByte" );
    1453                 :          0 :       defaultAlg = QgsContrastEnhancement::contrastEnhancementAlgorithmString(
    1454                 :            :                      MULTIPLE_BAND_MULTI_BYTE_ENHANCEMENT_ALGORITHM );
    1455                 :          0 :       defaultLimits = QgsRasterMinMaxOrigin::limitsString(
    1456                 :            :                         MULTIPLE_BAND_MULTI_BYTE_MIN_MAX_LIMITS );
    1457                 :            :     }
    1458                 :          0 :   }
    1459                 :            : 
    1460                 :          0 :   if ( key.isEmpty() )
    1461                 :            :   {
    1462                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "No default contrast enhancement for this drawing style" ), 2 );
    1463                 :          0 :     myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( QString() );
    1464                 :          0 :     myLimits = QgsRasterMinMaxOrigin::limitsFromString( QString() );
    1465                 :          0 :     return false;
    1466                 :            :   }
    1467                 :          0 :   QgsDebugMsgLevel( "key = " + key, 4 );
    1468                 :            : 
    1469                 :          0 :   QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + key, defaultAlg ).toString();
    1470                 :          0 :   QgsDebugMsgLevel( "myAlgorithmString = " + myAlgorithmString, 4 );
    1471                 :            : 
    1472                 :          0 :   myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( myAlgorithmString );
    1473                 :            : 
    1474                 :          0 :   QString myLimitsString = mySettings.value( "/Raster/defaultContrastEnhancementLimits/" + key, defaultLimits ).toString();
    1475                 :          0 :   QgsDebugMsgLevel( "myLimitsString = " + myLimitsString, 4 );
    1476                 :          0 :   myLimits = QgsRasterMinMaxOrigin::limitsFromString( myLimitsString );
    1477                 :            : 
    1478                 :          0 :   return true;
    1479                 :          0 : }
    1480                 :            : 
    1481                 :          0 : void QgsRasterLayer::setDefaultContrastEnhancement()
    1482                 :            : {
    1483                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
    1484                 :            : 
    1485                 :            :   QgsContrastEnhancement::ContrastEnhancementAlgorithm myAlgorithm;
    1486                 :            :   QgsRasterMinMaxOrigin::Limits myLimits;
    1487                 :          0 :   defaultContrastEnhancementSettings( myAlgorithm, myLimits );
    1488                 :            : 
    1489                 :          0 :   setContrastEnhancement( myAlgorithm, myLimits );
    1490                 :          0 : }
    1491                 :            : 
    1492                 :          0 : void QgsRasterLayer::setLayerOrder( QStringList const &layers )
    1493                 :            : {
    1494                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
    1495                 :            : 
    1496                 :          0 :   if ( mDataProvider )
    1497                 :            :   {
    1498                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "About to mDataProvider->setLayerOrder(layers)." ), 4 );
    1499                 :          0 :     mDataProvider->setLayerOrder( layers );
    1500                 :          0 :   }
    1501                 :            : 
    1502                 :          0 : }
    1503                 :            : 
    1504                 :          0 : void QgsRasterLayer::setSubLayerVisibility( const QString &name, bool vis )
    1505                 :            : {
    1506                 :            : 
    1507                 :          0 :   if ( mDataProvider )
    1508                 :            :   {
    1509                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "About to mDataProvider->setSubLayerVisibility(name, vis)." ), 4 );
    1510                 :          0 :     mDataProvider->setSubLayerVisibility( name, vis );
    1511                 :          0 :   }
    1512                 :            : 
    1513                 :          0 : }
    1514                 :            : 
    1515                 :          0 : QDateTime QgsRasterLayer::timestamp() const
    1516                 :            : {
    1517                 :          0 :   if ( !mDataProvider )
    1518                 :          0 :     return QDateTime();
    1519                 :          0 :   return mDataProvider->timestamp();
    1520                 :          0 : }
    1521                 :            : 
    1522                 :          0 : bool QgsRasterLayer::accept( QgsStyleEntityVisitorInterface *visitor ) const
    1523                 :            : {
    1524                 :          0 :   if ( auto *lRenderer = mPipe.renderer() )
    1525                 :            :   {
    1526                 :          0 :     if ( !lRenderer->accept( visitor ) )
    1527                 :          0 :       return false;
    1528                 :          0 :   }
    1529                 :          0 :   return true;
    1530                 :          0 : }
    1531                 :            : 
    1532                 :            : 
    1533                 :          0 : bool QgsRasterLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props ) const
    1534                 :            : {
    1535                 :          0 :   Q_UNUSED( errorMessage )
    1536                 :            : 
    1537                 :          0 :   QVariantMap localProps = QVariantMap( props );
    1538                 :          0 :   if ( hasScaleBasedVisibility() )
    1539                 :            :   {
    1540                 :            :     // TODO: QgsSymbolLayerUtils::mergeScaleDependencies generate SE only and not SLD1.0
    1541                 :          0 :     QgsSymbolLayerUtils::mergeScaleDependencies( maximumScale(), minimumScale(), localProps );
    1542                 :          0 :   }
    1543                 :            : 
    1544                 :          0 :   if ( isSpatial() ) // TODO: does it make sense this control?
    1545                 :            :   {
    1546                 :            :     // store constraints
    1547                 :          0 :     QDomElement constraintElem = doc.createElement( QStringLiteral( "sld:LayerFeatureConstraints" ) );
    1548                 :          0 :     node.appendChild( constraintElem );
    1549                 :            : 
    1550                 :          0 :     QDomElement featureTypeConstraintElem = doc.createElement( QStringLiteral( "sld:FeatureTypeConstraint" ) );
    1551                 :          0 :     constraintElem.appendChild( featureTypeConstraintElem );
    1552                 :            : 
    1553                 :          0 :     QDomElement userStyleElem = doc.createElement( QStringLiteral( "sld:UserStyle" ) );
    1554                 :          0 :     node.appendChild( userStyleElem );
    1555                 :            : 
    1556                 :          0 :     if ( !name().isEmpty() )
    1557                 :            :     {
    1558                 :          0 :       QDomElement nameElem = doc.createElement( QStringLiteral( "sld:Name" ) );
    1559                 :          0 :       nameElem.appendChild( doc.createTextNode( name() ) );
    1560                 :          0 :       userStyleElem.appendChild( nameElem );
    1561                 :          0 :     }
    1562                 :            : 
    1563                 :          0 :     if ( !abstract().isEmpty() )
    1564                 :            :     {
    1565                 :          0 :       QDomElement abstractElem = doc.createElement( QStringLiteral( "sld:Abstract" ) );
    1566                 :          0 :       abstractElem.appendChild( doc.createTextNode( abstract() ) );
    1567                 :          0 :       userStyleElem.appendChild( abstractElem );
    1568                 :          0 :     }
    1569                 :            : 
    1570                 :          0 :     if ( !title().isEmpty() )
    1571                 :            :     {
    1572                 :          0 :       QDomElement titleElem = doc.createElement( QStringLiteral( "sld:Title" ) );
    1573                 :          0 :       titleElem.appendChild( doc.createTextNode( title() ) );
    1574                 :          0 :       userStyleElem.appendChild( titleElem );
    1575                 :          0 :     }
    1576                 :            : 
    1577                 :          0 :     QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "sld:FeatureTypeStyle" ) );
    1578                 :          0 :     userStyleElem.appendChild( featureTypeStyleElem );
    1579                 :            : 
    1580                 :            : #if 0
    1581                 :            :     // TODO: Is there a way to fill it's value with the named style?
    1582                 :            :     // by default <sld:Name> under <sld:FeatureTypeStyle> can have 0 occurrences
    1583                 :            :     // the same happen for tags:
    1584                 :            :     // sld:Title
    1585                 :            :     // sld:Abstract
    1586                 :            :     // sld:FeatureTypeName
    1587                 :            :     // sld:SemanticTypeIdentifier
    1588                 :            :     QDomElement typeStyleNameElem = doc.createElement( QStringLiteral( "sld:Name" ) );
    1589                 :            :     featureTypeStyleElem.appendChild( typeStyleNameElem );
    1590                 :            : #endif
    1591                 :            : 
    1592                 :          0 :     QDomElement typeStyleRuleElem = doc.createElement( QStringLiteral( "sld:Rule" ) );
    1593                 :          0 :     featureTypeStyleElem.appendChild( typeStyleRuleElem );
    1594                 :            : 
    1595                 :            :     // add ScaleDenominator tags
    1596                 :          0 :     if ( hasScaleBasedVisibility() )
    1597                 :            :     {
    1598                 :            :       // note that denominator is the inverted value of scale
    1599                 :          0 :       if ( maximumScale() != 0.0 )
    1600                 :            :       {
    1601                 :          0 :         QDomElement minScaleElem = doc.createElement( QStringLiteral( "sld:MinScaleDenominator" ) );
    1602                 :          0 :         minScaleElem.appendChild( doc.createTextNode( QString::number( maximumScale() ) ) );
    1603                 :          0 :         typeStyleRuleElem.appendChild( minScaleElem );
    1604                 :          0 :       }
    1605                 :            : 
    1606                 :          0 :       QDomElement maxScaleElem = doc.createElement( QStringLiteral( "sld:MaxScaleDenominator" ) );
    1607                 :          0 :       maxScaleElem.appendChild( doc.createTextNode( QString::number( minimumScale() ) ) );
    1608                 :          0 :       typeStyleRuleElem.appendChild( maxScaleElem );
    1609                 :          0 :     }
    1610                 :            : 
    1611                 :            :     // export renderer dependent tags
    1612                 :          0 :     mPipe.renderer()->toSld( doc, typeStyleRuleElem, localProps );
    1613                 :            : 
    1614                 :            :     // inject raster layer parameters in RasterSymbolizer tag because
    1615                 :            :     // they belongs to rasterlayer and not to the renderer => avoid to
    1616                 :            :     // pass many parameters value via localProps
    1617                 :          0 :     QDomNodeList elements = typeStyleRuleElem.elementsByTagName( QStringLiteral( "sld:RasterSymbolizer" ) );
    1618                 :          0 :     if ( elements.size() != 0 )
    1619                 :            :     {
    1620                 :            :       // there SHOULD be only one
    1621                 :          0 :       QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
    1622                 :            : 
    1623                 :            :       // lamda helper used below to reduce code redundancy
    1624                 :          0 :       auto vendorOptionWriter = [&]( QString name, QString value )
    1625                 :            :       {
    1626                 :          0 :         QDomElement vendorOptionElem = doc.createElement( QStringLiteral( "sld:VendorOption" ) );
    1627                 :          0 :         vendorOptionElem.setAttribute( QStringLiteral( "name" ), name );
    1628                 :          0 :         vendorOptionElem.appendChild( doc.createTextNode( value ) );
    1629                 :          0 :         rasterSymbolizerElem.appendChild( vendorOptionElem );
    1630                 :          0 :       };
    1631                 :            : 
    1632                 :            :       // add greyScale rendering mode if set
    1633                 :          0 :       if ( hueSaturationFilter()->grayscaleMode() != QgsHueSaturationFilter::GrayscaleOff )
    1634                 :            :       {
    1635                 :          0 :         QString property;
    1636                 :          0 :         switch ( hueSaturationFilter()->grayscaleMode() )
    1637                 :            :         {
    1638                 :            :           case QgsHueSaturationFilter::GrayscaleLightness:
    1639                 :          0 :             property = QStringLiteral( "lightness" );
    1640                 :          0 :             break;
    1641                 :            :           case QgsHueSaturationFilter::GrayscaleLuminosity:
    1642                 :          0 :             property = QStringLiteral( "luminosity" );
    1643                 :          0 :             break;
    1644                 :            :           case QgsHueSaturationFilter::GrayscaleAverage:
    1645                 :          0 :             property = QStringLiteral( "average" );
    1646                 :          0 :             break;
    1647                 :            :           case QgsHueSaturationFilter::GrayscaleOff:
    1648                 :            :             // added just to avoid travis fail
    1649                 :          0 :             break;
    1650                 :            :         }
    1651                 :          0 :         if ( !property.isEmpty() )
    1652                 :          0 :           vendorOptionWriter( QStringLiteral( "grayScale" ), property );
    1653                 :          0 :       }
    1654                 :            : 
    1655                 :            :       // add Hue, Saturation and Lighting values in props is Hue filter is set
    1656                 :          0 :       if ( hueSaturationFilter() && hueSaturationFilter()->colorizeOn() )
    1657                 :            :       {
    1658                 :          0 :         vendorOptionWriter( QStringLiteral( "colorizeOn" ), QString::number( hueSaturationFilter()->colorizeOn() ) );
    1659                 :          0 :         vendorOptionWriter( QStringLiteral( "colorizeRed" ), QString::number( hueSaturationFilter()->colorizeColor().red() ) );
    1660                 :          0 :         vendorOptionWriter( QStringLiteral( "colorizeGreen" ), QString::number( hueSaturationFilter()->colorizeColor().green() ) );
    1661                 :          0 :         vendorOptionWriter( QStringLiteral( "colorizeBlue" ), QString::number( hueSaturationFilter()->colorizeColor().blue() ) );
    1662                 :          0 :         if ( hueSaturationFilter()->colorizeStrength() != 100.0 )
    1663                 :          0 :           vendorOptionWriter( QStringLiteral( "colorizeStrength" ), QString::number( hueSaturationFilter()->colorizeStrength() / 100.0 ) );
    1664                 :          0 :         vendorOptionWriter( QStringLiteral( "saturation" ), QString::number( hueSaturationFilter()->colorizeColor().saturationF() ) );
    1665                 :          0 :       }
    1666                 :            :       else
    1667                 :            :       {
    1668                 :            :         // saturation != 0 (default value)
    1669                 :          0 :         if ( hueSaturationFilter()->saturation() != 0 )
    1670                 :            :         {
    1671                 :            :           // normlize value [-100:100] -> [0:1]
    1672                 :          0 :           int s = hueSaturationFilter()->saturation();
    1673                 :          0 :           double sF = ( s - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
    1674                 :          0 :           vendorOptionWriter( QStringLiteral( "saturation" ), QString::number( sF ) );
    1675                 :          0 :         }
    1676                 :            :       }
    1677                 :            : 
    1678                 :            :       // brightness != 0 (default value)
    1679                 :          0 :       if ( brightnessFilter()->brightness() != 0 )
    1680                 :            :       {
    1681                 :            :         // normalize value [-255:255] -> [0:1]
    1682                 :          0 :         int b = brightnessFilter()->brightness();
    1683                 :          0 :         double bF = ( b - ( -255.0 ) ) / ( 255.0 - ( -255.0 ) );
    1684                 :          0 :         vendorOptionWriter( QStringLiteral( "brightness" ), QString::number( bF ) );
    1685                 :          0 :       }
    1686                 :            : 
    1687                 :            :       // contrast != 0 (default value)
    1688                 :          0 :       if ( brightnessFilter()->contrast() != 0 )
    1689                 :            :       {
    1690                 :            :         // normlize value [-100:100] -> [0:1]
    1691                 :          0 :         int c = brightnessFilter()->contrast();
    1692                 :          0 :         double cF = ( c - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
    1693                 :          0 :         vendorOptionWriter( QStringLiteral( "contrast" ), QString::number( cF ) );
    1694                 :          0 :       }
    1695                 :            : 
    1696                 :            : #if 0
    1697                 :            :       // TODO: check if the below mapping formula make sense to map QGIS contrast with SLD gamma value
    1698                 :            :       //
    1699                 :            :       // add SLD1.0 ContrastEnhancement GammaValue = QGIS Contrast
    1700                 :            :       // SLD1.0 does only define 1 as neutral/center double value but does not define range.
    1701                 :            :       // because https://en.wikipedia.org/wiki/Gamma_correction assumed gamma is >0.
    1702                 :            :       // whilst QGIS has a -100/100 values centered in 0 => QGIS contrast value will be scaled in the
    1703                 :            :       // following way:
    1704                 :            :       // [-100,0] => [0,1] and [0,100] => [1,100]
    1705                 :            :       // an alternative could be scale [-100,100] => (0,2]
    1706                 :            :       //
    1707                 :            :       if ( newProps.contains( QStringLiteral( "contrast" ) ) )
    1708                 :            :       {
    1709                 :            :         double gamma;
    1710                 :            :         double contrast = newProps[ QStringLiteral( "contrast" ) ].toDouble();
    1711                 :            :         double percentage = ( contrast - ( -100.0 ) ) / ( 100.0 - ( -100.0 ) );
    1712                 :            :         if ( percentage <= 0.5 )
    1713                 :            :         {
    1714                 :            :           // stretch % to [0-1]
    1715                 :            :           gamma = percentage / 0.5;
    1716                 :            :         }
    1717                 :            :         else
    1718                 :            :         {
    1719                 :            :           gamma = contrast;
    1720                 :            :         }
    1721                 :            : 
    1722                 :            :         QDomElement globalContrastEnhancementElem = doc.createElement( QStringLiteral( "sld:ContrastEnhancement" ) );
    1723                 :            :         rasterSymolizerElem.appendChild( globalContrastEnhancementElem );
    1724                 :            : 
    1725                 :            :         QDomElement gammaValueElem = doc.createElement( QStringLiteral( "sld:GammaValue" ) );
    1726                 :            :         gammaValueElem.appendChild( doc.createTextNode( QString::number( gamma ) ) );
    1727                 :            :         globalContrastEnhancementElem.appendChild( gammaValueElem );
    1728                 :            :       }
    1729                 :            : #endif
    1730                 :          0 :     }
    1731                 :          0 :   }
    1732                 :            :   return true;
    1733                 :          0 : }
    1734                 :            : 
    1735                 :            : 
    1736                 :          0 : void QgsRasterLayer::setRenderer( QgsRasterRenderer *renderer )
    1737                 :            : {
    1738                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
    1739                 :          0 :   if ( !renderer )
    1740                 :            :   {
    1741                 :          0 :     return;
    1742                 :            :   }
    1743                 :            : 
    1744                 :          0 :   mPipe.set( renderer );
    1745                 :          0 :   emit rendererChanged();
    1746                 :          0 :   emit styleChanged();
    1747                 :          0 : }
    1748                 :            : 
    1749                 :          0 : void QgsRasterLayer::showStatusMessage( QString const &message )
    1750                 :            : {
    1751                 :            :   // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage));
    1752                 :            : 
    1753                 :            :   // Pass-through
    1754                 :            :   // TODO: See if we can connect signal-to-signal.  This is a kludge according to the Qt doc.
    1755                 :          0 :   emit statusChanged( message );
    1756                 :          0 : }
    1757                 :            : 
    1758                 :          0 : void QgsRasterLayer::setTransformContext( const QgsCoordinateTransformContext &transformContext )
    1759                 :            : {
    1760                 :          0 :   if ( mDataProvider )
    1761                 :          0 :     mDataProvider->setTransformContext( transformContext );
    1762                 :          0 :   invalidateWgs84Extent();
    1763                 :          0 : }
    1764                 :            : 
    1765                 :          0 : QStringList QgsRasterLayer::subLayers() const
    1766                 :            : {
    1767                 :          0 :   if ( ! mDataProvider )
    1768                 :          0 :     return QStringList();
    1769                 :          0 :   return mDataProvider->subLayers();
    1770                 :          0 : }
    1771                 :            : 
    1772                 :            : // this function should be used when rendering with the MTR engine introduced in 2.3, as QPixmap is not thread safe (see bug #9626)
    1773                 :            : // note: previewAsImage and previewAsPixmap should use a common low-level fct QgsRasterLayer::previewOnPaintDevice( QSize size, QColor bgColor, QPaintDevice &device )
    1774                 :          0 : QImage QgsRasterLayer::previewAsImage( QSize size, const QColor &bgColor, QImage::Format format )
    1775                 :            : {
    1776                 :          0 :   QImage image( size, format );
    1777                 :            : 
    1778                 :          0 :   if ( ! isValid( ) )
    1779                 :          0 :     return  QImage();
    1780                 :            : 
    1781                 :          0 :   if ( image.format() == QImage::Format_Indexed8 )
    1782                 :            :   {
    1783                 :          0 :     image.setColor( 0, bgColor.rgba() );
    1784                 :          0 :     image.fill( 0 );  //defaults to white, set to transparent for rendering on a map
    1785                 :          0 :   }
    1786                 :            :   else
    1787                 :            :   {
    1788                 :          0 :     image.fill( bgColor );
    1789                 :            :   }
    1790                 :            : 
    1791                 :          0 :   QgsRasterViewPort *rasterViewPort = new QgsRasterViewPort();
    1792                 :            : 
    1793                 :            :   double mapUnitsPerPixel;
    1794                 :          0 :   double x = 0.0;
    1795                 :          0 :   double y = 0.0;
    1796                 :          0 :   QgsRectangle extent = mDataProvider->extent();
    1797                 :          0 :   if ( extent.width() / extent.height() >= static_cast< double >( image.width() ) / image.height() )
    1798                 :            :   {
    1799                 :          0 :     mapUnitsPerPixel = extent.width() / image.width();
    1800                 :          0 :     y = ( image.height() - extent.height() / mapUnitsPerPixel ) / 2;
    1801                 :          0 :   }
    1802                 :            :   else
    1803                 :            :   {
    1804                 :          0 :     mapUnitsPerPixel = extent.height() / image.height();
    1805                 :          0 :     x = ( image.width() - extent.width() / mapUnitsPerPixel ) / 2;
    1806                 :            :   }
    1807                 :            : 
    1808                 :          0 :   const double pixelWidth = extent.width() / mapUnitsPerPixel;
    1809                 :          0 :   const double pixelHeight = extent.height() / mapUnitsPerPixel;
    1810                 :            : 
    1811                 :          0 :   rasterViewPort->mTopLeftPoint = QgsPointXY( x, y );
    1812                 :          0 :   rasterViewPort->mBottomRightPoint = QgsPointXY( pixelWidth, pixelHeight );
    1813                 :          0 :   rasterViewPort->mWidth = image.width();
    1814                 :          0 :   rasterViewPort->mHeight = image.height();
    1815                 :            : 
    1816                 :          0 :   rasterViewPort->mDrawnExtent = extent;
    1817                 :          0 :   rasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
    1818                 :          0 :   rasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
    1819                 :            : 
    1820                 :          0 :   QgsMapToPixel *mapToPixel = new QgsMapToPixel( mapUnitsPerPixel );
    1821                 :            : 
    1822                 :          0 :   QPainter *painter = new QPainter( &image );
    1823                 :          0 :   draw( painter, rasterViewPort, mapToPixel );
    1824                 :          0 :   delete rasterViewPort;
    1825                 :          0 :   delete mapToPixel;
    1826                 :            : 
    1827                 :          0 :   painter->end();
    1828                 :          0 :   delete painter;
    1829                 :            : 
    1830                 :          0 :   return image;
    1831                 :          0 : }
    1832                 :            : 
    1833                 :            : //////////////////////////////////////////////////////////
    1834                 :            : //
    1835                 :            : // Protected methods
    1836                 :            : //
    1837                 :            : /////////////////////////////////////////////////////////
    1838                 :            : /*
    1839                 :            :  * \param QDomNode node that will contain the symbology definition for this layer.
    1840                 :            :  * \param errorMessage reference to string that will be updated with any error messages
    1841                 :            :  * \return TRUE in case of success.
    1842                 :            :  */
    1843                 :          0 : bool QgsRasterLayer::readSymbology( const QDomNode &layer_node, QString &errorMessage,
    1844                 :            :                                     QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
    1845                 :            : {
    1846                 :          0 :   Q_UNUSED( errorMessage )
    1847                 :            :   // TODO: implement categories for raster layer
    1848                 :            : 
    1849                 :          0 :   QDomElement rasterRendererElem;
    1850                 :            : 
    1851                 :          0 :   QDomElement layerElement = layer_node.toElement();
    1852                 :          0 :   readCommonStyle( layerElement, context, categories );
    1853                 :            : 
    1854                 :            :   // pipe element was introduced in the end of 1.9 development when there were
    1855                 :            :   // already many project files in use so we support 1.9 backward compatibility
    1856                 :            :   // even it was never officially released -> use pipe element if present, otherwise
    1857                 :            :   // use layer node
    1858                 :          0 :   QDomNode pipeNode = layer_node.firstChildElement( QStringLiteral( "pipe" ) );
    1859                 :          0 :   if ( pipeNode.isNull() ) // old project
    1860                 :            :   {
    1861                 :          0 :     pipeNode = layer_node;
    1862                 :          0 :   }
    1863                 :            : 
    1864                 :            :   //rasterlayerproperties element there -> old format (1.8 and early 1.9)
    1865                 :          0 :   if ( !layer_node.firstChildElement( QStringLiteral( "rasterproperties" ) ).isNull() )
    1866                 :            :   {
    1867                 :            :     //copy node because layer_node is const
    1868                 :          0 :     QDomNode layerNodeCopy = layer_node.cloneNode();
    1869                 :          0 :     QDomDocument doc = layerNodeCopy.ownerDocument();
    1870                 :          0 :     QDomElement rasterPropertiesElem = layerNodeCopy.firstChildElement( QStringLiteral( "rasterproperties" ) );
    1871                 :          0 :     QgsProjectFileTransform::convertRasterProperties( doc, layerNodeCopy, rasterPropertiesElem,
    1872                 :            :         this );
    1873                 :          0 :     rasterRendererElem = layerNodeCopy.firstChildElement( QStringLiteral( "rasterrenderer" ) );
    1874                 :          0 :     QgsDebugMsgLevel( doc.toString(), 4 );
    1875                 :          0 :   }
    1876                 :            :   else
    1877                 :            :   {
    1878                 :          0 :     rasterRendererElem = pipeNode.firstChildElement( QStringLiteral( "rasterrenderer" ) );
    1879                 :            :   }
    1880                 :            : 
    1881                 :          0 :   if ( !rasterRendererElem.isNull() )
    1882                 :            :   {
    1883                 :          0 :     QString rendererType = rasterRendererElem.attribute( QStringLiteral( "type" ) );
    1884                 :          0 :     QgsRasterRendererRegistryEntry rendererEntry;
    1885                 :          0 :     if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererType, rendererEntry ) )
    1886                 :            :     {
    1887                 :          0 :       QgsRasterRenderer *renderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() );
    1888                 :          0 :       mPipe.set( renderer );
    1889                 :          0 :     }
    1890                 :          0 :   }
    1891                 :            : 
    1892                 :            :   //brightness
    1893                 :          0 :   QgsBrightnessContrastFilter *brightnessFilter = new QgsBrightnessContrastFilter();
    1894                 :          0 :   mPipe.set( brightnessFilter );
    1895                 :            : 
    1896                 :            :   //brightness coefficient
    1897                 :          0 :   QDomElement brightnessElem = pipeNode.firstChildElement( QStringLiteral( "brightnesscontrast" ) );
    1898                 :          0 :   if ( !brightnessElem.isNull() )
    1899                 :            :   {
    1900                 :          0 :     brightnessFilter->readXml( brightnessElem );
    1901                 :          0 :   }
    1902                 :            : 
    1903                 :            :   //hue/saturation
    1904                 :          0 :   QgsHueSaturationFilter *hueSaturationFilter = new QgsHueSaturationFilter();
    1905                 :          0 :   mPipe.set( hueSaturationFilter );
    1906                 :            : 
    1907                 :            :   //saturation coefficient
    1908                 :          0 :   QDomElement hueSaturationElem = pipeNode.firstChildElement( QStringLiteral( "huesaturation" ) );
    1909                 :          0 :   if ( !hueSaturationElem.isNull() )
    1910                 :            :   {
    1911                 :          0 :     hueSaturationFilter->readXml( hueSaturationElem );
    1912                 :          0 :   }
    1913                 :            : 
    1914                 :            :   //resampler
    1915                 :          0 :   QgsRasterResampleFilter *resampleFilter = new QgsRasterResampleFilter();
    1916                 :          0 :   mPipe.set( resampleFilter );
    1917                 :            : 
    1918                 :            :   //max oversampling
    1919                 :          0 :   QDomElement resampleElem = pipeNode.firstChildElement( QStringLiteral( "rasterresampler" ) );
    1920                 :          0 :   if ( !resampleElem.isNull() )
    1921                 :            :   {
    1922                 :          0 :     resampleFilter->readXml( resampleElem );
    1923                 :          0 :   }
    1924                 :            : 
    1925                 :            :   //provider
    1926                 :          0 :   if ( mDataProvider )
    1927                 :            :   {
    1928                 :          0 :     QDomElement providerElem = pipeNode.firstChildElement( QStringLiteral( "provider" ) );
    1929                 :          0 :     if ( !providerElem.isNull() )
    1930                 :            :     {
    1931                 :          0 :       mDataProvider->readXml( providerElem );
    1932                 :          0 :     }
    1933                 :          0 :   }
    1934                 :            : 
    1935                 :            :   // Resampling stage
    1936                 :          0 :   QDomNode resamplingStageElement = pipeNode.namedItem( QStringLiteral( "resamplingStage" ) );
    1937                 :          0 :   if ( !resamplingStageElement.isNull() )
    1938                 :            :   {
    1939                 :          0 :     QDomElement e = resamplingStageElement.toElement();
    1940                 :          0 :     if ( e.text() == QLatin1String( "provider" ) )
    1941                 :          0 :       setResamplingStage( QgsRasterPipe::ResamplingStage::Provider );
    1942                 :          0 :     else if ( e.text() == QLatin1String( "resamplingFilter" ) )
    1943                 :          0 :       setResamplingStage( QgsRasterPipe::ResamplingStage::ResampleFilter );
    1944                 :          0 :   }
    1945                 :            : 
    1946                 :            :   // get and set the blend mode if it exists
    1947                 :          0 :   QDomNode blendModeNode = layer_node.namedItem( QStringLiteral( "blendMode" ) );
    1948                 :          0 :   if ( !blendModeNode.isNull() )
    1949                 :            :   {
    1950                 :          0 :     QDomElement e = blendModeNode.toElement();
    1951                 :          0 :     setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
    1952                 :          0 :   }
    1953                 :            : 
    1954                 :          0 :   readCustomProperties( layer_node );
    1955                 :            : 
    1956                 :            :   return true;
    1957                 :          0 : }
    1958                 :            : 
    1959                 :          0 : bool QgsRasterLayer::readStyle( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
    1960                 :            : {
    1961                 :          0 :   return readSymbology( node, errorMessage, context, categories );
    1962                 :            : }
    1963                 :            : 
    1964                 :          0 : bool QgsRasterLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
    1965                 :            : {
    1966                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
    1967                 :            :   // Make sure to read the file first so stats etc are initialized properly!
    1968                 :            : 
    1969                 :            :   //process provider key
    1970                 :          0 :   QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
    1971                 :            : 
    1972                 :          0 :   if ( pkeyNode.isNull() )
    1973                 :            :   {
    1974                 :          0 :     mProviderKey = QStringLiteral( "gdal" );
    1975                 :          0 :   }
    1976                 :            :   else
    1977                 :            :   {
    1978                 :          0 :     QDomElement pkeyElt = pkeyNode.toElement();
    1979                 :          0 :     mProviderKey = pkeyElt.text();
    1980                 :          0 :     if ( mProviderKey.isEmpty() )
    1981                 :            :     {
    1982                 :          0 :       mProviderKey = QStringLiteral( "gdal" );
    1983                 :          0 :     }
    1984                 :          0 :   }
    1985                 :            : 
    1986                 :            :   // Open the raster source based on provider and datasource
    1987                 :            : 
    1988                 :            :   // Go down the raster-data-provider paradigm
    1989                 :            : 
    1990                 :            :   // Collect provider-specific information
    1991                 :            : 
    1992                 :          0 :   QDomNode rpNode = layer_node.namedItem( QStringLiteral( "rasterproperties" ) );
    1993                 :            : 
    1994                 :          0 :   if ( mProviderKey == QLatin1String( "wms" ) )
    1995                 :            :   {
    1996                 :            :     // >>> BACKWARD COMPATIBILITY < 1.9
    1997                 :            :     // The old WMS URI format does not contain all the information, we add them here.
    1998                 :          0 :     if ( !mDataSource.contains( QLatin1String( "crs=" ) ) && !mDataSource.contains( QLatin1String( "format=" ) ) )
    1999                 :            :     {
    2000                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "Old WMS URI format detected -> adding params" ), 4 );
    2001                 :          0 :       QgsDataSourceUri uri;
    2002                 :          0 :       uri.setEncodedUri( mDataSource );
    2003                 :          0 :       QDomElement layerElement = rpNode.firstChildElement( QStringLiteral( "wmsSublayer" ) );
    2004                 :          0 :       while ( !layerElement.isNull() )
    2005                 :            :       {
    2006                 :            :         // TODO: sublayer visibility - post-0.8 release timeframe
    2007                 :            : 
    2008                 :            :         // collect name for the sublayer
    2009                 :          0 :         uri.setParam( QStringLiteral( "layers" ),  layerElement.namedItem( QStringLiteral( "name" ) ).toElement().text() );
    2010                 :            : 
    2011                 :            :         // collect style for the sublayer
    2012                 :          0 :         uri.setParam( QStringLiteral( "styles" ), layerElement.namedItem( QStringLiteral( "style" ) ).toElement().text() );
    2013                 :            : 
    2014                 :          0 :         layerElement = layerElement.nextSiblingElement( QStringLiteral( "wmsSublayer" ) );
    2015                 :            :       }
    2016                 :            : 
    2017                 :            :       // Collect format
    2018                 :          0 :       uri.setParam( QStringLiteral( "format" ), rpNode.namedItem( QStringLiteral( "wmsFormat" ) ).toElement().text() );
    2019                 :            : 
    2020                 :            :       // WMS CRS URL param should not be mixed with that assigned to the layer.
    2021                 :            :       // In the old WMS URI version there was no CRS and layer crs().authid() was used.
    2022                 :          0 :       uri.setParam( QStringLiteral( "crs" ), crs().authid() );
    2023                 :          0 :       mDataSource = uri.encodedUri();
    2024                 :          0 :     }
    2025                 :            :     // <<< BACKWARD COMPATIBILITY < 1.9
    2026                 :          0 :   }
    2027                 :            : 
    2028                 :          0 :   if ( !( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) )
    2029                 :            :   {
    2030                 :          0 :     QgsDataProvider::ProviderOptions providerOptions { context.transformContext() };
    2031                 :          0 :     QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
    2032                 :          0 :     if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
    2033                 :            :     {
    2034                 :          0 :       flags |= QgsDataProvider::FlagTrustDataSource;
    2035                 :          0 :     }
    2036                 :          0 :     setDataProvider( mProviderKey, providerOptions, flags );
    2037                 :          0 :   }
    2038                 :            : 
    2039                 :          0 :   mOriginalStyleElement = layer_node.namedItem( QStringLiteral( "originalStyle" ) ).firstChildElement();
    2040                 :          0 :   if ( mOriginalStyleElement.isNull() )
    2041                 :          0 :     mOriginalStyleElement = layer_node.toElement();
    2042                 :          0 :   mOriginalStyleDocument = layer_node.ownerDocument();
    2043                 :            : 
    2044                 :          0 :   if ( ! mDataProvider )
    2045                 :            :   {
    2046                 :          0 :     if ( !( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) )
    2047                 :            :     {
    2048                 :          0 :       QgsDebugMsg( QStringLiteral( "Raster data provider could not be created for %1" ).arg( mDataSource ) );
    2049                 :          0 :     }
    2050                 :          0 :     return false;
    2051                 :            :   }
    2052                 :            : 
    2053                 :          0 :   QString error;
    2054                 :          0 :   bool res = readSymbology( layer_node, error, context );
    2055                 :            : 
    2056                 :            :   // old wms settings we need to correct
    2057                 :          0 :   if ( res && mProviderKey == QLatin1String( "wms" ) && ( !renderer() || renderer()->type() != QLatin1String( "singlebandcolordata" ) ) )
    2058                 :            :   {
    2059                 :          0 :     setRendererForDrawingStyle( QgsRaster::SingleBandColorDataStyle );
    2060                 :          0 :   }
    2061                 :            : 
    2062                 :            :   // Check timestamp
    2063                 :            :   // This was probably introduced to reload completely raster if data changed and
    2064                 :            :   // reset completely symbology to reflect new data type etc. It creates however
    2065                 :            :   // problems, because user defined symbology is complete lost if data file time
    2066                 :            :   // changed (the content may be the same). See also 6900.
    2067                 :            : #if 0
    2068                 :            :   QDomNode stampNode = layer_node.namedItem( "timestamp" );
    2069                 :            :   if ( !stampNode.isNull() )
    2070                 :            :   {
    2071                 :            :     QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate );
    2072                 :            :     // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static?
    2073                 :            :     if ( stamp < mDataProvider->dataTimestamp() )
    2074                 :            :     {
    2075                 :            :       QgsDebugMsgLevel( QStringLiteral( "data changed, reload provider" ), 3 );
    2076                 :            :       closeDataProvider();
    2077                 :            :       init();
    2078                 :            :       setDataProvider( mProviderKey );
    2079                 :            :       if ( !isValid() ) return false;
    2080                 :            :     }
    2081                 :            :   }
    2082                 :            : #endif
    2083                 :            : 
    2084                 :            :   // Load user no data value
    2085                 :          0 :   QDomElement noDataElement = layer_node.firstChildElement( QStringLiteral( "noData" ) );
    2086                 :            : 
    2087                 :          0 :   QDomNodeList noDataBandList = noDataElement.elementsByTagName( QStringLiteral( "noDataList" ) );
    2088                 :            : 
    2089                 :          0 :   for ( int i = 0; i < noDataBandList.size(); ++i )
    2090                 :            :   {
    2091                 :          0 :     QDomElement bandElement = noDataBandList.at( i ).toElement();
    2092                 :            :     bool ok;
    2093                 :          0 :     int bandNo = bandElement.attribute( QStringLiteral( "bandNo" ) ).toInt( &ok );
    2094                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "bandNo = %1" ).arg( bandNo ), 4 );
    2095                 :          0 :     if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) )
    2096                 :            :     {
    2097                 :          0 :       mDataProvider->setUseSourceNoDataValue( bandNo, bandElement.attribute( QStringLiteral( "useSrcNoData" ) ).toInt() );
    2098                 :          0 :       QgsRasterRangeList myNoDataRangeList;
    2099                 :            : 
    2100                 :          0 :       QDomNodeList rangeList = bandElement.elementsByTagName( QStringLiteral( "noDataRange" ) );
    2101                 :            : 
    2102                 :          0 :       myNoDataRangeList.reserve( rangeList.size() );
    2103                 :          0 :       for ( int j = 0; j < rangeList.size(); ++j )
    2104                 :            :       {
    2105                 :          0 :         QDomElement rangeElement = rangeList.at( j ).toElement();
    2106                 :          0 :         QgsRasterRange myNoDataRange( rangeElement.attribute( QStringLiteral( "min" ) ).toDouble(),
    2107                 :          0 :                                       rangeElement.attribute( QStringLiteral( "max" ) ).toDouble() );
    2108                 :          0 :         QgsDebugMsgLevel( QStringLiteral( "min = %1 %2" ).arg( rangeElement.attribute( "min" ) ).arg( myNoDataRange.min() ), 4 );
    2109                 :          0 :         myNoDataRangeList << myNoDataRange;
    2110                 :          0 :       }
    2111                 :          0 :       mDataProvider->setUserNoDataValue( bandNo, myNoDataRangeList );
    2112                 :          0 :     }
    2113                 :          0 :   }
    2114                 :            : 
    2115                 :          0 :   readStyleManager( layer_node );
    2116                 :            : 
    2117                 :          0 :   return res;
    2118                 :          0 : }
    2119                 :            : 
    2120                 :          0 : bool QgsRasterLayer::writeSymbology( QDomNode &layer_node, QDomDocument &document, QString &errorMessage,
    2121                 :            :                                      const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
    2122                 :            : {
    2123                 :          0 :   Q_UNUSED( errorMessage )
    2124                 :            :   // TODO: implement categories for raster layer
    2125                 :            : 
    2126                 :          0 :   QDomElement layerElement = layer_node.toElement();
    2127                 :          0 :   writeCommonStyle( layerElement, document, context, categories );
    2128                 :            : 
    2129                 :            :   // Store pipe members into pipe element, in future, it will be
    2130                 :            :   // possible to add custom filters into the pipe
    2131                 :          0 :   QDomElement pipeElement  = document.createElement( QStringLiteral( "pipe" ) );
    2132                 :            : 
    2133                 :          0 :   for ( int i = 0; i < mPipe.size(); i++ )
    2134                 :            :   {
    2135                 :          0 :     QgsRasterInterface *interface = mPipe.at( i );
    2136                 :          0 :     if ( !interface ) continue;
    2137                 :          0 :     interface->writeXml( document, pipeElement );
    2138                 :          0 :   }
    2139                 :            : 
    2140                 :          0 :   QDomElement resamplingStageElement = document.createElement( QStringLiteral( "resamplingStage" ) );
    2141                 :          0 :   QDomText resamplingStageText = document.createTextNode( resamplingStage() == QgsRasterPipe::ResamplingStage::Provider ? QStringLiteral( "provider" ) : QStringLiteral( "resamplingFilter" ) );
    2142                 :          0 :   resamplingStageElement.appendChild( resamplingStageText );
    2143                 :          0 :   pipeElement.appendChild( resamplingStageElement );
    2144                 :            : 
    2145                 :          0 :   layer_node.appendChild( pipeElement );
    2146                 :            : 
    2147                 :          0 :   if ( !isValid() && !mOriginalStyleElement.isNull() )
    2148                 :            :   {
    2149                 :          0 :     QDomElement originalStyleElement = document.createElement( QStringLiteral( "originalStyle" ) );
    2150                 :          0 :     originalStyleElement.appendChild( mOriginalStyleElement );
    2151                 :          0 :     layer_node.appendChild( originalStyleElement );
    2152                 :          0 :   }
    2153                 :            : 
    2154                 :            :   // add blend mode node
    2155                 :          0 :   QDomElement blendModeElement  = document.createElement( QStringLiteral( "blendMode" ) );
    2156                 :          0 :   QDomText blendModeText = document.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
    2157                 :          0 :   blendModeElement.appendChild( blendModeText );
    2158                 :          0 :   layer_node.appendChild( blendModeElement );
    2159                 :            : 
    2160                 :            :   return true;
    2161                 :          0 : }
    2162                 :            : 
    2163                 :          0 : bool QgsRasterLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
    2164                 :            :                                  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
    2165                 :            : {
    2166                 :          0 :   return writeSymbology( node, doc, errorMessage, context, categories );
    2167                 :            : } // bool QgsRasterLayer::writeSymbology
    2168                 :            : 
    2169                 :            : /*
    2170                 :            :  *  virtual
    2171                 :            :  *  \note Called by QgsMapLayer::writeXml().
    2172                 :            :  */
    2173                 :          0 : bool QgsRasterLayer::writeXml( QDomNode &layer_node,
    2174                 :            :                                QDomDocument &document,
    2175                 :            :                                const QgsReadWriteContext &context ) const
    2176                 :            : {
    2177                 :            :   // first get the layer element so that we can append the type attribute
    2178                 :            : 
    2179                 :          0 :   QDomElement mapLayerNode = layer_node.toElement();
    2180                 :            : 
    2181                 :          0 :   if ( mapLayerNode.isNull() || "maplayer" != mapLayerNode.nodeName() )
    2182                 :            :   {
    2183                 :          0 :     QgsMessageLog::logMessage( tr( "<maplayer> not found." ), tr( "Raster" ) );
    2184                 :          0 :     return false;
    2185                 :            :   }
    2186                 :            : 
    2187                 :          0 :   mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::RasterLayer ) );
    2188                 :            : 
    2189                 :            :   // add provider node
    2190                 :            : 
    2191                 :          0 :   QDomElement provider  = document.createElement( QStringLiteral( "provider" ) );
    2192                 :          0 :   QDomText providerText = document.createTextNode( mProviderKey );
    2193                 :          0 :   provider.appendChild( providerText );
    2194                 :          0 :   layer_node.appendChild( provider );
    2195                 :            : 
    2196                 :            :   // User no data
    2197                 :          0 :   QDomElement noData  = document.createElement( QStringLiteral( "noData" ) );
    2198                 :            : 
    2199                 :          0 :   for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ )
    2200                 :            :   {
    2201                 :          0 :     QDomElement noDataRangeList = document.createElement( QStringLiteral( "noDataList" ) );
    2202                 :          0 :     noDataRangeList.setAttribute( QStringLiteral( "bandNo" ), bandNo );
    2203                 :          0 :     noDataRangeList.setAttribute( QStringLiteral( "useSrcNoData" ), mDataProvider->useSourceNoDataValue( bandNo ) );
    2204                 :            : 
    2205                 :          0 :     const auto constUserNoDataValues = mDataProvider->userNoDataValues( bandNo );
    2206                 :          0 :     for ( QgsRasterRange range : constUserNoDataValues )
    2207                 :            :     {
    2208                 :          0 :       QDomElement noDataRange = document.createElement( QStringLiteral( "noDataRange" ) );
    2209                 :            : 
    2210                 :          0 :       noDataRange.setAttribute( QStringLiteral( "min" ), QgsRasterBlock::printValue( range.min() ) );
    2211                 :          0 :       noDataRange.setAttribute( QStringLiteral( "max" ), QgsRasterBlock::printValue( range.max() ) );
    2212                 :          0 :       noDataRangeList.appendChild( noDataRange );
    2213                 :          0 :     }
    2214                 :            : 
    2215                 :          0 :     noData.appendChild( noDataRangeList );
    2216                 :            : 
    2217                 :          0 :   }
    2218                 :          0 :   if ( noData.hasChildNodes() )
    2219                 :            :   {
    2220                 :          0 :     layer_node.appendChild( noData );
    2221                 :          0 :   }
    2222                 :            : 
    2223                 :          0 :   writeStyleManager( layer_node, document );
    2224                 :            : 
    2225                 :            :   //write out the symbology
    2226                 :          0 :   QString errorMsg;
    2227                 :          0 :   return writeSymbology( layer_node, document, errorMsg, context );
    2228                 :          0 : }
    2229                 :            : 
    2230                 :            : // TODO: this should ideally go to gdal provider (together with most of encodedSource() + decodedSource())
    2231                 :          0 : static bool _parseGpkgColons( const QString &src, QString &filename, QString &tablename )
    2232                 :            : {
    2233                 :            :   // GDAL accepts the following input format:  GPKG:filename:table
    2234                 :            :   // (GDAL won't accept quoted filename)
    2235                 :            : 
    2236                 :          0 :   QStringList lst = src.split( ':' );
    2237                 :          0 :   if ( lst.count() != 3 && lst.count() != 4 )
    2238                 :          0 :     return false;
    2239                 :            : 
    2240                 :          0 :   tablename = lst.last();
    2241                 :          0 :   if ( lst.count() == 3 )
    2242                 :            :   {
    2243                 :          0 :     filename = lst[1];
    2244                 :          0 :     return true;
    2245                 :            :   }
    2246                 :          0 :   else if ( lst.count() == 4 && lst[1].count() == 1 && ( lst[2][0] == '/' || lst[2][0] == '\\' ) )
    2247                 :            :   {
    2248                 :            :     // a bit of handling to make sure that filename C:\hello.gpkg is parsed correctly
    2249                 :          0 :     filename = lst[1] + ":" + lst[2];
    2250                 :          0 :     return true;
    2251                 :            :   }
    2252                 :          0 :   return false;
    2253                 :          0 : }
    2254                 :            : 
    2255                 :            : 
    2256                 :          0 : QString QgsRasterLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
    2257                 :            : {
    2258                 :          0 :   QString src( source );
    2259                 :          0 :   bool handled = false;
    2260                 :            : 
    2261                 :            :   // Update path for subdataset
    2262                 :          0 :   if ( providerType() == QLatin1String( "gdal" ) )
    2263                 :            :   {
    2264                 :          0 :     if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
    2265                 :            :     {
    2266                 :            :       // NETCDF:filename:variable
    2267                 :            :       // filename can be quoted with " as it can contain colons
    2268                 :          0 :       QRegExp r( "NETCDF:(.+):([^:]+)" );
    2269                 :          0 :       if ( r.exactMatch( src ) )
    2270                 :            :       {
    2271                 :          0 :         QString filename = r.cap( 1 );
    2272                 :          0 :         if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
    2273                 :          0 :           filename = filename.mid( 1, filename.length() - 2 );
    2274                 :          0 :         src = "NETCDF:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
    2275                 :          0 :         handled = true;
    2276                 :          0 :       }
    2277                 :          0 :     }
    2278                 :          0 :     else if ( src.startsWith( QLatin1String( "GPKG:" ) ) )
    2279                 :            :     {
    2280                 :            :       // GPKG:filename:table
    2281                 :          0 :       QString filename, tablename;
    2282                 :          0 :       if ( _parseGpkgColons( src, filename, tablename ) )
    2283                 :            :       {
    2284                 :          0 :         filename = context.pathResolver().writePath( filename );
    2285                 :          0 :         src = QStringLiteral( "GPKG:%1:%2" ).arg( filename, tablename );
    2286                 :          0 :         handled = true;
    2287                 :          0 :       }
    2288                 :          0 :     }
    2289                 :          0 :     else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
    2290                 :            :     {
    2291                 :            :       // HDF4_SDS:subdataset_type:file_name:subdataset_index
    2292                 :            :       // filename can be quoted with " as it can contain colons
    2293                 :          0 :       QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
    2294                 :          0 :       if ( r.exactMatch( src ) )
    2295                 :            :       {
    2296                 :          0 :         QString filename = r.cap( 2 );
    2297                 :          0 :         if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
    2298                 :          0 :           filename = filename.mid( 1, filename.length() - 2 );
    2299                 :          0 :         src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 3 );
    2300                 :          0 :         handled = true;
    2301                 :          0 :       }
    2302                 :          0 :     }
    2303                 :          0 :     else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
    2304                 :            :     {
    2305                 :            :       // HDF5:file_name:subdataset
    2306                 :            :       // filename can be quoted with " as it can contain colons
    2307                 :          0 :       QRegExp r( "HDF5:(.+):([^:]+)" );
    2308                 :          0 :       if ( r.exactMatch( src ) )
    2309                 :            :       {
    2310                 :          0 :         QString filename = r.cap( 1 );
    2311                 :          0 :         if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
    2312                 :          0 :           filename = filename.mid( 1, filename.length() - 2 );
    2313                 :          0 :         src = "HDF5:\"" + context.pathResolver().writePath( filename ) + "\":" + r.cap( 2 );
    2314                 :          0 :         handled = true;
    2315                 :          0 :       }
    2316                 :          0 :     }
    2317                 :          0 :     else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
    2318                 :            :     {
    2319                 :            :       // NITF_IM:0:filename
    2320                 :            :       // RADARSAT_2_CALIB:?:filename
    2321                 :          0 :       QRegExp r( "([^:]+):([^:]+):(.+)" );
    2322                 :          0 :       if ( r.exactMatch( src ) )
    2323                 :            :       {
    2324                 :          0 :         src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().writePath( r.cap( 3 ) );
    2325                 :          0 :         handled = true;
    2326                 :          0 :       }
    2327                 :          0 :     }
    2328                 :          0 :   }
    2329                 :          0 :   else if ( providerType() == "wms" )
    2330                 :            :   {
    2331                 :            :     // handle relative paths to XYZ tiles
    2332                 :          0 :     QgsDataSourceUri uri;
    2333                 :          0 :     uri.setEncodedUri( src );
    2334                 :          0 :     QUrl srcUrl( uri.param( QStringLiteral( "url" ) ) );
    2335                 :          0 :     if ( srcUrl.isLocalFile() )
    2336                 :            :     {
    2337                 :            :       // relative path will become "file:./x.txt"
    2338                 :          0 :       QString relSrcUrl = context.pathResolver().writePath( srcUrl.toLocalFile() );
    2339                 :          0 :       uri.removeParam( QStringLiteral( "url" ) );  // needed because setParam() would insert second "url" key
    2340                 :          0 :       uri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() );
    2341                 :          0 :       src = uri.encodedUri();
    2342                 :          0 :       handled = true;
    2343                 :          0 :     }
    2344                 :          0 :   }
    2345                 :            : 
    2346                 :          0 :   if ( !handled )
    2347                 :          0 :     src = context.pathResolver().writePath( src );
    2348                 :            : 
    2349                 :          0 :   return src;
    2350                 :          0 : }
    2351                 :            : 
    2352                 :          0 : QString QgsRasterLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
    2353                 :            : {
    2354                 :          0 :   QString src( source );
    2355                 :            : 
    2356                 :          0 :   if ( provider == QLatin1String( "wms" ) )
    2357                 :            :   {
    2358                 :            :     // >>> BACKWARD COMPATIBILITY < 1.9
    2359                 :            :     // For project file backward compatibility we must support old format:
    2360                 :            :     // 1. mode: <url>
    2361                 :            :     //    example: http://example.org/wms?
    2362                 :            :     // 2. mode: tiled=<width>;<height>;<resolution>;<resolution>...,ignoreUrl=GetMap;GetFeatureInfo,featureCount=<count>,username=<name>,password=<password>,url=<url>
    2363                 :            :     //    example: tiled=256;256;0.703;0.351,url=http://example.org/tilecache?
    2364                 :            :     //    example: featureCount=10,http://example.org/wms?
    2365                 :            :     //    example: ignoreUrl=GetMap;GetFeatureInfo,username=cimrman,password=jara,url=http://example.org/wms?
    2366                 :            :     // This is modified version of old QgsWmsProvider::parseUri
    2367                 :            :     // The new format has always params crs,format,layers,styles and that params
    2368                 :            :     // should not appear in old format url -> use them to identify version
    2369                 :            :     // XYZ tile layers do not need to contain crs,format params, but they have type=xyz
    2370                 :          0 :     if ( !src.contains( QLatin1String( "type=" ) ) &&
    2371                 :          0 :          !src.contains( QLatin1String( "crs=" ) ) && !src.contains( QLatin1String( "format=" ) ) )
    2372                 :            :     {
    2373                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "Old WMS URI format detected -> converting to new format" ), 2 );
    2374                 :          0 :       QgsDataSourceUri uri;
    2375                 :          0 :       if ( !src.startsWith( QLatin1String( "http:" ) ) )
    2376                 :            :       {
    2377                 :          0 :         QStringList parts = src.split( ',' );
    2378                 :          0 :         QStringListIterator iter( parts );
    2379                 :          0 :         while ( iter.hasNext() )
    2380                 :            :         {
    2381                 :          0 :           QString item = iter.next();
    2382                 :          0 :           if ( item.startsWith( QLatin1String( "username=" ) ) )
    2383                 :            :           {
    2384                 :          0 :             uri.setUsername( item.mid( 9 ) );
    2385                 :          0 :           }
    2386                 :          0 :           else if ( item.startsWith( QLatin1String( "password=" ) ) )
    2387                 :            :           {
    2388                 :          0 :             uri.setPassword( item.mid( 9 ) );
    2389                 :          0 :           }
    2390                 :          0 :           else if ( item.startsWith( QLatin1String( "tiled=" ) ) )
    2391                 :            :           {
    2392                 :            :             // in < 1.9 tiled= may apper in to variants:
    2393                 :            :             // tiled=width;height - non tiled mode, specifies max width and max height
    2394                 :            :             // tiled=width;height;resolutions-1;resolution2;... - tile mode
    2395                 :            : 
    2396                 :          0 :             QStringList params = item.mid( 6 ).split( ';' );
    2397                 :            : 
    2398                 :          0 :             if ( params.size() == 2 ) // non tiled mode
    2399                 :            :             {
    2400                 :          0 :               uri.setParam( QStringLiteral( "maxWidth" ), params.takeFirst() );
    2401                 :          0 :               uri.setParam( QStringLiteral( "maxHeight" ), params.takeFirst() );
    2402                 :          0 :             }
    2403                 :          0 :             else if ( params.size() > 2 ) // tiled mode
    2404                 :            :             {
    2405                 :            :               // resolutions are no more needed and size limit is not used for tiles
    2406                 :            :               // we have to tell to the provider however that it is tiled
    2407                 :          0 :               uri.setParam( QStringLiteral( "tileMatrixSet" ), QString() );
    2408                 :          0 :             }
    2409                 :          0 :           }
    2410                 :          0 :           else if ( item.startsWith( QLatin1String( "featureCount=" ) ) )
    2411                 :            :           {
    2412                 :          0 :             uri.setParam( QStringLiteral( "featureCount" ), item.mid( 13 ) );
    2413                 :          0 :           }
    2414                 :          0 :           else if ( item.startsWith( QLatin1String( "url=" ) ) )
    2415                 :            :           {
    2416                 :          0 :             uri.setParam( QStringLiteral( "url" ), item.mid( 4 ) );
    2417                 :          0 :           }
    2418                 :          0 :           else if ( item.startsWith( QLatin1String( "ignoreUrl=" ) ) )
    2419                 :            :           {
    2420                 :          0 :             uri.setParam( QStringLiteral( "ignoreUrl" ), item.mid( 10 ).split( ';' ) );
    2421                 :          0 :           }
    2422                 :          0 :         }
    2423                 :          0 :       }
    2424                 :            :       else
    2425                 :            :       {
    2426                 :          0 :         uri.setParam( QStringLiteral( "url" ), src );
    2427                 :            :       }
    2428                 :          0 :       src = uri.encodedUri();
    2429                 :            :       // At this point, the URI is obviously incomplete, we add additional params
    2430                 :            :       // in QgsRasterLayer::readXml
    2431                 :          0 :     }
    2432                 :            :     // <<< BACKWARD COMPATIBILITY < 1.9
    2433                 :            : 
    2434                 :            :     // handle relative paths to XYZ tiles
    2435                 :          0 :     QgsDataSourceUri uri;
    2436                 :          0 :     uri.setEncodedUri( src );
    2437                 :          0 :     QUrl srcUrl( uri.param( QStringLiteral( "url" ) ) );
    2438                 :          0 :     if ( srcUrl.isLocalFile() )  // file-based URL? convert to relative path
    2439                 :            :     {
    2440                 :          0 :       QString absSrcUrl = context.pathResolver().readPath( srcUrl.toLocalFile() );
    2441                 :          0 :       uri.removeParam( QStringLiteral( "url" ) );  // needed because setParam() would insert second "url" key
    2442                 :          0 :       uri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() );
    2443                 :          0 :       src = uri.encodedUri();
    2444                 :          0 :     }
    2445                 :            : 
    2446                 :          0 :   }
    2447                 :            :   else
    2448                 :            :   {
    2449                 :          0 :     bool handled = false;
    2450                 :            : 
    2451                 :          0 :     if ( provider == QLatin1String( "gdal" ) )
    2452                 :            :     {
    2453                 :          0 :       if ( src.startsWith( QLatin1String( "NETCDF:" ) ) )
    2454                 :            :       {
    2455                 :            :         // NETCDF:filename:variable
    2456                 :            :         // filename can be quoted with " as it can contain colons
    2457                 :          0 :         QRegExp r( "NETCDF:(.+):([^:]+)" );
    2458                 :          0 :         if ( r.exactMatch( src ) )
    2459                 :            :         {
    2460                 :          0 :           QString filename = r.cap( 1 );
    2461                 :          0 :           if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
    2462                 :          0 :             filename = filename.mid( 1, filename.length() - 2 );
    2463                 :          0 :           src = "NETCDF:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
    2464                 :          0 :           handled = true;
    2465                 :          0 :         }
    2466                 :          0 :       }
    2467                 :          0 :       else if ( src.startsWith( QLatin1String( "GPKG:" ) ) )
    2468                 :            :       {
    2469                 :            :         // GPKG:filename:table
    2470                 :          0 :         QString filename, tablename;
    2471                 :          0 :         if ( _parseGpkgColons( src, filename, tablename ) )
    2472                 :            :         {
    2473                 :          0 :           filename = context.pathResolver().readPath( filename );
    2474                 :          0 :           src = QStringLiteral( "GPKG:%1:%2" ).arg( filename, tablename );
    2475                 :          0 :           handled = true;
    2476                 :          0 :         }
    2477                 :          0 :       }
    2478                 :          0 :       else if ( src.startsWith( QLatin1String( "HDF4_SDS:" ) ) )
    2479                 :            :       {
    2480                 :            :         // HDF4_SDS:subdataset_type:file_name:subdataset_index
    2481                 :            :         // filename can be quoted with " as it can contain colons
    2482                 :          0 :         QRegExp r( "HDF4_SDS:([^:]+):(.+):([^:]+)" );
    2483                 :          0 :         if ( r.exactMatch( src ) )
    2484                 :            :         {
    2485                 :          0 :           QString filename = r.cap( 2 );
    2486                 :          0 :           if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
    2487                 :          0 :             filename = filename.mid( 1, filename.length() - 2 );
    2488                 :          0 :           src = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 3 );
    2489                 :          0 :           handled = true;
    2490                 :          0 :         }
    2491                 :          0 :       }
    2492                 :          0 :       else if ( src.startsWith( QLatin1String( "HDF5:" ) ) )
    2493                 :            :       {
    2494                 :            :         // HDF5:file_name:subdataset
    2495                 :            :         // filename can be quoted with " as it can contain colons
    2496                 :          0 :         QRegExp r( "HDF5:(.+):([^:]+)" );
    2497                 :          0 :         if ( r.exactMatch( src ) )
    2498                 :            :         {
    2499                 :          0 :           QString filename = r.cap( 1 );
    2500                 :          0 :           if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
    2501                 :          0 :             filename = filename.mid( 1, filename.length() - 2 );
    2502                 :          0 :           src = "HDF5:\"" + context.pathResolver().readPath( filename ) + "\":" + r.cap( 2 );
    2503                 :          0 :           handled = true;
    2504                 :          0 :         }
    2505                 :          0 :       }
    2506                 :          0 :       else if ( src.contains( QRegExp( "^(NITF_IM|RADARSAT_2_CALIB):" ) ) )
    2507                 :            :       {
    2508                 :            :         // NITF_IM:0:filename
    2509                 :            :         // RADARSAT_2_CALIB:?:filename
    2510                 :          0 :         QRegExp r( "([^:]+):([^:]+):(.+)" );
    2511                 :          0 :         if ( r.exactMatch( src ) )
    2512                 :            :         {
    2513                 :          0 :           src = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + context.pathResolver().readPath( r.cap( 3 ) );
    2514                 :          0 :           handled = true;
    2515                 :          0 :         }
    2516                 :          0 :       }
    2517                 :          0 :     }
    2518                 :            : 
    2519                 :          0 :     if ( !handled )
    2520                 :          0 :       src = context.pathResolver().readPath( src );
    2521                 :            :   }
    2522                 :            : 
    2523                 :          0 :   return src;
    2524                 :          0 : }
    2525                 :            : 
    2526                 :          0 : int QgsRasterLayer::width() const
    2527                 :            : {
    2528                 :          0 :   if ( !mDataProvider ) return 0;
    2529                 :          0 :   return mDataProvider->xSize();
    2530                 :          0 : }
    2531                 :            : 
    2532                 :          0 : int QgsRasterLayer::height() const
    2533                 :            : {
    2534                 :          0 :   if ( !mDataProvider ) return 0;
    2535                 :          0 :   return mDataProvider->ySize();
    2536                 :          0 : }
    2537                 :            : 
    2538                 :          0 : void QgsRasterLayer::setResamplingStage( QgsRasterPipe::ResamplingStage stage )
    2539                 :            : {
    2540                 :          0 :   mPipe.setResamplingStage( stage );
    2541                 :          0 : }
    2542                 :            : 
    2543                 :            : //////////////////////////////////////////////////////////
    2544                 :            : //
    2545                 :            : // Private methods
    2546                 :            : //
    2547                 :            : /////////////////////////////////////////////////////////
    2548                 :          0 : bool QgsRasterLayer::update()
    2549                 :            : {
    2550                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "entered." ), 4 );
    2551                 :            :   // Check if data changed
    2552                 :          0 :   if ( mDataProvider && mDataProvider->dataTimestamp() > mDataProvider->timestamp() )
    2553                 :            :   {
    2554                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "reload data" ), 4 );
    2555                 :          0 :     closeDataProvider();
    2556                 :          0 :     init();
    2557                 :          0 :     QgsDataProvider::ProviderOptions providerOptions;
    2558                 :          0 :     QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
    2559                 :          0 :     if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
    2560                 :            :     {
    2561                 :          0 :       flags |= QgsDataProvider::FlagTrustDataSource;
    2562                 :          0 :     }
    2563                 :          0 :     setDataProvider( mProviderKey, providerOptions, flags );
    2564                 :          0 :     emit dataChanged();
    2565                 :          0 :   }
    2566                 :          0 :   return isValid();
    2567                 :          0 : }

Generated by: LCOV version 1.14