QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsrasterlayerproperties.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterlayerproperties.cpp - description
3  -------------------
4  begin : 1/1/2004
5  copyright : (C) 2004 Tim Sutton
6  email : [email protected]
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <limits>
19 #include <typeinfo>
20 
21 #include "qgsgui.h"
22 #include "qgsapplication.h"
24 #include "qgscontrastenhancement.h"
25 #include "qgscoordinatetransform.h"
27 #include "qgslogger.h"
28 #include "qgsmapcanvas.h"
30 #include "qgsmaptoolemitpoint.h"
31 #include "qgsmaptopixel.h"
32 #include "qgsmetadatawidget.h"
35 #include "qgsnative.h"
39 #include "qgsproject.h"
40 #include "qgsrasterbandstats.h"
42 #include "qgsrasterdataprovider.h"
45 #include "qgsrasterlayer.h"
47 #include "qgsrasterpyramid.h"
48 #include "qgsrasterrange.h"
49 #include "qgsrasterrenderer.h"
51 #include "qgsrastertransparency.h"
54 #include "qgshuesaturationfilter.h"
56 #include "qgssettings.h"
58 #include "qgsmaplayerlegend.h"
59 #include "qgsfileutils.h"
60 #include "qgswebview.h"
61 #include "qgsvectorlayer.h"
62 #include "qgsprovidermetadata.h"
63 #include "qgsproviderregistry.h"
65 #include "qgsdoublevalidator.h"
67 
69 #include "qgsprojecttimesettings.h"
70 
71 #include <QDesktopServices>
72 #include <QTableWidgetItem>
73 #include <QHeaderView>
74 #include <QTextStream>
75 #include <QFile>
76 #include <QFileDialog>
77 #include <QMessageBox>
78 #include <QPainter>
79 #include <QLinearGradient>
80 #include <QPainterPath>
81 #include <QPolygonF>
82 #include <QColorDialog>
83 #include <QList>
84 #include <QMouseEvent>
85 #include <QVector>
86 #include <QUrl>
87 #include <QMenu>
88 #include <QScreen>
89 
90 QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer *lyr, QgsMapCanvas *canvas, QWidget *parent, Qt::WindowFlags fl )
91  : QgsOptionsDialogBase( QStringLiteral( "RasterLayerProperties" ), parent, fl )
92  // Constant that signals property not used.
93  , TRSTRING_NOT_SET( tr( "Not Set" ) )
94  , mDefaultStandardDeviation( 0 )
95  , mDefaultRedBand( 0 )
96  , mDefaultGreenBand( 0 )
97  , mDefaultBlueBand( 0 )
98  , mRasterLayer( qobject_cast<QgsRasterLayer *>( lyr ) )
99  , mGradientHeight( 0.0 )
100  , mGradientWidth( 0.0 )
101  , mMapCanvas( canvas )
102  , mMetadataFilled( false )
103 {
104  mGrayMinimumMaximumEstimated = true;
105  mRGBMinimumMaximumEstimated = true;
106 
107  setupUi( this );
108  connect( mLayerOrigNameLineEd, &QLineEdit::textEdited, this, &QgsRasterLayerProperties::mLayerOrigNameLineEd_textEdited );
109  connect( buttonBuildPyramids, &QPushButton::clicked, this, &QgsRasterLayerProperties::buttonBuildPyramids_clicked );
110  connect( pbnAddValuesFromDisplay, &QToolButton::clicked, this, &QgsRasterLayerProperties::pbnAddValuesFromDisplay_clicked );
111  connect( pbnAddValuesManually, &QToolButton::clicked, this, &QgsRasterLayerProperties::pbnAddValuesManually_clicked );
112  connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsRasterLayerProperties::mCrsSelector_crsChanged );
113  connect( pbnDefaultValues, &QToolButton::clicked, this, &QgsRasterLayerProperties::pbnDefaultValues_clicked );
114  connect( pbnExportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterLayerProperties::pbnExportTransparentPixelValues_clicked );
115  connect( pbnImportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterLayerProperties::pbnImportTransparentPixelValues_clicked );
116  connect( pbnRemoveSelectedRow, &QToolButton::clicked, this, &QgsRasterLayerProperties::pbnRemoveSelectedRow_clicked );
117  connect( mRenderTypeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRasterLayerProperties::mRenderTypeComboBox_currentIndexChanged );
118  connect( mResetColorRenderingBtn, &QToolButton::clicked, this, &QgsRasterLayerProperties::mResetColorRenderingBtn_clicked );
119  // QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
120  // switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
121  // and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
122  initOptionsBase( false );
123  connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsRasterLayerProperties::showHelp );
124 
125  connect( mSetEndAsStartStaticButton, &QPushButton::clicked, this, &QgsRasterLayerProperties::setEndAsStartStaticButton_clicked );
126  connect( mProjectTemporalRange, &QRadioButton::toggled, this, &QgsRasterLayerProperties::passProjectTemporalRange_toggled );
127  connect( mStaticTemporalRange, &QRadioButton::toggled, this, &QgsRasterLayerProperties::staticTemporalRange_toggled );
128 
129  connect( mStaticTemporalRange, &QRadioButton::toggled, mStaticWmstFrame, &QWidget::setEnabled );
130  connect( mReferenceTime, &QCheckBox::toggled, mWmstReferenceTimeFrame, &QWidget::setEnabled );
131 
132  if ( mRasterLayer && mRasterLayer->temporalProperties() )
133  connect( mRasterLayer->temporalProperties(), &QgsRasterLayerTemporalProperties::changed, this, &QgsRasterLayerProperties::temporalPropertiesChange );
134 
135  mSourceGroupBox->hide();
136 
137  mBtnStyle = new QPushButton( tr( "Style" ) );
138  QMenu *menuStyle = new QMenu( this );
139  menuStyle->addAction( tr( "Load Style…" ), this, &QgsRasterLayerProperties::loadStyle_clicked );
140  menuStyle->addAction( tr( "Save Style…" ), this, &QgsRasterLayerProperties::saveStyleAs_clicked );
141  menuStyle->addSeparator();
142  menuStyle->addAction( tr( "Save as Default" ), this, &QgsRasterLayerProperties::saveDefaultStyle_clicked );
143  menuStyle->addAction( tr( "Restore Default" ), this, &QgsRasterLayerProperties::loadDefaultStyle_clicked );
144  mBtnStyle->setMenu( menuStyle );
145  connect( menuStyle, &QMenu::aboutToShow, this, &QgsRasterLayerProperties::aboutToShowStyleMenu );
146  buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
147 
148  mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
149  QMenu *menuMetadata = new QMenu( this );
150  mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata…" ), this, &QgsRasterLayerProperties::loadMetadata );
151  mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata…" ), this, &QgsRasterLayerProperties::saveMetadataAs );
152  menuMetadata->addSeparator();
153  menuMetadata->addAction( tr( "Save as Default" ), this, &QgsRasterLayerProperties::saveDefaultMetadata );
154  menuMetadata->addAction( tr( "Restore Default" ), this, &QgsRasterLayerProperties::loadDefaultMetadata );
155  mBtnMetadata->setMenu( menuMetadata );
156  buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
157 
158  connect( lyr->styleManager(), &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsRasterLayerProperties::syncToLayer );
159 
160  connect( this, &QDialog::accepted, this, &QgsRasterLayerProperties::apply );
161  connect( this, &QDialog::rejected, this, &QgsRasterLayerProperties::onCancel );
162 
163  connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsRasterLayerProperties::apply );
164 
165  // brightness/contrast controls
166  connect( mSliderBrightness, &QAbstractSlider::valueChanged, mBrightnessSpinBox, &QSpinBox::setValue );
167  connect( mBrightnessSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), mSliderBrightness, &QAbstractSlider::setValue );
168  mBrightnessSpinBox->setClearValue( 0 );
169 
170  connect( mSliderContrast, &QAbstractSlider::valueChanged, mContrastSpinBox, &QSpinBox::setValue );
171  connect( mContrastSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), mSliderContrast, &QAbstractSlider::setValue );
172  mContrastSpinBox->setClearValue( 0 );
173 
174  // gamma correction controls
175  connect( mSliderGamma, &QAbstractSlider::valueChanged, this, &QgsRasterLayerProperties::updateGammaSpinBox );
176  connect( mGammaSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsRasterLayerProperties::updateGammaSlider );
177  mGammaSpinBox->setClearValue( 1.0 );
178 
179  // Connect saturation slider and spin box
180  connect( sliderSaturation, &QAbstractSlider::valueChanged, spinBoxSaturation, &QSpinBox::setValue );
181  connect( spinBoxSaturation, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), sliderSaturation, &QAbstractSlider::setValue );
182  spinBoxSaturation->setClearValue( 0 );
183 
184  // Connect colorize strength slider and spin box
185  connect( sliderColorizeStrength, &QAbstractSlider::valueChanged, spinColorizeStrength, &QSpinBox::setValue );
186  connect( spinColorizeStrength, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), sliderColorizeStrength, &QAbstractSlider::setValue );
187  spinColorizeStrength->setClearValue( 100 );
188 
189  // enable or disable saturation slider and spin box depending on grayscale combo choice
190  connect( comboGrayscale, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRasterLayerProperties::toggleSaturationControls );
191 
192  // enable or disable colorize colorbutton with colorize checkbox
193  connect( mColorizeCheck, &QAbstractButton::toggled, this, &QgsRasterLayerProperties::toggleColorizeControls );
194 
195  // enable or disable Build Pyramids button depending on selection in pyramid list
196  connect( lbxPyramidResolutions, &QListWidget::itemSelectionChanged, this, &QgsRasterLayerProperties::toggleBuildPyramidsButton );
197 
198  connect( mRefreshLayerCheckBox, &QCheckBox::toggled, mRefreshLayerIntervalSpinBox, &QDoubleSpinBox::setEnabled );
199 
200  // set up the scale based layer visibility stuff....
201  mScaleRangeWidget->setMapCanvas( mMapCanvas );
202  chkUseScaleDependentRendering->setChecked( lyr->hasScaleBasedVisibility() );
203  mScaleRangeWidget->setScaleRange( lyr->minimumScale(), lyr->maximumScale() );
204 
205  leNoDataValue->setValidator( new QgsDoubleValidator( -std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), 1000, this ) );
206 
207  // build GUI components
208  QIcon myPyramidPixmap( QgsApplication::getThemeIcon( "/mIconPyramid.svg" ) );
209  QIcon myNoPyramidPixmap( QgsApplication::getThemeIcon( "/mIconNoPyramid.svg" ) );
210 
211  pbnAddValuesManually->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
212  pbnAddValuesFromDisplay->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionContextHelp.png" ) ) );
213  pbnRemoveSelectedRow->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyRemove.svg" ) ) );
214  pbnDefaultValues->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ) );
215  pbnImportTransparentPixelValues->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileOpen.svg" ) ) );
216  pbnExportTransparentPixelValues->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileSave.svg" ) ) );
217 
218  if ( mMapCanvas )
219  {
220  mPixelSelectorTool = qgis::make_unique<QgsMapToolEmitPoint>( canvas );
221  connect( mPixelSelectorTool.get(), &QgsMapToolEmitPoint::canvasClicked, this, &QgsRasterLayerProperties::pixelSelected );
222  connect( mPixelSelectorTool.get(), &QgsMapToolEmitPoint::deactivated, this, &QgsRasterLayerProperties::restoreWindowModality );
223  }
224  else
225  {
226  pbnAddValuesFromDisplay->setEnabled( false );
227  }
228 
229  if ( !mRasterLayer )
230  {
231  return;
232  }
233 
234  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
235 
236  // Only do pyramids if dealing directly with GDAL.
237  if ( provider && provider->capabilities() & QgsRasterDataProvider::BuildPyramids )
238  {
239  // initialize resampling methods
240  cboResamplingMethod->clear();
241 
242  const auto constProviderType = QgsRasterDataProvider::pyramidResamplingMethods( mRasterLayer->providerType() );
243  for ( QPair<QString, QString> method : constProviderType )
244  {
245  cboResamplingMethod->addItem( method.second, method.first );
246  }
247 
248  // keep it in sync with qgsrasterpyramidsoptionwidget.cpp
249  QString prefix = provider->name() + "/driverOptions/_pyramids/";
250  QgsSettings mySettings;
251  QString defaultMethod = mySettings.value( prefix + "resampling", "AVERAGE" ).toString();
252  int idx = cboResamplingMethod->findData( defaultMethod );
253  if ( idx >= 0 )
254  cboResamplingMethod->setCurrentIndex( idx );
255 
256 
257  // build pyramid list
258  QList< QgsRasterPyramid > myPyramidList = provider->buildPyramidList();
259  QList< QgsRasterPyramid >::iterator myRasterPyramidIterator;
260 
261  for ( myRasterPyramidIterator = myPyramidList.begin();
262  myRasterPyramidIterator != myPyramidList.end();
263  ++myRasterPyramidIterator )
264  {
265  if ( myRasterPyramidIterator->exists )
266  {
267  lbxPyramidResolutions->addItem( new QListWidgetItem( myPyramidPixmap,
268  QString::number( myRasterPyramidIterator->xDim ) + QStringLiteral( " x " ) +
269  QString::number( myRasterPyramidIterator->yDim ) ) );
270  }
271  else
272  {
273  lbxPyramidResolutions->addItem( new QListWidgetItem( myNoPyramidPixmap,
274  QString::number( myRasterPyramidIterator->xDim ) + QStringLiteral( " x " ) +
275  QString::number( myRasterPyramidIterator->yDim ) ) );
276  }
277  }
278  }
279  else
280  {
281  // disable Pyramids tab completely
282  mOptsPage_Pyramids->setEnabled( false );
283  }
284 
285  // We can calculate histogram for all data sources but estimated only if
286  // size is unknown - could also be enabled if well supported (estimated histogram
287  // and let user know that it is estimated)
288  if ( !provider || !( provider->capabilities() & QgsRasterDataProvider::Size ) )
289  {
290  // disable Histogram tab completely
291  mOptsPage_Histogram->setEnabled( false );
292  }
293 
294  QVBoxLayout *layout = new QVBoxLayout( metadataFrame );
295  layout->setContentsMargins( 0, 0, 0, 0 );
296  mMetadataWidget = new QgsMetadataWidget( this, mRasterLayer );
297  mMetadataWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
298  mMetadataWidget->setMapCanvas( mMapCanvas );
299  layout->addWidget( mMetadataWidget );
300  metadataFrame->setLayout( layout );
301 
302  QVBoxLayout *temporalLayout = new QVBoxLayout( temporalFrame );
303  temporalLayout->setContentsMargins( 0, 0, 0, 0 );
304  mTemporalWidget = new QgsRasterLayerTemporalPropertiesWidget( this, mRasterLayer );
305  temporalLayout->addWidget( mTemporalWidget );
306 
307  setSourceStaticTimeState();
308  mWmstGroup->setVisible( mRasterLayer->providerType() == QLatin1String( "wms" ) && mRasterLayer->dataProvider() && mRasterLayer->dataProvider()->temporalCapabilities()->hasTemporalCapabilities() );
309 
310  // This group is used to define the temporal capabilities of the PG raster layer
311  if ( mRasterLayer->dataProvider() && mRasterLayer->providerType() == QLatin1String( "postgresraster" ) )
312  {
313  mPostgresRasterTemporalGroup->setEnabled( true );
314  mPostgresRasterTemporalGroup->setVisible( true );
315  mPostgresRasterTemporalGroup->setChecked( false );
316  const QgsFields fields { mRasterLayer->dataProvider()->fields() };
317  mPostgresRasterTemporalFieldComboBox->setFields( fields );
318  mPostgresRasterTemporalFieldComboBox->setFilters( QgsFieldProxyModel::Filter::Date |
319  QgsFieldProxyModel::Filter::DateTime |
320  QgsFieldProxyModel::Filter::String );
321  mPostgresRasterTemporalFieldComboBox->setAllowEmptyFieldName( true );
322  connect( mPostgresRasterTemporalFieldComboBox, &QgsFieldComboBox::fieldChanged, this, [ = ]( const QString & fieldName )
323  {
324  mPostgresRasterDefaultTime->setEnabled( ! fieldName.isEmpty() );
325  } );
326  mPostgresRasterDefaultTime->setAllowNull( true );
327  mPostgresRasterDefaultTime->setEmpty();
328  if ( mRasterLayer->dataProvider()->uri().hasParam( QStringLiteral( "temporalFieldIndex" ) ) )
329  {
330  bool ok;
331  const int fieldIdx { mRasterLayer->dataProvider()->uri().param( QStringLiteral( "temporalFieldIndex" ) ).toInt( &ok ) };
332  if ( ok && fields.exists( fieldIdx ) )
333  {
334  mPostgresRasterTemporalGroup->setChecked( true );
335  mPostgresRasterTemporalFieldComboBox->setField( fields.field( fieldIdx ).name() );
336  if ( mRasterLayer->dataProvider()->uri().hasParam( QStringLiteral( "temporalDefaultTime" ) ) )
337  {
338  const QDateTime defaultDateTime { QDateTime::fromString( mRasterLayer->dataProvider()->uri().param( QStringLiteral( "temporalDefaultTime" ) ), Qt::DateFormat::ISODate ) };
339  if ( defaultDateTime.isValid() )
340  {
341  mPostgresRasterDefaultTime->setDateTime( defaultDateTime );
342  }
343  }
344  }
345  }
346  }
347  else
348  {
349  mPostgresRasterTemporalGroup->setEnabled( false );
350  mPostgresRasterTemporalGroup->setVisible( false );
351  }
352 
353  QgsDebugMsgLevel( "Setting crs to " + mRasterLayer->crs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ), 2 );
354  QgsDebugMsgLevel( "Setting crs to " + mRasterLayer->crs().userFriendlyIdentifier(), 2 );
355  mCrsSelector->setCrs( mRasterLayer->crs() );
356 
357  // Set text for pyramid info box
358  QString pyramidFormat( QStringLiteral( "<h2>%1</h2><p>%2 %3 %4</p><b><font color='red'><p>%5</p><p>%6</p>" ) );
359  QString pyramidHeader = tr( "Description" );
360  QString pyramidSentence1 = tr( "Large resolution raster layers can slow navigation in QGIS." );
361  QString pyramidSentence2 = tr( "By creating lower resolution copies of the data (pyramids) performance can be considerably improved as QGIS selects the most suitable resolution to use depending on the level of zoom." );
362  QString pyramidSentence3 = tr( "You must have write access in the directory where the original data is stored to build pyramids." );
363  QString pyramidSentence4 = tr( "Please note that building internal pyramids may alter the original data file and once created they cannot be removed!" );
364  QString pyramidSentence5 = tr( "Please note that building internal pyramids could corrupt your image - always make a backup of your data first!" );
365 
366  tePyramidDescription->setHtml( pyramidFormat.arg( pyramidHeader,
367  pyramidSentence1,
368  pyramidSentence2,
369  pyramidSentence3,
370  pyramidSentence4,
371  pyramidSentence5 ) );
372 
373  //resampling
374  mResamplingGroupBox->setSaveCheckedState( true );
375  mResamplingUtils.initWidgets( mRasterLayer, mZoomedInResamplingComboBox, mZoomedOutResamplingComboBox, mMaximumOversamplingSpinBox, mCbEarlyResampling );
376  mResamplingUtils.refreshWidgetsFromLayer();
377 
378  const QgsRasterRenderer *renderer = mRasterLayer->renderer();
379 
380  btnColorizeColor->setColorDialogTitle( tr( "Select Color" ) );
381  btnColorizeColor->setContext( QStringLiteral( "symbology" ) );
382 
383  // Hue and saturation color control
384  const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter();
385  //set hue and saturation controls to current values
386  if ( hueSaturationFilter )
387  {
388  sliderSaturation->setValue( hueSaturationFilter->saturation() );
389  comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
390 
391  // Set initial state of saturation controls based on grayscale mode choice
392  toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
393 
394  // Set initial state of colorize controls
395  mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
396  btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
397  toggleColorizeControls( hueSaturationFilter->colorizeOn() );
398  sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
399  }
400 
401  //blend mode
402  mBlendModeComboBox->setBlendMode( mRasterLayer->blendMode() );
403 
404  //transparency band
405  if ( provider )
406  {
407  cboxTransparencyBand->setShowNotSetOption( true, tr( "None" ) );
408  cboxTransparencyBand->setLayer( mRasterLayer );
409 
410 // Alpha band is set in sync()
411 #if 0
412  if ( renderer )
413  {
414  QgsDebugMsg( QStringLiteral( "alphaBand = %1" ).arg( renderer->alphaBand() ) );
415  if ( renderer->alphaBand() > 0 )
416  {
417  cboxTransparencyBand->setCurrentIndex( cboxTransparencyBand->findData( renderer->alphaBand() ) );
418  }
419  }
420 #endif
421  }
422 
423  // create histogram widget
424  mHistogramWidget = nullptr;
425  if ( mOptsPage_Histogram->isEnabled() )
426  {
427  mHistogramWidget = new QgsRasterHistogramWidget( mRasterLayer, mOptsPage_Histogram );
428  mHistogramStackedWidget->addWidget( mHistogramWidget );
429  }
430 
431  //insert renderer widgets into registry
438 
439  //fill available renderers into combo box
441  mDisableRenderTypeComboBoxCurrentIndexChanged = true;
442  const auto constRenderersList = QgsApplication::rasterRendererRegistry()->renderersList();
443  for ( const QString &name : constRenderersList )
444  {
445  if ( QgsApplication::rasterRendererRegistry()->rendererData( name, entry ) )
446  {
447  if ( ( mRasterLayer->rasterType() != QgsRasterLayer::ColorLayer && entry.name != QLatin1String( "singlebandcolordata" ) ) ||
448  ( mRasterLayer->rasterType() == QgsRasterLayer::ColorLayer && entry.name == QLatin1String( "singlebandcolordata" ) ) )
449  {
450  mRenderTypeComboBox->addItem( entry.visibleName, entry.name );
451  }
452  }
453  }
454  mDisableRenderTypeComboBoxCurrentIndexChanged = false;
455 
456  int widgetIndex = 0;
457  if ( renderer )
458  {
459  QString rendererType = renderer->type();
460  widgetIndex = mRenderTypeComboBox->findData( rendererType );
461  if ( widgetIndex != -1 )
462  {
463  mDisableRenderTypeComboBoxCurrentIndexChanged = true;
464  mRenderTypeComboBox->setCurrentIndex( widgetIndex );
465  mDisableRenderTypeComboBoxCurrentIndexChanged = false;
466  }
467 
468  if ( rendererType == QLatin1String( "singlebandcolordata" ) && mRenderTypeComboBox->count() == 1 )
469  {
470  // no band rendering options for singlebandcolordata, so minimize group box
471  QSizePolicy sizep = mBandRenderingGrpBx->sizePolicy();
472  sizep.setVerticalStretch( 0 );
473  sizep.setVerticalPolicy( QSizePolicy::Maximum );
474  mBandRenderingGrpBx->setSizePolicy( sizep );
475  mBandRenderingGrpBx->updateGeometry();
476  }
477 
478  if ( mRasterLayer->providerType() != QLatin1String( "wms" ) )
479  {
480  mWMSPrintGroupBox->hide();
481  mPublishDataSourceUrlCheckBox->hide();
482  mBackgroundLayerCheckBox->hide();
483  }
484  }
485 
486 #ifdef WITH_QTWEBKIT
487  // Setup information tab
488 
489 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
490  const int horizontalDpi = qApp->desktop()->screen()->logicalDpiX();
491 #else
492  const int horizontalDpi = logicalDpiX();
493 #endif
494 
495  // Adjust zoom: text is ok, but HTML seems rather big at least on Linux/KDE
496  if ( horizontalDpi > 96 )
497  {
498  mMetadataViewer->setZoomFactor( mMetadataViewer->zoomFactor() * 0.9 );
499  }
500  mMetadataViewer->page()->setLinkDelegationPolicy( QWebPage::LinkDelegationPolicy::DelegateAllLinks );
501  connect( mMetadataViewer->page(), &QWebPage::linkClicked, this, &QgsRasterLayerProperties::urlClicked );
502  mMetadataViewer->page()->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
503  mMetadataViewer->page()->settings()->setAttribute( QWebSettings::JavascriptEnabled, true );
504 
505 #endif
506 
507  mRenderTypeComboBox_currentIndexChanged( widgetIndex );
508 
509  // update based on lyr's current state
510  sync();
511 
512  QgsSettings settings;
513  // if dialog hasn't been opened/closed yet, default to Styles tab, which is used most often
514  // this will be read by restoreOptionsBaseUi()
515  if ( !settings.contains( QStringLiteral( "/Windows/RasterLayerProperties/tab" ) ) )
516  {
517  settings.setValue( QStringLiteral( "Windows/RasterLayerProperties/tab" ),
518  mOptStackedWidget->indexOf( mOptsPage_Style ) );
519  }
520 
521  mResetColorRenderingBtn->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUndo.svg" ) ) );
522 
523  QString title = tr( "Layer Properties — %1" ).arg( lyr->name() );
524 
525  if ( !mRasterLayer->styleManager()->isDefault( mRasterLayer->styleManager()->currentStyle() ) )
526  title += QStringLiteral( " (%1)" ).arg( mRasterLayer->styleManager()->currentStyle() );
527  restoreOptionsBaseUi( title );
528  optionsStackedWidget_CurrentChanged( mOptionsStackedWidget->currentIndex() );
529 
530  //Add help page references
531  mOptsPage_Information->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#information-properties" ) );
532  mOptsPage_Source->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#source-properties" ) );
533  mOptsPage_Style->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#symbology-properties" ) );
534  mOptsPage_Transparency->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#transparency-properties" ) );
535 
536  if ( mOptsPage_Histogram )
537  mOptsPage_Histogram->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#histogram-properties" ) );
538 
539  mOptsPage_Rendering->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#rendering-properties" ) );
540 
541  if ( mOptsPage_Pyramids )
542  mOptsPage_Pyramids->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#pyramids-properties" ) );
543 
544  mOptsPage_Metadata->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#metadata-properties" ) );
545  mOptsPage_Legend->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#legend-properties" ) );
546  mOptsPage_Server->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#server-properties" ) );
547 }
548 
550 {
551  if ( !factory->supportsLayer( mRasterLayer ) || !factory->supportLayerPropertiesDialog() )
552  {
553  return;
554  }
555 
556  QgsMapLayerConfigWidget *page = factory->createWidget( mRasterLayer, nullptr, false, this );
557  mLayerPropertiesPages << page;
558 
559  const QString beforePage = factory->layerPropertiesPagePositionHint();
560  if ( beforePage.isEmpty() )
561  addPage( factory->title(), factory->title(), factory->icon(), page );
562  else
563  insertPage( factory->title(), factory->title(), factory->icon(), page, beforePage );
564 }
565 
566 void QgsRasterLayerProperties::setupTransparencyTable( int nBands )
567 {
568  tableTransparency->clear();
569  tableTransparency->setColumnCount( 0 );
570  tableTransparency->setRowCount( 0 );
571  mTransparencyToEdited.clear();
572 
573  if ( nBands == 3 )
574  {
575  tableTransparency->setColumnCount( 4 );
576  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Red" ) ) );
577  tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Green" ) ) );
578  tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Blue" ) ) );
579  tableTransparency->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
580  }
581  else //1 band
582  {
583  tableTransparency->setColumnCount( 3 );
584 // Is it important to distinguish the header? It becomes difficult with range.
585 #if 0
586  if ( QgsRasterLayer::PalettedColor != mRasterLayer->drawingStyle() &&
587  QgsRasterLayer::PalettedSingleBandGray != mRasterLayer->drawingStyle() &&
588  QgsRasterLayer::PalettedSingleBandPseudoColor != mRasterLayer->drawingStyle() &&
589  QgsRasterLayer::PalettedMultiBandColor != mRasterLayer->drawingStyle() )
590  {
591  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Gray" ) ) );
592  }
593  else
594  {
595  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Indexed Value" ) ) );
596  }
597 #endif
598  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "From" ) ) );
599  tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "To" ) ) );
600  tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
601  }
602 
603  tableTransparency->horizontalHeader()->setSectionResizeMode( 0, QHeaderView::Stretch );
604  tableTransparency->horizontalHeader()->setSectionResizeMode( 1, QHeaderView::Stretch );
605 }
606 
607 void QgsRasterLayerProperties::populateTransparencyTable( QgsRasterRenderer *renderer )
608 {
609  if ( !mRasterLayer )
610  {
611  return;
612  }
613 
614  if ( !renderer )
615  {
616  return;
617  }
618 
619  int nBands = renderer->usesBands().size();
620  setupTransparencyTable( nBands );
621 
622  const QgsRasterTransparency *rasterTransparency = renderer->rasterTransparency();
623  if ( !rasterTransparency )
624  {
625  return;
626  }
627 
628  if ( nBands == 1 )
629  {
630  QList<QgsRasterTransparency::TransparentSingleValuePixel> pixelList = rasterTransparency->transparentSingleValuePixelList();
631  for ( int i = 0; i < pixelList.size(); ++i )
632  {
633  tableTransparency->insertRow( i );
634  setTransparencyCell( i, 0, pixelList[i].min );
635  setTransparencyCell( i, 1, pixelList[i].max );
636  setTransparencyCell( i, 2, pixelList[i].percentTransparent );
637  // break synchronization only if values differ
638  if ( pixelList[i].min != pixelList[i].max )
639  {
640  setTransparencyToEdited( i );
641  }
642  }
643  }
644  else if ( nBands == 3 )
645  {
646  QList<QgsRasterTransparency::TransparentThreeValuePixel> pixelList = rasterTransparency->transparentThreeValuePixelList();
647  for ( int i = 0; i < pixelList.size(); ++i )
648  {
649  tableTransparency->insertRow( i );
650  setTransparencyCell( i, 0, pixelList[i].red );
651  setTransparencyCell( i, 1, pixelList[i].green );
652  setTransparencyCell( i, 2, pixelList[i].blue );
653  setTransparencyCell( i, 3, pixelList[i].percentTransparent );
654  }
655  }
656 
657  tableTransparency->resizeColumnsToContents();
658  tableTransparency->resizeRowsToContents();
659 }
660 
661 void QgsRasterLayerProperties::setRendererWidget( const QString &rendererName )
662 {
663  QgsDebugMsgLevel( "rendererName = " + rendererName, 3 );
664  QgsRasterRendererWidget *oldWidget = mRendererWidget;
665  QgsRasterRenderer *oldRenderer = mRasterLayer->renderer();
666 
667  int alphaBand = -1;
668  double opacity = 1;
669  QColor nodataColor;
670  if ( oldRenderer )
671  {
672  // Retain alpha band and opacity when switching renderer
673  alphaBand = oldRenderer->alphaBand();
674  opacity = oldRenderer->opacity();
675  nodataColor = oldRenderer->nodataColor();
676  }
677 
678  QgsRasterRendererRegistryEntry rendererEntry;
679  if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
680  {
681  if ( rendererEntry.widgetCreateFunction ) //single band color data renderer e.g. has no widget
682  {
683  QgsDebugMsgLevel( QStringLiteral( "renderer has widgetCreateFunction" ), 3 );
684  // Current canvas extent (used to calc min/max) in layer CRS
685  QgsRectangle myExtent = mMapCanvas->mapSettings().outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() );
686  if ( oldWidget && ( !oldRenderer || rendererName != oldRenderer->type() ) )
687  {
688  if ( rendererName == QLatin1String( "singlebandgray" ) )
689  {
690  whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::SingleBandGray, mRasterLayer->dataProvider() ) );
691  whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
692  }
693  else if ( rendererName == QLatin1String( "multibandcolor" ) )
694  {
695  whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::MultiBandColor, mRasterLayer->dataProvider() ) );
696  whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
697  }
698  }
699  mRasterLayer->renderer()->setAlphaBand( alphaBand );
700  mRasterLayer->renderer()->setOpacity( opacity );
701  mRasterLayer->renderer()->setNodataColor( nodataColor );
702  mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
703  mRendererWidget->setMapCanvas( mMapCanvas );
704  mRendererStackedWidget->addWidget( mRendererWidget );
705  if ( oldWidget )
706  {
707  //compare used bands in new and old renderer and reset transparency dialog if different
708  QgsRasterRenderer *oldRenderer = oldWidget->renderer();
709  QgsRasterRenderer *newRenderer = mRendererWidget->renderer();
710  QList<int> oldBands = oldRenderer->usesBands();
711  QList<int> newBands = newRenderer->usesBands();
712  if ( oldBands != newBands )
713  {
714  populateTransparencyTable( newRenderer );
715  }
716  delete oldRenderer;
717  delete newRenderer;
718  }
719  }
720  }
721 
722  const int widgetIndex = mRenderTypeComboBox->findData( rendererName );
723  if ( widgetIndex != -1 )
724  {
725  mDisableRenderTypeComboBoxCurrentIndexChanged = true;
726  mRenderTypeComboBox->setCurrentIndex( widgetIndex );
727  mDisableRenderTypeComboBoxCurrentIndexChanged = false;
728  }
729 
730  if ( mRendererWidget != oldWidget )
731  delete oldWidget;
732 
733  if ( mHistogramWidget )
734  {
735  mHistogramWidget->setRendererWidget( rendererName, mRendererWidget );
736  }
737 }
738 
739 void QgsRasterLayerProperties::sync()
740 {
741  QgsSettings myQSettings;
742 
743  if ( !mSourceWidget )
744  {
745  mSourceWidget = QgsGui::sourceWidgetProviderRegistry()->createWidget( mRasterLayer );
746  if ( mSourceWidget )
747  {
748  QHBoxLayout *layout = new QHBoxLayout();
749  layout->addWidget( mSourceWidget );
750  mSourceGroupBox->setLayout( layout );
751  mSourceGroupBox->show();
752 
753  connect( mSourceWidget, &QgsProviderSourceWidget::validChanged, this, [ = ]( bool isValid )
754  {
755  buttonBox->button( QDialogButtonBox::Apply )->setEnabled( isValid );
756  buttonBox->button( QDialogButtonBox::Ok )->setEnabled( isValid );
757  } );
758  }
759  }
760 
761  if ( mSourceWidget )
762  mSourceWidget->setSourceUri( mRasterLayer->source() );
763 
764  const QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
765  if ( !provider )
766  return;
767 
768  if ( provider->dataType( 1 ) == Qgis::ARGB32
769  || provider->dataType( 1 ) == Qgis::ARGB32_Premultiplied )
770  {
771  gboxNoDataValue->setEnabled( false );
772  gboxCustomTransparency->setEnabled( false );
773  mOptionsStackedWidget->setCurrentWidget( mOptsPage_Server );
774  }
775 
776  // TODO: Wouldn't it be better to just removeWidget() the tabs than delete them? [LS]
777  if ( !( provider->capabilities() & QgsRasterDataProvider::BuildPyramids ) )
778  {
779  if ( mOptsPage_Pyramids )
780  {
781  delete mOptsPage_Pyramids;
782  mOptsPage_Pyramids = nullptr;
783  }
784  }
785 
786  if ( !( provider->capabilities() & QgsRasterDataProvider::Size ) )
787  {
788  if ( mOptsPage_Histogram )
789  {
790  delete mOptsPage_Histogram;
791  mOptsPage_Histogram = nullptr;
792  delete mHistogramWidget;
793  mHistogramWidget = nullptr;
794  }
795  }
796 
797  QgsDebugMsgLevel( QStringLiteral( "populate transparency tab" ), 3 );
798 
799  /*
800  * Style tab
801  */
802 
803  //set brightness, contrast and gamma
804  QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter();
805  if ( brightnessFilter )
806  {
807  mSliderBrightness->setValue( brightnessFilter->brightness() );
808  mSliderContrast->setValue( brightnessFilter->contrast() );
809  mGammaSpinBox->setValue( brightnessFilter->gamma() );
810  }
811 
812  // Hue and saturation color control
813  const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter();
814  //set hue and saturation controls to current values
815  if ( hueSaturationFilter )
816  {
817  sliderSaturation->setValue( hueSaturationFilter->saturation() );
818  comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
819 
820  // Set state of saturation controls based on grayscale mode choice
821  toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
822 
823  // Set state of colorize controls
824  mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
825  btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
826  toggleColorizeControls( hueSaturationFilter->colorizeOn() );
827  sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
828  }
829 
830  /*
831  * Transparent Pixel Tab
832  */
833 
834  //set the transparency slider
835  QgsRasterRenderer *renderer = mRasterLayer->renderer();
836  if ( renderer )
837  {
838  mOpacityWidget->setOpacity( renderer->opacity() );
839  cboxTransparencyBand->setBand( renderer->alphaBand() );
840  }
841 
842  //add current NoDataValue to NoDataValue line edit
843  // TODO: should be per band
844  // TODO: no data ranges
845  if ( provider->sourceHasNoDataValue( 1 ) )
846  {
847  double v = QgsRasterBlock::printValue( provider->sourceNoDataValue( 1 ) ).toDouble();
848  lblSrcNoDataValue->setText( QLocale().toString( v, 'g' ) );
849  }
850  else
851  {
852  lblSrcNoDataValue->setText( tr( "not defined" ) );
853  }
854 
855  mSrcNoDataValueCheckBox->setChecked( provider->useSourceNoDataValue( 1 ) );
856 
857  bool enableSrcNoData = provider->sourceHasNoDataValue( 1 ) && !std::isnan( provider->sourceNoDataValue( 1 ) );
858 
859  mSrcNoDataValueCheckBox->setEnabled( enableSrcNoData );
860  lblSrcNoDataValue->setEnabled( enableSrcNoData );
861 
862  QgsRasterRangeList noDataRangeList = provider->userNoDataValues( 1 );
863  QgsDebugMsgLevel( QStringLiteral( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ), 3 );
864  if ( !noDataRangeList.isEmpty() )
865  {
866  leNoDataValue->insert( QgsRasterBlock::printValue( noDataRangeList.value( 0 ).min() ) );
867  }
868  else
869  {
870  leNoDataValue->insert( QString() );
871  }
872 
873  mRefreshLayerCheckBox->setChecked( mRasterLayer->hasAutoRefreshEnabled() );
874  mRefreshLayerIntervalSpinBox->setEnabled( mRasterLayer->hasAutoRefreshEnabled() );
875  mRefreshLayerIntervalSpinBox->setValue( mRasterLayer->autoRefreshInterval() / 1000.0 );
876 
877  populateTransparencyTable( mRasterLayer->renderer() );
878 
879  QgsDebugMsgLevel( QStringLiteral( "populate colormap tab" ), 3 );
880  /*
881  * Transparent Pixel Tab
882  */
883 
884  QgsDebugMsgLevel( QStringLiteral( "populate general tab" ), 3 );
885  /*
886  * General Tab
887  */
888 
889  //these properties (layer name and label) are provided by the qgsmaplayer superclass
890  mLayerOrigNameLineEd->setText( mRasterLayer->name() );
891  leDisplayName->setText( mRasterLayer->name() );
892 
893  QgsDebugMsgLevel( QStringLiteral( "populate metadata tab" ), 2 );
894  /*
895  * Metadata Tab
896  */
897  //populate the metadata tab's text browser widget with gdal metadata info
898  updateInformationContent();
899 
900  // WMS Name as layer short name
901  mLayerShortNameLineEdit->setText( mRasterLayer->shortName() );
902  // WMS Name validator
903  QValidator *shortNameValidator = new QRegExpValidator( QgsApplication::shortNameRegExp(), this );
904  mLayerShortNameLineEdit->setValidator( shortNameValidator );
905 
906  //layer title and abstract
907  mLayerTitleLineEdit->setText( mRasterLayer->title() );
908  mLayerAbstractTextEdit->setPlainText( mRasterLayer->abstract() );
909  mLayerKeywordListLineEdit->setText( mRasterLayer->keywordList() );
910  mLayerDataUrlLineEdit->setText( mRasterLayer->dataUrl() );
911  mLayerDataUrlFormatComboBox->setCurrentIndex(
912  mLayerDataUrlFormatComboBox->findText(
913  mRasterLayer->dataUrlFormat()
914  )
915  );
916 
917  //layer attribution and metadataUrl
918  mLayerAttributionLineEdit->setText( mRasterLayer->attribution() );
919  mLayerAttributionUrlLineEdit->setText( mRasterLayer->attributionUrl() );
920  mLayerMetadataUrlLineEdit->setText( mRasterLayer->metadataUrl() );
921  mLayerMetadataUrlTypeComboBox->setCurrentIndex(
922  mLayerMetadataUrlTypeComboBox->findText(
923  mRasterLayer->metadataUrlType()
924  )
925  );
926  mLayerMetadataUrlFormatComboBox->setCurrentIndex(
927  mLayerMetadataUrlFormatComboBox->findText(
928  mRasterLayer->metadataUrlFormat()
929  )
930  );
931 
932  mLayerLegendUrlLineEdit->setText( mRasterLayer->legendUrl() );
933  mLayerLegendUrlFormatComboBox->setCurrentIndex( mLayerLegendUrlFormatComboBox->findText( mRasterLayer->legendUrlFormat() ) );
934 
935  //WMS print layer
936  QVariant wmsPrintLayer = mRasterLayer->customProperty( QStringLiteral( "WMSPrintLayer" ) );
937  if ( wmsPrintLayer.isValid() )
938  {
939  mWMSPrintLayerLineEdit->setText( wmsPrintLayer.toString() );
940  }
941 
942  QVariant wmsPublishDataSourceUrl = mRasterLayer->customProperty( QStringLiteral( "WMSPublishDataSourceUrl" ), false );
943  mPublishDataSourceUrlCheckBox->setChecked( wmsPublishDataSourceUrl.toBool() );
944 
945  QVariant wmsBackgroundLayer = mRasterLayer->customProperty( QStringLiteral( "WMSBackgroundLayer" ), false );
946  mBackgroundLayerCheckBox->setChecked( wmsBackgroundLayer.toBool() );
947 
948  mLegendConfigEmbeddedWidget->setLayer( mRasterLayer );
949 
950  mTemporalWidget->syncToLayer();
951 
952  for ( QgsMapLayerConfigWidget *page : qgis::as_const( mLayerPropertiesPages ) )
953  {
954  page->syncToLayer( mRasterLayer );
955  }
956 
957 }
958 
959 void QgsRasterLayerProperties::apply()
960 {
961  if ( mSourceWidget )
962  {
963  const QString newSource = mSourceWidget->sourceUri();
964  if ( newSource != mRasterLayer->source() )
965  {
966  mRasterLayer->setDataSource( newSource, mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );
967  }
968  }
969 
970  // Do nothing on "bad" layers
971  if ( !mRasterLayer->isValid() )
972  return;
973 
974  /*
975  * Legend Tab
976  */
977  mLegendConfigEmbeddedWidget->applyToLayer();
978 
979  QgsDebugMsgLevel( QStringLiteral( "apply processing symbology tab" ), 3 );
980  /*
981  * Symbology Tab
982  */
983 
984  //set whether the layer histogram should be inverted
985  //mRasterLayer->setInvertHistogram( cboxInvertColorMap->isChecked() );
986 
987  mRasterLayer->brightnessFilter()->setBrightness( mSliderBrightness->value() );
988  mRasterLayer->brightnessFilter()->setContrast( mSliderContrast->value() );
989  mRasterLayer->brightnessFilter()->setGamma( mGammaSpinBox->value() );
990 
991  QgsDebugMsgLevel( QStringLiteral( "processing transparency tab" ), 3 );
992  /*
993  * Transparent Pixel Tab
994  */
995 
996  //set NoDataValue
997  QgsRasterRangeList myNoDataRangeList;
998  if ( "" != leNoDataValue->text() )
999  {
1000  bool myDoubleOk = false;
1001  double myNoDataValue = QgsDoubleValidator::toDouble( leNoDataValue->text(), &myDoubleOk );
1002  if ( myDoubleOk )
1003  {
1004  QgsRasterRange myNoDataRange( myNoDataValue, myNoDataValue );
1005  myNoDataRangeList << myNoDataRange;
1006  }
1007  }
1008  for ( int bandNo = 1; bandNo <= mRasterLayer->dataProvider()->bandCount(); bandNo++ )
1009  {
1010  mRasterLayer->dataProvider()->setUserNoDataValue( bandNo, myNoDataRangeList );
1011  mRasterLayer->dataProvider()->setUseSourceNoDataValue( bandNo, mSrcNoDataValueCheckBox->isChecked() );
1012  }
1013 
1014  //set renderer from widget
1015  QgsRasterRendererWidget *rendererWidget = dynamic_cast<QgsRasterRendererWidget *>( mRendererStackedWidget->currentWidget() );
1016  if ( rendererWidget )
1017  {
1018  rendererWidget->doComputations();
1019 
1020  mRasterLayer->setRenderer( rendererWidget->renderer() );
1021  }
1022 
1023  mMetadataWidget->acceptMetadata();
1024  mMetadataFilled = false;
1025 
1026  //transparency settings
1027  QgsRasterRenderer *rasterRenderer = mRasterLayer->renderer();
1028  if ( rasterRenderer )
1029  {
1030  rasterRenderer->setAlphaBand( cboxTransparencyBand->currentBand() );
1031 
1032  //Walk through each row in table and test value. If not valid set to 0.0 and continue building transparency list
1033  QgsRasterTransparency *rasterTransparency = new QgsRasterTransparency();
1034  if ( tableTransparency->columnCount() == 4 )
1035  {
1037  QList<QgsRasterTransparency::TransparentThreeValuePixel> myTransparentThreeValuePixelList;
1038  for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
1039  {
1040  myTransparentPixel.red = transparencyCellValue( myListRunner, 0 );
1041  myTransparentPixel.green = transparencyCellValue( myListRunner, 1 );
1042  myTransparentPixel.blue = transparencyCellValue( myListRunner, 2 );
1043  myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 3 );
1044  myTransparentThreeValuePixelList.append( myTransparentPixel );
1045  }
1046  rasterTransparency->setTransparentThreeValuePixelList( myTransparentThreeValuePixelList );
1047  }
1048  else if ( tableTransparency->columnCount() == 3 )
1049  {
1051  QList<QgsRasterTransparency::TransparentSingleValuePixel> myTransparentSingleValuePixelList;
1052  for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
1053  {
1054  myTransparentPixel.min = transparencyCellValue( myListRunner, 0 );
1055  myTransparentPixel.max = transparencyCellValue( myListRunner, 1 );
1056  myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 2 );
1057 
1058  myTransparentSingleValuePixelList.append( myTransparentPixel );
1059  }
1060  rasterTransparency->setTransparentSingleValuePixelList( myTransparentSingleValuePixelList );
1061  }
1062 
1063  rasterRenderer->setRasterTransparency( rasterTransparency );
1064 
1065  //set global transparency
1066  rasterRenderer->setOpacity( mOpacityWidget->opacity() );
1067  }
1068 
1069  QgsDebugMsgLevel( QStringLiteral( "processing general tab" ), 3 );
1070  /*
1071  * General Tab
1072  */
1073  mRasterLayer->setName( mLayerOrigNameLineEd->text() );
1074 
1075  // set up the scale based layer visibility stuff....
1076  mRasterLayer->setScaleBasedVisibility( chkUseScaleDependentRendering->isChecked() );
1077  mRasterLayer->setMinimumScale( mScaleRangeWidget->minimumScale() );
1078  mRasterLayer->setMaximumScale( mScaleRangeWidget->maximumScale() );
1079 
1080  mRasterLayer->setAutoRefreshInterval( mRefreshLayerIntervalSpinBox->value() * 1000.0 );
1081  mRasterLayer->setAutoRefreshEnabled( mRefreshLayerCheckBox->isChecked() );
1082 
1083  //update the legend pixmap
1084  // pixmapLegend->setPixmap( mRasterLayer->legendAsPixmap() );
1085  // pixmapLegend->setScaledContents( true );
1086  // pixmapLegend->repaint();
1087 
1088  mResamplingUtils.refreshLayerFromWidgets();
1089 
1090  // Hue and saturation controls
1091  QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter();
1092  if ( hueSaturationFilter )
1093  {
1094  hueSaturationFilter->setSaturation( sliderSaturation->value() );
1095  hueSaturationFilter->setGrayscaleMode( ( QgsHueSaturationFilter::GrayscaleMode ) comboGrayscale->currentIndex() );
1096  hueSaturationFilter->setColorizeOn( mColorizeCheck->checkState() );
1097  hueSaturationFilter->setColorizeColor( btnColorizeColor->color() );
1098  hueSaturationFilter->setColorizeStrength( sliderColorizeStrength->value() );
1099  }
1100 
1101  //set the blend mode for the layer
1102  mRasterLayer->setBlendMode( mBlendModeComboBox->blendMode() );
1103 
1104  updateSourceStaticTime();
1105 
1106  // Update temporal field
1107  if ( mRasterLayer->dataProvider() )
1108  {
1109  QgsDataSourceUri uri { mRasterLayer->dataProvider()->uri() };
1110  if ( mPostgresRasterTemporalGroup->isEnabled() &&
1111  mPostgresRasterTemporalGroup->isChecked() &&
1112  ! mPostgresRasterTemporalFieldComboBox->currentField().isEmpty() )
1113  {
1114  const QString originaUri { uri.uri() };
1115  const int fieldIdx { mRasterLayer->dataProvider()->fields().lookupField( mPostgresRasterTemporalFieldComboBox->currentField() ) };
1116  uri.removeParam( QStringLiteral( "temporalFieldIndex" ) );
1117  uri.removeParam( QStringLiteral( "temporalDefaultTime" ) );
1118  if ( fieldIdx >= 0 )
1119  {
1120  uri.setParam( QStringLiteral( "temporalFieldIndex" ), QString::number( fieldIdx ) );
1121  if ( mPostgresRasterDefaultTime->dateTime().isValid() )
1122  {
1123  QDateTime defaultDateTime { mPostgresRasterDefaultTime->dateTime() };
1124  const QTime defaultTime { defaultDateTime.time() };
1125  // Set secs to 0
1126  defaultDateTime.setTime( { defaultTime.hour(), defaultTime.minute(), 0 } );
1127  uri.setParam( QStringLiteral( "temporalDefaultTime" ), defaultDateTime.toString( Qt::DateFormat::ISODate ) );
1128  }
1129  if ( uri.uri( ) != originaUri )
1130  mRasterLayer->setDataSource( uri.uri(), mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );
1131  }
1132  }
1133  else if ( uri.hasParam( QStringLiteral( "temporalFieldIndex" ) ) )
1134  {
1135  uri.removeParam( QStringLiteral( "temporalFieldIndex" ) );
1136  uri.removeParam( QStringLiteral( "temporalDefaultTime" ) );
1137  mRasterLayer->setDataSource( uri.uri(), mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );
1138  }
1139  }
1140 
1141  // Update temporal properties
1142  mTemporalWidget->saveTemporalProperties();
1143 
1144  mRasterLayer->setCrs( mCrsSelector->crs() );
1145 
1146  if ( mRasterLayer->shortName() != mLayerShortNameLineEdit->text() )
1147  mMetadataFilled = false;
1148  mRasterLayer->setShortName( mLayerShortNameLineEdit->text() );
1149 
1150  if ( mRasterLayer->title() != mLayerTitleLineEdit->text() )
1151  mMetadataFilled = false;
1152  mRasterLayer->setTitle( mLayerTitleLineEdit->text() );
1153 
1154  if ( mRasterLayer->abstract() != mLayerAbstractTextEdit->toPlainText() )
1155  mMetadataFilled = false;
1156  mRasterLayer->setAbstract( mLayerAbstractTextEdit->toPlainText() );
1157 
1158  if ( mRasterLayer->keywordList() != mLayerKeywordListLineEdit->text() )
1159  mMetadataFilled = false;
1160  mRasterLayer->setKeywordList( mLayerKeywordListLineEdit->text() );
1161 
1162  if ( mRasterLayer->dataUrl() != mLayerDataUrlLineEdit->text() )
1163  mMetadataFilled = false;
1164  mRasterLayer->setDataUrl( mLayerDataUrlLineEdit->text() );
1165 
1166  if ( mRasterLayer->dataUrlFormat() != mLayerDataUrlFormatComboBox->currentText() )
1167  mMetadataFilled = false;
1168  mRasterLayer->setDataUrlFormat( mLayerDataUrlFormatComboBox->currentText() );
1169 
1170  //layer attribution and metadataUrl
1171  if ( mRasterLayer->attribution() != mLayerAttributionLineEdit->text() )
1172  mMetadataFilled = false;
1173  mRasterLayer->setAttribution( mLayerAttributionLineEdit->text() );
1174 
1175  if ( mRasterLayer->attributionUrl() != mLayerAttributionUrlLineEdit->text() )
1176  mMetadataFilled = false;
1177  mRasterLayer->setAttributionUrl( mLayerAttributionUrlLineEdit->text() );
1178 
1179  if ( mRasterLayer->metadataUrl() != mLayerMetadataUrlLineEdit->text() )
1180  mMetadataFilled = false;
1181  mRasterLayer->setMetadataUrl( mLayerMetadataUrlLineEdit->text() );
1182 
1183  if ( mRasterLayer->metadataUrlType() != mLayerMetadataUrlTypeComboBox->currentText() )
1184  mMetadataFilled = false;
1185  mRasterLayer->setMetadataUrlType( mLayerMetadataUrlTypeComboBox->currentText() );
1186 
1187  if ( mRasterLayer->metadataUrlFormat() != mLayerMetadataUrlFormatComboBox->currentText() )
1188  mMetadataFilled = false;
1189  mRasterLayer->setMetadataUrlFormat( mLayerMetadataUrlFormatComboBox->currentText() );
1190 
1191  if ( mRasterLayer->legendUrl() != mLayerLegendUrlLineEdit->text() )
1192  mMetadataFilled = false;
1193  mRasterLayer->setLegendUrl( mLayerLegendUrlLineEdit->text() );
1194 
1195  if ( mRasterLayer->legendUrlFormat() != mLayerLegendUrlFormatComboBox->currentText() )
1196  mMetadataFilled = false;
1197  mRasterLayer->setLegendUrlFormat( mLayerLegendUrlFormatComboBox->currentText() );
1198 
1199  if ( !mWMSPrintLayerLineEdit->text().isEmpty() )
1200  {
1201  mRasterLayer->setCustomProperty( QStringLiteral( "WMSPrintLayer" ), mWMSPrintLayerLineEdit->text() );
1202  }
1203 
1204  mRasterLayer->setCustomProperty( "WMSPublishDataSourceUrl", mPublishDataSourceUrlCheckBox->isChecked() );
1205  mRasterLayer->setCustomProperty( "WMSBackgroundLayer", mBackgroundLayerCheckBox->isChecked() );
1206 
1207  // Force a redraw of the legend
1208  mRasterLayer->setLegend( QgsMapLayerLegend::defaultRasterLegend( mRasterLayer ) );
1209 
1210  //make sure the layer is redrawn
1211  mRasterLayer->triggerRepaint();
1212 
1213  // notify the project we've made a change
1214  QgsProject::instance()->setDirty( true );
1215 }//apply
1216 
1217 void QgsRasterLayerProperties::updateSourceStaticTime()
1218 {
1220  mRasterLayer->providerType() );
1221  const QVariantMap currentUri = metadata->decodeUri( mRasterLayer->dataProvider()->dataSourceUri() );
1222 
1223  QVariantMap uri = currentUri;
1224 
1225  if ( mWmstGroup->isVisibleTo( this ) )
1226  uri[ QStringLiteral( "allowTemporalUpdates" ) ] = mWmstGroup->isChecked();
1227 
1228 
1229  if ( mWmstGroup->isEnabled() &&
1230  mRasterLayer->dataProvider() &&
1232  {
1233  bool enableTime = !mDisableTime->isChecked();
1234 
1235  uri[ QStringLiteral( "enableTime" ) ] = enableTime;
1236  qobject_cast< QgsRasterLayerTemporalProperties * >( mRasterLayer->temporalProperties() )->setIntervalHandlingMethod( static_cast< QgsRasterDataProviderTemporalCapabilities::IntervalHandlingMethod >(
1237  mFetchModeComboBox->currentData().toInt() ) );
1238 
1239  // Don't do static temporal updates if temporal properties are active
1240  if ( !mRasterLayer->temporalProperties()->isActive() )
1241  {
1242  if ( mStaticTemporalRange->isChecked() )
1243  {
1244  QString time = mStartStaticDateTimeEdit->dateTime().toString( Qt::ISODateWithMs ) + '/' +
1245  mEndStaticDateTimeEdit->dateTime().toString( Qt::ISODateWithMs );
1246  uri[ QStringLiteral( "time" ) ] = time;
1247  uri[ QStringLiteral( "temporalSource" ) ] = QLatin1String( "provider" );
1248  }
1249 
1250  if ( mProjectTemporalRange->isChecked() )
1251  {
1252  QgsDateTimeRange range;
1253 
1254  if ( QgsProject::instance()->timeSettings() )
1256  if ( range.begin().isValid() && range.end().isValid() )
1257  {
1258  QString time = range.begin().toString( Qt::ISODateWithMs ) + '/' +
1259  range.end().toString( Qt::ISODateWithMs );
1260 
1261  uri[ QStringLiteral( "time" ) ] = time;
1262  uri[ QStringLiteral( "temporalSource" ) ] = QLatin1String( "project" );
1263  }
1264  }
1265  }
1266 
1267  if ( mReferenceTime->isChecked() )
1268  {
1269  QString referenceTime = mReferenceDateTimeEdit->dateTime().toString( Qt::ISODateWithMs );
1270  uri[ QStringLiteral( "referenceTime" ) ] = referenceTime;
1271  }
1272  else
1273  {
1274  if ( uri.contains( QStringLiteral( "referenceTime" ) ) )
1275  uri.remove( QStringLiteral( "referenceTime" ) );
1276  }
1277  }
1278 
1279  if ( currentUri != uri )
1280  mRasterLayer->setDataSource( metadata->encodeUri( uri ), mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );
1281 }
1282 
1283 void QgsRasterLayerProperties::setSourceStaticTimeState()
1284 {
1285  if ( mRasterLayer->dataProvider() && mRasterLayer->dataProvider()->temporalCapabilities()->hasTemporalCapabilities() )
1286  {
1287  const QgsDateTimeRange availableProviderRange = mRasterLayer->dataProvider()->temporalCapabilities()->availableTemporalRange();
1288  const QgsDateTimeRange availableReferenceRange = mRasterLayer->dataProvider()->temporalCapabilities()->availableReferenceTemporalRange();
1289 
1291  mRasterLayer->providerType() );
1292 
1293  QVariantMap uri = metadata->decodeUri( mRasterLayer->dataProvider()->dataSourceUri() );
1294 
1295  mStartStaticDateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
1296  mEndStaticDateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
1297  mReferenceDateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
1298 
1299  // setup maximum extents for widgets, based on provider's capabilities
1300  if ( availableProviderRange.begin().isValid() && availableProviderRange.end().isValid() )
1301  {
1302  mStartStaticDateTimeEdit->setDateTimeRange( availableProviderRange.begin(),
1303  availableProviderRange.end() );
1304  mStartStaticDateTimeEdit->setDateTime( availableProviderRange.begin() );
1305  mEndStaticDateTimeEdit->setDateTimeRange( availableProviderRange.begin(),
1306  availableProviderRange.end() );
1307  mEndStaticDateTimeEdit->setDateTime( availableProviderRange.end() );
1308  }
1309  if ( availableReferenceRange.begin().isValid() && availableReferenceRange.end().isValid() )
1310  {
1311  mReferenceDateTimeEdit->setDateTimeRange( availableReferenceRange.begin(),
1312  availableReferenceRange.end() );
1313  mReferenceDateTimeEdit->setDateTime( availableReferenceRange.begin() );
1314  }
1315 
1316  const QString time = uri.value( QStringLiteral( "time" ) ).toString();
1317  if ( !time.isEmpty() )
1318  {
1319  QStringList parts = time.split( '/' );
1320  mStartStaticDateTimeEdit->setDateTime( QDateTime::fromString( parts.at( 0 ), Qt::ISODateWithMs ) );
1321  mEndStaticDateTimeEdit->setDateTime( QDateTime::fromString( parts.at( 1 ), Qt::ISODateWithMs ) );
1322  }
1323 
1324  const QString referenceTimeExtent = uri.value( QStringLiteral( "referenceTimeDimensionExtent" ) ).toString();
1325 
1326  mReferenceTime->setEnabled( !referenceTimeExtent.isEmpty() );
1327  mReferenceDateTimeEdit->setVisible( !referenceTimeExtent.isEmpty() );
1328 
1329  QString referenceTimeLabelText = referenceTimeExtent.isEmpty() ?
1330  tr( "There is no reference time in the layer's capabilities." ) : QString();
1331  mReferenceTimeLabel->setText( referenceTimeLabelText );
1332 
1333  const QString referenceTime = uri.value( QStringLiteral( "referenceTime" ) ).toString();
1334 
1335  mReferenceTime->setChecked( !referenceTime.isEmpty() );
1336 
1337  if ( !referenceTime.isEmpty() && !referenceTimeExtent.isEmpty() )
1338  {
1339  mReferenceDateTimeEdit->setDateTime( QDateTime::fromString( referenceTime, Qt::ISODateWithMs ) );
1340  }
1341 
1342  mFetchModeComboBox->addItem( tr( "Use Whole Temporal Range" ), QgsRasterDataProviderTemporalCapabilities::MatchUsingWholeRange );
1343  mFetchModeComboBox->addItem( tr( "Match to Start of Range" ), QgsRasterDataProviderTemporalCapabilities::MatchExactUsingStartOfRange );
1344  mFetchModeComboBox->addItem( tr( "Match to End of Range" ), QgsRasterDataProviderTemporalCapabilities::MatchExactUsingEndOfRange );
1345  mFetchModeComboBox->addItem( tr( "Closest Match to Start of Range" ), QgsRasterDataProviderTemporalCapabilities::FindClosestMatchToStartOfRange );
1346  mFetchModeComboBox->addItem( tr( "Closest Match to End of Range" ), QgsRasterDataProviderTemporalCapabilities::FindClosestMatchToEndOfRange );
1347  mFetchModeComboBox->setCurrentIndex( mFetchModeComboBox->findData( qobject_cast< QgsRasterLayerTemporalProperties * >( mRasterLayer->temporalProperties() )->intervalHandlingMethod() ) );
1348 
1349  const QString temporalSource = uri.value( QStringLiteral( "temporalSource" ) ).toString();
1350  bool enableTime = uri.value( QStringLiteral( "enableTime" ), true ).toBool();
1351 
1352  if ( temporalSource == QLatin1String( "provider" ) )
1353  mStaticTemporalRange->setChecked( !time.isEmpty() );
1354  else if ( temporalSource == QLatin1String( "project" ) )
1355  mProjectTemporalRange->setChecked( !time.isEmpty() );
1356 
1357  mDisableTime->setChecked( !enableTime );
1358 
1359  mWmstOptions->setEnabled( !mRasterLayer->temporalProperties()->isActive() );
1360 
1361  if ( mRasterLayer->temporalProperties()->isActive() )
1362  mWmstOptionsLabel->setText( tr( "The static temporal options below are disabled because the layer "
1363  "temporal properties are active, to enable them disable temporal properties "
1364  "in the temporal tab. " ) );
1365  QgsDateTimeRange range;
1366  if ( QgsProject::instance()->timeSettings() )
1368 
1369  if ( !range.begin().isValid() || !range.end().isValid() )
1370  {
1371  mProjectTemporalRange->setEnabled( false );
1372  mProjectTemporalRangeLabel->setText( tr( "The option below is disabled because the project temporal range "
1373  "is not valid, update the project temporal range in the project properties "
1374  "with valid values in order to use it here." ) );
1375  }
1376 
1377  mWmstGroup->setChecked( uri.contains( QStringLiteral( "allowTemporalUpdates" ) ) &&
1378  uri.value( QStringLiteral( "allowTemporalUpdates" ), true ).toBool() );
1379  }
1380 }
1381 
1382 void QgsRasterLayerProperties::staticTemporalRange_toggled( bool checked )
1383 {
1384  if ( checked )
1385  {
1386  mLabel->clear();
1387  }
1388 }
1389 
1390 void QgsRasterLayerProperties::passProjectTemporalRange_toggled( bool checked )
1391 {
1392  if ( checked )
1393  {
1394  QgsDateTimeRange range;
1395  if ( QgsProject::instance()->timeSettings() )
1397 
1398  if ( range.begin().isValid() && range.end().isValid() )
1399  mLabel->setText( tr( "Project temporal range is set from %1 to %2" ).arg(
1400  range.begin().toString( "yyyy-MM-dd HH:mm:ss" ),
1401  range.end().toString( "yyyy-MM-dd HH:mm:ss" )
1402  ) );
1403  else
1404  mLabel->setText( tr( "Project temporal range is not valid, can't use it here" ) );
1405  }
1406 }
1407 
1408 void QgsRasterLayerProperties::temporalPropertiesChange()
1409 {
1410  mWmstOptions->setEnabled( !mRasterLayer->temporalProperties()->isActive() );
1411 
1412  if ( mRasterLayer->temporalProperties()->isActive() )
1413  mWmstOptionsLabel->setText( tr( "The static temporal options below are disabled because the layer "
1414  "temporal properties are active, to enable them disable temporal properties "
1415  "in the temporal tab. " ) );
1416  else
1417  mWmstOptionsLabel->clear();
1418 }
1419 
1420 void QgsRasterLayerProperties::mLayerOrigNameLineEd_textEdited( const QString &text )
1421 {
1422  leDisplayName->setText( mRasterLayer->formatLayerName( text ) );
1423 }
1424 
1425 void QgsRasterLayerProperties::buttonBuildPyramids_clicked()
1426 {
1427  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
1428 
1429  std::unique_ptr< QgsRasterBlockFeedback > feedback( new QgsRasterBlockFeedback() );
1430 
1431  connect( feedback.get(), &QgsRasterBlockFeedback::progressChanged, mPyramidProgress, &QProgressBar::setValue );
1432  //
1433  // Go through the list marking any files that are selected in the listview
1434  // as true so that we can generate pyramids for them.
1435  //
1436  QList< QgsRasterPyramid> myPyramidList = provider->buildPyramidList();
1437  for ( int myCounterInt = 0; myCounterInt < lbxPyramidResolutions->count(); myCounterInt++ )
1438  {
1439  QListWidgetItem *myItem = lbxPyramidResolutions->item( myCounterInt );
1440  //mark to be pyramided
1441  myPyramidList[myCounterInt].build = myItem->isSelected() || myPyramidList[myCounterInt].exists;
1442  }
1443 
1444  // keep it in sync with qgsrasterpyramidsoptionwidget.cpp
1445  QString prefix = provider->name() + "/driverOptions/_pyramids/";
1446  QgsSettings mySettings;
1447  QString resamplingMethod( cboResamplingMethod->currentData().toString() );
1448  mySettings.setValue( prefix + "resampling", resamplingMethod );
1449 
1450  //
1451  // Ask raster layer to build the pyramids
1452  //
1453 
1454  // let the user know we're going to possibly be taking a while
1455  QApplication::setOverrideCursor( Qt::WaitCursor );
1456  QString res = provider->buildPyramids(
1457  myPyramidList,
1458  resamplingMethod,
1459  ( QgsRaster::RasterPyramidsFormat ) cbxPyramidsFormat->currentIndex(),
1460  QStringList(),
1461  feedback.get() );
1462  QApplication::restoreOverrideCursor();
1463  mPyramidProgress->setValue( 0 );
1464  buttonBuildPyramids->setEnabled( false );
1465  if ( !res.isNull() )
1466  {
1467  if ( res == QLatin1String( "CANCELED" ) )
1468  {
1469  // user canceled
1470  }
1471  else if ( res == QLatin1String( "ERROR_WRITE_ACCESS" ) )
1472  {
1473  QMessageBox::warning( this, tr( "Building Pyramids" ),
1474  tr( "Write access denied. Adjust the file permissions and try again." ) );
1475  }
1476  else if ( res == QLatin1String( "ERROR_WRITE_FORMAT" ) )
1477  {
1478  QMessageBox::warning( this, tr( "Building Pyramids" ),
1479  tr( "The file was not writable. Some formats do not "
1480  "support pyramid overviews. Consult the GDAL documentation if in doubt." ) );
1481  }
1482  else if ( res == QLatin1String( "FAILED_NOT_SUPPORTED" ) )
1483  {
1484  QMessageBox::warning( this, tr( "Building Pyramids" ),
1485  tr( "Building pyramid overviews is not supported on this type of raster." ) );
1486  }
1487  else if ( res == QLatin1String( "ERROR_JPEG_COMPRESSION" ) )
1488  {
1489  QMessageBox::warning( this, tr( "Building Pyramids" ),
1490  tr( "Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." ) );
1491  }
1492  else if ( res == QLatin1String( "ERROR_VIRTUAL" ) )
1493  {
1494  QMessageBox::warning( this, tr( "Building Pyramids" ),
1495  tr( "Building pyramid overviews is not supported on this type of raster." ) );
1496  }
1497 
1498  }
1499 
1500  //
1501  // repopulate the pyramids list
1502  //
1503  lbxPyramidResolutions->clear();
1504  // Need to rebuild list as some or all pyramids may have failed to build
1505  myPyramidList = provider->buildPyramidList();
1506  QIcon myPyramidPixmap( QgsApplication::getThemeIcon( "/mIconPyramid.svg" ) );
1507  QIcon myNoPyramidPixmap( QgsApplication::getThemeIcon( "/mIconNoPyramid.svg" ) );
1508 
1509  QList< QgsRasterPyramid >::iterator myRasterPyramidIterator;
1510  for ( myRasterPyramidIterator = myPyramidList.begin();
1511  myRasterPyramidIterator != myPyramidList.end();
1512  ++myRasterPyramidIterator )
1513  {
1514  if ( myRasterPyramidIterator->exists )
1515  {
1516  lbxPyramidResolutions->addItem( new QListWidgetItem( myPyramidPixmap,
1517  QString::number( myRasterPyramidIterator->xDim ) + QStringLiteral( " x " ) +
1518  QString::number( myRasterPyramidIterator->yDim ) ) );
1519  }
1520  else
1521  {
1522  lbxPyramidResolutions->addItem( new QListWidgetItem( myNoPyramidPixmap,
1523  QString::number( myRasterPyramidIterator->xDim ) + QStringLiteral( " x " ) +
1524  QString::number( myRasterPyramidIterator->yDim ) ) );
1525  }
1526  }
1527  //update the legend pixmap
1528  // pixmapLegend->setPixmap( mRasterLayer->legendAsPixmap() );
1529  // pixmapLegend->setScaledContents( true );
1530  // pixmapLegend->repaint();
1531 
1532  //populate the metadata tab's text browser widget with gdal metadata info
1533  updateInformationContent();
1534 }
1535 
1536 void QgsRasterLayerProperties::urlClicked( const QUrl &url )
1537 {
1538  QFileInfo file( url.toLocalFile() );
1539  if ( file.exists() && !file.isDir() )
1540  QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
1541  else
1542  QDesktopServices::openUrl( url );
1543 }
1544 
1545 void QgsRasterLayerProperties::mRenderTypeComboBox_currentIndexChanged( int index )
1546 {
1547  if ( index < 0 || mDisableRenderTypeComboBoxCurrentIndexChanged || ! mRasterLayer->renderer() )
1548  {
1549  return;
1550  }
1551 
1552  QString rendererName = mRenderTypeComboBox->itemData( index ).toString();
1553  setRendererWidget( rendererName );
1554 }
1555 
1556 void QgsRasterLayerProperties::pbnAddValuesFromDisplay_clicked()
1557 {
1558  if ( mMapCanvas && mPixelSelectorTool )
1559  {
1560  //Need to work around the modality of the dialog but can not just hide() it.
1561  // According to Qt5 docs, to change modality the dialog needs to be hidden
1562  // and shown again.
1563  hide();
1564  setModal( false );
1565 
1566  // Transfer focus to the canvas to use the selector tool
1567  mMapCanvas->window()->raise();
1568  mMapCanvas->window()->activateWindow();
1569  mMapCanvas->window()->setFocus();
1570  mMapCanvas->setMapTool( mPixelSelectorTool.get() );
1571 
1572  }
1573 }
1574 
1575 void QgsRasterLayerProperties::pbnAddValuesManually_clicked()
1576 {
1577  QgsRasterRenderer *renderer = mRendererWidget->renderer();
1578  if ( !renderer )
1579  {
1580  return;
1581  }
1582 
1583  tableTransparency->insertRow( tableTransparency->rowCount() );
1584 
1585  int n = renderer->usesBands().size();
1586  if ( n == 1 ) n++;
1587 
1588  for ( int i = 0; i < n; i++ )
1589  {
1590  setTransparencyCell( tableTransparency->rowCount() - 1, i, std::numeric_limits<double>::quiet_NaN() );
1591  }
1592 
1593  setTransparencyCell( tableTransparency->rowCount() - 1, n, 100 );
1594 
1595  tableTransparency->resizeColumnsToContents();
1596  tableTransparency->resizeRowsToContents();
1597 }
1598 
1599 void QgsRasterLayerProperties::mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem &crs )
1600 {
1601  QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mMapCanvas, tr( "Select Transformation" ) );
1602  mRasterLayer->setCrs( crs );
1603  mMetadataWidget->crsChanged();
1604 }
1605 
1606 void QgsRasterLayerProperties::pbnDefaultValues_clicked()
1607 {
1608  if ( !mRendererWidget )
1609  {
1610  return;
1611  }
1612 
1613  QgsRasterRenderer *r = mRendererWidget->renderer();
1614  if ( !r )
1615  {
1616  return;
1617  }
1618 
1619  int nBands = r->usesBands().size();
1620  delete r; // really delete?
1621 
1622  setupTransparencyTable( nBands );
1623 
1624  tableTransparency->resizeColumnsToContents(); // works only with values
1625  tableTransparency->resizeRowsToContents();
1626 }
1627 
1628 void QgsRasterLayerProperties::setTransparencyCell( int row, int column, double value )
1629 {
1630  QgsDebugMsgLevel( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ), 3 );
1631  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
1632  if ( !provider ) return;
1633 
1634  QgsRasterRenderer *renderer = mRendererWidget->renderer();
1635  if ( !renderer ) return;
1636  int nBands = renderer->usesBands().size();
1637 
1638  QLineEdit *lineEdit = new QLineEdit();
1639  lineEdit->setFrame( false ); // frame looks bad in table
1640  // Without margins row selection is not displayed (important for delete row)
1641  lineEdit->setContentsMargins( 1, 1, 1, 1 );
1642 
1643  if ( column == tableTransparency->columnCount() - 1 )
1644  {
1645  // transparency
1646  // Who needs transparency as floating point?
1647  lineEdit->setValidator( new QIntValidator( nullptr ) );
1648  lineEdit->setText( QString::number( static_cast<int>( value ) ) );
1649  }
1650  else
1651  {
1652  // value
1653  QString valueString;
1654  switch ( provider->sourceDataType( 1 ) )
1655  {
1656  case Qgis::Float32:
1657  case Qgis::Float64:
1658  lineEdit->setValidator( new QgsDoubleValidator( nullptr ) );
1659  if ( !std::isnan( value ) )
1660  {
1661  double v = QgsRasterBlock::printValue( value ).toDouble();
1662  valueString = QLocale().toString( v, 'g' ) ;
1663  }
1664  break;
1665  default:
1666  lineEdit->setValidator( new QIntValidator( nullptr ) );
1667  if ( !std::isnan( value ) )
1668  {
1669  valueString = QLocale().toString( static_cast<int>( value ) );
1670  }
1671  break;
1672  }
1673  lineEdit->setText( valueString );
1674  }
1675  tableTransparency->setCellWidget( row, column, lineEdit );
1676  adjustTransparencyCellWidth( row, column );
1677 
1678  if ( nBands == 1 && ( column == 0 || column == 1 ) )
1679  {
1680  connect( lineEdit, &QLineEdit::textEdited, this, &QgsRasterLayerProperties::transparencyCellTextEdited );
1681  }
1682  tableTransparency->resizeColumnsToContents();
1683 }
1684 
1685 void QgsRasterLayerProperties::setTransparencyCellValue( int row, int column, double value )
1686 {
1687  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
1688  if ( !lineEdit ) return;
1689  double v = QgsRasterBlock::printValue( value ).toDouble();
1690  lineEdit->setText( QLocale().toString( v, 'g' ) );
1691  lineEdit->adjustSize();
1692  adjustTransparencyCellWidth( row, column );
1693  tableTransparency->resizeColumnsToContents();
1694 }
1695 
1696 double QgsRasterLayerProperties::transparencyCellValue( int row, int column )
1697 {
1698  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
1699  if ( !lineEdit || lineEdit->text().isEmpty() )
1700  {
1701  return std::numeric_limits<double>::quiet_NaN();
1702  }
1703  return lineEdit->text().toDouble();
1704 }
1705 
1706 void QgsRasterLayerProperties::adjustTransparencyCellWidth( int row, int column )
1707 {
1708  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
1709  if ( !lineEdit ) return;
1710 
1711  int width = std::max( lineEdit->fontMetrics().boundingRect( lineEdit->text() ).width() + 10, 100 );
1712  width = std::max( width, tableTransparency->columnWidth( column ) );
1713 
1714  lineEdit->setFixedWidth( width );
1715 }
1716 
1717 void QgsRasterLayerProperties::pbnExportTransparentPixelValues_clicked()
1718 {
1719  QgsSettings myQSettings;
1720  QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
1721  QString myFileName = QFileDialog::getSaveFileName( this, tr( "Save File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
1722  if ( !myFileName.isEmpty() )
1723  {
1724  if ( !myFileName.endsWith( QLatin1String( ".txt" ), Qt::CaseInsensitive ) )
1725  {
1726  myFileName = myFileName + ".txt";
1727  }
1728 
1729  QFile myOutputFile( myFileName );
1730  if ( myOutputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
1731  {
1732  QTextStream myOutputStream( &myOutputFile );
1733  myOutputStream << "# " << tr( "QGIS Generated Transparent Pixel Value Export File" ) << '\n';
1734  if ( rasterIsMultiBandColor() )
1735  {
1736  myOutputStream << "#\n#\n# " << tr( "Red" ) << "\t" << tr( "Green" ) << "\t" << tr( "Blue" ) << "\t" << tr( "Percent Transparent" );
1737  for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
1738  {
1739  myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
1740  << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
1741  << QString::number( transparencyCellValue( myTableRunner, 2 ) ) << "\t"
1742  << QString::number( transparencyCellValue( myTableRunner, 3 ) );
1743  }
1744  }
1745  else
1746  {
1747  myOutputStream << "#\n#\n# " << tr( "Value" ) << "\t" << tr( "Percent Transparent" );
1748 
1749  for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
1750  {
1751  myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
1752  << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
1753  << QString::number( transparencyCellValue( myTableRunner, 2 ) );
1754  }
1755  }
1756  }
1757  else
1758  {
1759  QMessageBox::warning( this, tr( "Export Transparent Pixels" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
1760  }
1761  }
1762 }
1763 
1764 void QgsRasterLayerProperties::transparencyCellTextEdited( const QString &text )
1765 {
1766  Q_UNUSED( text )
1767  QgsDebugMsgLevel( QStringLiteral( "text = %1" ).arg( text ), 3 );
1768  QgsRasterRenderer *renderer = mRendererWidget->renderer();
1769  if ( !renderer )
1770  {
1771  return;
1772  }
1773  int nBands = renderer->usesBands().size();
1774  if ( nBands == 1 )
1775  {
1776  QLineEdit *lineEdit = qobject_cast<QLineEdit *>( sender() );
1777  if ( !lineEdit ) return;
1778  int row = -1;
1779  int column = -1;
1780  for ( int r = 0; r < tableTransparency->rowCount(); r++ )
1781  {
1782  for ( int c = 0; c < tableTransparency->columnCount(); c++ )
1783  {
1784  if ( tableTransparency->cellWidget( r, c ) == sender() )
1785  {
1786  row = r;
1787  column = c;
1788  break;
1789  }
1790  }
1791  if ( row != -1 ) break;
1792  }
1793  QgsDebugMsgLevel( QStringLiteral( "row = %1 column =%2" ).arg( row ).arg( column ), 3 );
1794 
1795  if ( column == 0 )
1796  {
1797  QLineEdit *toLineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, 1 ) );
1798  if ( !toLineEdit ) return;
1799  bool toChanged = mTransparencyToEdited.value( row );
1800  QgsDebugMsgLevel( QStringLiteral( "toChanged = %1" ).arg( toChanged ), 3 );
1801  if ( !toChanged )
1802  {
1803  toLineEdit->setText( lineEdit->text() );
1804  }
1805  }
1806  else if ( column == 1 )
1807  {
1808  setTransparencyToEdited( row );
1809  }
1810  }
1811 }
1812 
1813 void QgsRasterLayerProperties::aboutToShowStyleMenu()
1814 {
1815  // this should be unified with QgsVectorLayerProperties::aboutToShowStyleMenu()
1816 
1817  QMenu *m = qobject_cast<QMenu *>( sender() );
1818 
1820  // re-add style manager actions!
1821  m->addSeparator();
1823 }
1824 
1825 void QgsRasterLayerProperties::syncToLayer()
1826 {
1827  QgsRasterRenderer *renderer = mRasterLayer->renderer();
1828  if ( renderer )
1829  {
1830  setRendererWidget( renderer->type() );
1831  }
1832  sync();
1833  mRasterLayer->triggerRepaint();
1834 }
1835 
1836 void QgsRasterLayerProperties::setTransparencyToEdited( int row )
1837 {
1838  if ( row >= mTransparencyToEdited.size() )
1839  {
1840  mTransparencyToEdited.resize( row + 1 );
1841  }
1842  mTransparencyToEdited[row] = true;
1843 }
1844 
1846 {
1848 
1849  bool isMetadataPanel = ( index == mOptStackedWidget->indexOf( mOptsPage_Metadata ) );
1850  mBtnStyle->setVisible( ! isMetadataPanel );
1851  mBtnMetadata->setVisible( isMetadataPanel );
1852 
1853  if ( !mHistogramWidget )
1854  return;
1855 
1856  if ( index == mOptStackedWidget->indexOf( mOptsPage_Histogram ) )
1857  {
1858  mHistogramWidget->setActive( true );
1859  }
1860  else
1861  {
1862  mHistogramWidget->setActive( false );
1863  }
1864 
1865  if ( index == mOptStackedWidget->indexOf( mOptsPage_Information ) || !mMetadataFilled )
1866  {
1867  //set the metadata contents (which can be expensive)
1868  updateInformationContent();
1869  }
1870 }
1871 
1872 void QgsRasterLayerProperties::setEndAsStartStaticButton_clicked()
1873 {
1874  mEndStaticDateTimeEdit->setDateTime( mStartStaticDateTimeEdit->dateTime() );
1875 }
1876 
1877 void QgsRasterLayerProperties::pbnImportTransparentPixelValues_clicked()
1878 {
1879  int myLineCounter = 0;
1880  bool myImportError = false;
1881  QString myBadLines;
1882  QgsSettings myQSettings;
1883  QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
1884  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Open file" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
1885  QFile myInputFile( myFileName );
1886  if ( myInputFile.open( QFile::ReadOnly ) )
1887  {
1888  QTextStream myInputStream( &myInputFile );
1889  QString myInputLine;
1890  if ( rasterIsMultiBandColor() )
1891  {
1892  for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
1893  {
1894  tableTransparency->removeRow( myTableRunner );
1895  }
1896 
1897  while ( !myInputStream.atEnd() )
1898  {
1899  myLineCounter++;
1900  myInputLine = myInputStream.readLine();
1901  if ( !myInputLine.isEmpty() )
1902  {
1903  if ( !myInputLine.simplified().startsWith( '#' ) )
1904  {
1905  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
1906  if ( myTokens.count() != 4 )
1907  {
1908  myImportError = true;
1909  myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
1910  }
1911  else
1912  {
1913  tableTransparency->insertRow( tableTransparency->rowCount() );
1914  for ( int col = 0; col < 4; col++ )
1915  {
1916  setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
1917  }
1918  }
1919  }
1920  }
1921  }
1922  }
1923  else
1924  {
1925  for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
1926  {
1927  tableTransparency->removeRow( myTableRunner );
1928  }
1929 
1930  while ( !myInputStream.atEnd() )
1931  {
1932  myLineCounter++;
1933  myInputLine = myInputStream.readLine();
1934  if ( !myInputLine.isEmpty() )
1935  {
1936  if ( !myInputLine.simplified().startsWith( '#' ) )
1937  {
1938  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
1939  if ( myTokens.count() != 3 && myTokens.count() != 2 ) // 2 for QGIS < 1.9 compatibility
1940  {
1941  myImportError = true;
1942  myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
1943  }
1944  else
1945  {
1946  if ( myTokens.count() == 2 )
1947  {
1948  myTokens.insert( 1, myTokens[0] ); // add 'to' value, QGIS < 1.9 compatibility
1949  }
1950  tableTransparency->insertRow( tableTransparency->rowCount() );
1951  for ( int col = 0; col < 3; col++ )
1952  {
1953  setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
1954  }
1955  }
1956  }
1957  }
1958  }
1959  }
1960 
1961  if ( myImportError )
1962  {
1963  QMessageBox::warning( this, tr( "Import Transparent Pixels" ), tr( "The following lines contained errors\n\n%1" ).arg( myBadLines ) );
1964  }
1965  }
1966  else if ( !myFileName.isEmpty() )
1967  {
1968  QMessageBox::warning( this, tr( "Import Transparent Pixels" ), tr( "Read access denied. Adjust the file permissions and try again.\n\n" ) );
1969  }
1970  tableTransparency->resizeColumnsToContents();
1971  tableTransparency->resizeRowsToContents();
1972 }
1973 
1974 void QgsRasterLayerProperties::pbnRemoveSelectedRow_clicked()
1975 {
1976  if ( 0 < tableTransparency->rowCount() )
1977  {
1978  tableTransparency->removeRow( tableTransparency->currentRow() );
1979  }
1980 }
1981 
1982 void QgsRasterLayerProperties::pixelSelected( const QgsPointXY &canvasPoint, const Qt::MouseButton &btn )
1983 {
1984  Q_UNUSED( btn )
1985  QgsRasterRenderer *renderer = mRendererWidget->renderer();
1986  if ( !renderer )
1987  {
1988  return;
1989  }
1990 
1991  //Get the pixel values and add a new entry to the transparency table
1992  if ( mMapCanvas && mPixelSelectorTool )
1993  {
1994  mMapCanvas->unsetMapTool( mPixelSelectorTool.get() );
1995 
1996  const QgsMapSettings &ms = mMapCanvas->mapSettings();
1997  QgsPointXY myPoint = ms.mapToLayerCoordinates( mRasterLayer, canvasPoint );
1998 
1999  QgsRectangle myExtent = ms.mapToLayerCoordinates( mRasterLayer, mMapCanvas->extent() );
2000  double mapUnitsPerPixel = mMapCanvas->mapUnitsPerPixel();
2001  int myWidth = mMapCanvas->extent().width() / mapUnitsPerPixel;
2002  int myHeight = mMapCanvas->extent().height() / mapUnitsPerPixel;
2003 
2004  QMap<int, QVariant> myPixelMap = mRasterLayer->dataProvider()->identify( myPoint, QgsRaster::IdentifyFormatValue, myExtent, myWidth, myHeight ).results();
2005 
2006  QList<int> bands = renderer->usesBands();
2007 
2008  QList<double> values;
2009  for ( int i = 0; i < bands.size(); ++i )
2010  {
2011  int bandNo = bands.value( i );
2012  if ( myPixelMap.count( bandNo ) == 1 )
2013  {
2014  if ( myPixelMap.value( bandNo ).isNull() )
2015  {
2016  return; // Don't add nodata, transparent anyway
2017  }
2018  double value = myPixelMap.value( bandNo ).toDouble();
2019  QgsDebugMsgLevel( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ), 3 );
2020  values.append( value );
2021  }
2022  }
2023  if ( bands.size() == 1 )
2024  {
2025  // Set 'to'
2026  values.insert( 1, values.value( 0 ) );
2027  }
2028  tableTransparency->insertRow( tableTransparency->rowCount() );
2029  for ( int i = 0; i < values.size(); i++ )
2030  {
2031  setTransparencyCell( tableTransparency->rowCount() - 1, i, values.value( i ) );
2032  }
2033  setTransparencyCell( tableTransparency->rowCount() - 1, tableTransparency->columnCount() - 1, 100 );
2034  }
2035  delete renderer;
2036 
2037  tableTransparency->resizeColumnsToContents();
2038  tableTransparency->resizeRowsToContents();
2039 }
2040 
2041 void QgsRasterLayerProperties::toggleSaturationControls( int grayscaleMode )
2042 {
2043  // Enable or disable saturation controls based on choice of grayscale mode
2044  if ( grayscaleMode == 0 )
2045  {
2046  sliderSaturation->setEnabled( true );
2047  spinBoxSaturation->setEnabled( true );
2048  }
2049  else
2050  {
2051  sliderSaturation->setEnabled( false );
2052  spinBoxSaturation->setEnabled( false );
2053  }
2054 }
2055 
2056 void QgsRasterLayerProperties::toggleColorizeControls( bool colorizeEnabled )
2057 {
2058  // Enable or disable colorize controls based on checkbox
2059  btnColorizeColor->setEnabled( colorizeEnabled );
2060  sliderColorizeStrength->setEnabled( colorizeEnabled );
2061  spinColorizeStrength->setEnabled( colorizeEnabled );
2062 }
2063 
2064 
2065 QLinearGradient QgsRasterLayerProperties::redGradient()
2066 {
2067  //define a gradient
2068  // TODO change this to actual polygon dims
2069  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
2070  myGradient.setColorAt( 0.0, QColor( 242, 14, 25, 190 ) );
2071  myGradient.setColorAt( 0.5, QColor( 175, 29, 37, 190 ) );
2072  myGradient.setColorAt( 1.0, QColor( 114, 17, 22, 190 ) );
2073  return myGradient;
2074 }
2075 QLinearGradient QgsRasterLayerProperties::greenGradient()
2076 {
2077  //define a gradient
2078  // TODO change this to actual polygon dims
2079  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
2080  myGradient.setColorAt( 0.0, QColor( 48, 168, 5, 190 ) );
2081  myGradient.setColorAt( 0.8, QColor( 36, 122, 4, 190 ) );
2082  myGradient.setColorAt( 1.0, QColor( 21, 71, 2, 190 ) );
2083  return myGradient;
2084 }
2085 QLinearGradient QgsRasterLayerProperties::blueGradient()
2086 {
2087  //define a gradient
2088  // TODO change this to actual polygon dims
2089  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
2090  myGradient.setColorAt( 0.0, QColor( 30, 0, 106, 190 ) );
2091  myGradient.setColorAt( 0.2, QColor( 30, 72, 128, 190 ) );
2092  myGradient.setColorAt( 1.0, QColor( 30, 223, 196, 190 ) );
2093  return myGradient;
2094 }
2095 QLinearGradient QgsRasterLayerProperties::grayGradient()
2096 {
2097  //define a gradient
2098  // TODO change this to actual polygon dims
2099  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
2100  myGradient.setColorAt( 0.0, QColor( 5, 5, 5, 190 ) );
2101  myGradient.setColorAt( 0.8, QColor( 122, 122, 122, 190 ) );
2102  myGradient.setColorAt( 1.0, QColor( 220, 220, 220, 190 ) );
2103  return myGradient;
2104 }
2105 QLinearGradient QgsRasterLayerProperties::highlightGradient()
2106 {
2107  //define another gradient for the highlight
2108  // TODO change this to actual polygon dims
2109  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
2110  myGradient.setColorAt( 1.0, QColor( 255, 255, 255, 50 ) );
2111  myGradient.setColorAt( 0.5, QColor( 255, 255, 255, 100 ) );
2112  myGradient.setColorAt( 0.0, QColor( 255, 255, 255, 150 ) );
2113  return myGradient;
2114 }
2115 
2116 
2117 
2118 //
2119 //
2120 // Next four methods for saving and restoring qml style state
2121 //
2122 //
2123 void QgsRasterLayerProperties::loadDefaultStyle_clicked()
2124 {
2125  bool defaultLoadedFlag = false;
2126  QString myMessage = mRasterLayer->loadDefaultStyle( defaultLoadedFlag );
2127  //reset if the default style was loaded OK only
2128  if ( defaultLoadedFlag )
2129  {
2130  syncToLayer();
2131  }
2132  else
2133  {
2134  //otherwise let the user know what went wrong
2135  QMessageBox::information( this,
2136  tr( "Default Style" ),
2137  myMessage
2138  );
2139  }
2140 }
2141 
2142 void QgsRasterLayerProperties::saveDefaultStyle_clicked()
2143 {
2144 
2145  apply(); // make sure the style to save is up-to-date
2146 
2147  // a flag passed by reference
2148  bool defaultSavedFlag = false;
2149  // after calling this the above flag will be set true for success
2150  // or false if the save operation failed
2151  QString myMessage = mRasterLayer->saveDefaultStyle( defaultSavedFlag );
2152  if ( !defaultSavedFlag )
2153  {
2154  //let the user know what went wrong
2155  QMessageBox::information( this,
2156  tr( "Default Style" ),
2157  myMessage
2158  );
2159  }
2160 }
2161 
2162 
2163 void QgsRasterLayerProperties::loadStyle_clicked()
2164 {
2165  QgsSettings settings;
2166  QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
2167 
2168  QString fileName = QFileDialog::getOpenFileName(
2169  this,
2170  tr( "Load layer properties from style file" ),
2171  lastUsedDir,
2172  tr( "QGIS Layer Style File" ) + " (*.qml)" );
2173  if ( fileName.isEmpty() )
2174  return;
2175 
2176  // ensure the user never omits the extension from the file name
2177  if ( !fileName.endsWith( QLatin1String( ".qml" ), Qt::CaseInsensitive ) )
2178  fileName += QLatin1String( ".qml" );
2179 
2180  mOldStyle = mRasterLayer->styleManager()->style( mRasterLayer->styleManager()->currentStyle() );
2181 
2182  bool defaultLoadedFlag = false;
2183  QString message = mRasterLayer->loadNamedStyle( fileName, defaultLoadedFlag );
2184  if ( defaultLoadedFlag )
2185  {
2186  settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( fileName ).absolutePath() );
2187  syncToLayer();
2188  }
2189  else
2190  {
2191  QMessageBox::information( this, tr( "Save Style" ), message );
2192  }
2193 }
2194 
2195 
2196 void QgsRasterLayerProperties::saveStyleAs_clicked()
2197 {
2198  QgsSettings settings;
2199  QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
2200 
2201  QString selectedFilter;
2202  QString outputFileName = QFileDialog::getSaveFileName(
2203  this,
2204  tr( "Save layer properties as style file" ),
2205  lastUsedDir,
2206  tr( "QGIS Layer Style File" ) + " (*.qml)" + ";;" + tr( "Styled Layer Descriptor" ) + " (*.sld)",
2207  &selectedFilter );
2208  if ( outputFileName.isEmpty() )
2209  return;
2210 
2211  StyleType type;
2212  // use selectedFilter to set style type
2213  if ( selectedFilter.contains( QStringLiteral( ".qml" ), Qt::CaseInsensitive ) )
2214  {
2215  outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "qml" ) );
2216  type = StyleType::QML;
2217  }
2218  else
2219  {
2220  outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "sld" ) );
2221  type = StyleType::SLD;
2222  }
2223 
2224  apply(); // make sure the style to save is up-to-date
2225 
2226  // then export style
2227  bool defaultLoadedFlag = false;
2228  QString message;
2229  switch ( type )
2230  {
2231  case QML:
2232  {
2233  message = mRasterLayer->saveNamedStyle( outputFileName, defaultLoadedFlag );
2234  break;
2235  }
2236  case SLD:
2237  {
2238  message = mRasterLayer->saveSldStyle( outputFileName, defaultLoadedFlag );
2239  break;
2240  }
2241  }
2242  if ( defaultLoadedFlag )
2243  {
2244  settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( outputFileName ).absolutePath() );
2245  sync();
2246  }
2247  else
2248  QMessageBox::information( this, tr( "Save Style" ), message );
2249 }
2250 
2251 void QgsRasterLayerProperties::restoreWindowModality()
2252 {
2253  hide();
2254  setModal( true );
2255  show();
2256  raise();
2257  activateWindow();
2258 }
2259 
2260 //
2261 //
2262 // Next four methods for saving and restoring QMD metadata
2263 //
2264 //
2265 
2266 void QgsRasterLayerProperties::loadMetadata()
2267 {
2268  QgsSettings myQSettings; // where we keep last used filter in persistent state
2269  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
2270 
2271  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer metadata from metadata file" ), myLastUsedDir,
2272  tr( "QGIS Layer Metadata File" ) + " (*.qmd)" );
2273  if ( myFileName.isNull() )
2274  {
2275  return;
2276  }
2277 
2278  QString myMessage;
2279  bool defaultLoadedFlag = false;
2280  myMessage = mRasterLayer->loadNamedMetadata( myFileName, defaultLoadedFlag );
2281 
2282  //reset if the default style was loaded OK only
2283  if ( defaultLoadedFlag )
2284  {
2285  mMetadataWidget->setMetadata( &mRasterLayer->metadata() );
2286  }
2287  else
2288  {
2289  //let the user know what went wrong
2290  QMessageBox::warning( this, tr( "Load Metadata" ), myMessage );
2291  }
2292 
2293  QFileInfo myFI( myFileName );
2294  QString myPath = myFI.path();
2295  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
2296 
2297  activateWindow(); // set focus back to properties dialog
2298 }
2299 
2300 void QgsRasterLayerProperties::saveMetadataAs()
2301 {
2302  QgsSettings myQSettings; // where we keep last used filter in persistent state
2303  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
2304 
2305  QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save Layer Metadata as QMD" ),
2306  myLastUsedDir, tr( "QMD File" ) + " (*.qmd)" );
2307  if ( myOutputFileName.isNull() ) //dialog canceled
2308  {
2309  return;
2310  }
2311 
2312  mMetadataWidget->acceptMetadata();
2313 
2314  //ensure the user never omitted the extension from the file name
2315  if ( !myOutputFileName.endsWith( QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata ), Qt::CaseInsensitive ) )
2316  {
2318  }
2319 
2320  bool defaultLoadedFlag = false;
2321  QString message = mRasterLayer->saveNamedMetadata( myOutputFileName, defaultLoadedFlag );
2322  if ( defaultLoadedFlag )
2323  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( myOutputFileName ).absolutePath() );
2324  else
2325  QMessageBox::information( this, tr( "Save Metadata" ), message );
2326 }
2327 
2328 void QgsRasterLayerProperties::saveDefaultMetadata()
2329 {
2330  mMetadataWidget->acceptMetadata();
2331 
2332  bool defaultSavedFlag = false;
2333  QString errorMsg = mRasterLayer->saveDefaultMetadata( defaultSavedFlag );
2334  if ( !defaultSavedFlag )
2335  {
2336  QMessageBox::warning( this, tr( "Default Metadata" ), errorMsg );
2337  }
2338 }
2339 
2340 void QgsRasterLayerProperties::loadDefaultMetadata()
2341 {
2342  bool defaultLoadedFlag = false;
2343  QString myMessage = mRasterLayer->loadNamedMetadata( mRasterLayer->metadataUri(), defaultLoadedFlag );
2344  //reset if the default metadata was loaded OK only
2345  if ( defaultLoadedFlag )
2346  {
2347  mMetadataWidget->setMetadata( &mRasterLayer->metadata() );
2348  }
2349  else
2350  {
2351  QMessageBox::information( this, tr( "Default Metadata" ), myMessage );
2352  }
2353 }
2354 
2355 
2356 void QgsRasterLayerProperties::toggleBuildPyramidsButton()
2357 {
2358  if ( lbxPyramidResolutions->selectedItems().empty() )
2359  {
2360  buttonBuildPyramids->setEnabled( false );
2361  }
2362  else
2363  {
2364  buttonBuildPyramids->setEnabled( true );
2365  }
2366 }
2367 
2368 void QgsRasterLayerProperties::mResetColorRenderingBtn_clicked()
2369 {
2370  mBlendModeComboBox->setBlendMode( QPainter::CompositionMode_SourceOver );
2371  mSliderBrightness->setValue( 0 );
2372  mSliderContrast->setValue( 0 );
2373  mGammaSpinBox->setValue( 1.0 );
2374  sliderSaturation->setValue( 0 );
2375  comboGrayscale->setCurrentIndex( ( int ) QgsHueSaturationFilter::GrayscaleOff );
2376  mColorizeCheck->setChecked( false );
2377  sliderColorizeStrength->setValue( 100 );
2378 }
2379 
2380 bool QgsRasterLayerProperties::rasterIsMultiBandColor()
2381 {
2382  return mRasterLayer && nullptr != dynamic_cast<QgsMultiBandColorRenderer *>( mRasterLayer->renderer() );
2383 }
2384 
2385 void QgsRasterLayerProperties::updateInformationContent()
2386 {
2387  const QString myStyle = QgsApplication::reportStyleSheet( QgsApplication::StyleSheetType::WebBrowser );
2388  // Inject the stylesheet
2389  const QString html { mRasterLayer->htmlMetadata().replace( QLatin1String( "<head>" ), QStringLiteral( R"raw(<head><style type="text/css">%1</style>)raw" ) ).arg( myStyle ) };
2390  mMetadataViewer->setHtml( html );
2391  mMetadataFilled = true;
2392 }
2393 
2394 void QgsRasterLayerProperties::onCancel()
2395 {
2396  if ( mOldStyle.xmlData() != mRasterLayer->styleManager()->style( mRasterLayer->styleManager()->currentStyle() ).xmlData() )
2397  {
2398  // need to reset style to previous - style applied directly to the layer (not in apply())
2399  QString myMessage;
2400  QDomDocument doc( QStringLiteral( "qgis" ) );
2401  int errorLine, errorColumn;
2402  doc.setContent( mOldStyle.xmlData(), false, &myMessage, &errorLine, &errorColumn );
2403  mRasterLayer->importNamedStyle( doc, myMessage );
2404  syncToLayer();
2405  }
2406 }
2407 
2408 void QgsRasterLayerProperties::showHelp()
2409 {
2410  const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
2411 
2412  if ( helpPage.isValid() )
2413  {
2414  QgsHelp::openHelp( helpPage.toString() );
2415  }
2416  else
2417  {
2418  QgsHelp::openHelp( QStringLiteral( "working_with_raster/raster_properties.html" ) );
2419  }
2420 }
2421 
2422 void QgsRasterLayerProperties::updateGammaSpinBox( int value )
2423 {
2424  whileBlocking( mGammaSpinBox )->setValue( value / 100.0 );
2425 }
2426 
2427 void QgsRasterLayerProperties::updateGammaSlider( double value )
2428 {
2429  whileBlocking( mSliderGamma )->setValue( value * 100 );
2430 }
@ Float32
Thirty two bit floating point (float)
Definition: qgis.h:109
@ Float64
Sixty four bit floating point (double)
Definition: qgis.h:110
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:116
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition: qgis.h:115
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
static QgsRasterRendererRegistry * rasterRendererRegistry()
Returns the application's raster renderer registry, used for managing raster layer renderers.
static QRegExp shortNameRegExp()
Returns the short name regular expression for line edit validator.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Brightness/contrast and gamma correction filter pipe for rasters.
int contrast() const
Returns current contrast level.
int brightness() const
Returns current brightness level.
double gamma() const
Returns current gamma value.
void setGamma(double gamma)
Set gamma value.
void setContrast(int contrast)
Set contrast level.
void setBrightness(int brightness)
Set brightness level.
This class represents a coordinate reference system (CRS).
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
bool hasTemporalCapabilities() const
Returns true if the provider has temporal capabilities available.
virtual QString name() const =0
Returns a provider name.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
QgsDataSourceUri uri() const
Gets the data source specification.
Class for storing the component parts of a RDBMS data source URI (e.g.
bool hasParam(const QString &key) const
Returns true if a parameter with the specified key exists.
QString uri(bool expandAuthConfig=true) const
Returns the complete URI as a string.
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
static bool run(const QgsCoordinateReferenceSystem &sourceCrs=QgsCoordinateReferenceSystem(), const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem(), QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr, const QString &windowTitle=QString())
Runs the dialog (if required) prompting for the desired transform to use from sourceCrs to destinatio...
QgsDoubleValidator is a QLineEdit Validator that combines QDoubleValidator and QRegularExpressionVali...
static double toDouble(const QString &input, bool *ok)
Converts input string to double value.
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
static QgsProviderSourceWidgetProviderRegistry * sourceWidgetProviderRegistry()
Returns the registry of provider source widget providers.
Definition: qgsgui.cpp:96
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:65
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:71
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Factory method to create the renderer for this type.
Color and saturation filter pipe for rasters.
void setColorizeOn(bool colorizeOn)
void setSaturation(int saturation)
void setGrayscaleMode(QgsHueSaturationFilter::GrayscaleMode grayscaleMode)
QgsHueSaturationFilter::GrayscaleMode grayscaleMode() const
void setColorizeColor(const QColor &colorizeColor)
void setColorizeStrength(int colorizeStrength)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:86
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
Factory class for creating custom map layer property pages.
virtual bool supportsLayer(QgsMapLayer *layer) const
Check if the layer is supported for this widget.
virtual QIcon icon() const
The icon that will be shown in the UI for the panel.
virtual QgsMapLayerConfigWidget * createWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, bool dockWidget=true, QWidget *parent=nullptr) const =0
Factory function to create the widget on demand as needed by the dock.
virtual QString title() const
The title of the panel.
virtual bool supportLayerPropertiesDialog() const
Flag if widget is supported for use in layer properties dialog.
virtual QString layerPropertiesPagePositionHint() const
Returns a tab name hinting at where this page should be inserted into the layer properties tab list.
A panel widget that can be shown in the map style dock.
static QgsMapLayerLegend * defaultRasterLegend(QgsRasterLayer *rl)
Create new legend implementation for raster layer.
void removesExtraMenuSeparators(QMenu *m)
removes extra separators from the menu
void addStyleManagerActions(QMenu *m, QgsMapLayer *layer)
adds actions to the menu in accordance to the layer
static QgsMapLayerStyleGuiUtils * instance()
returns a singleton instance of this class
QString currentStyle() const
Returns name of the current style.
bool isDefault(const QString &styleName) const
Returns true if this is the default style.
QgsMapLayerStyle style(const QString &name) const
Returns data of a stored style - accessed by its unique name.
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
QString xmlData() const
Returns XML content of the style.
Base class for all map layer types.
Definition: qgsmaplayer.h:85
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:279
QString name
Definition: qgsmaplayer.h:88
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:1026
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Import the properties of this layer from a QDomDocument.
void setAbstract(const QString &abstract)
Sets the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:309
virtual QString saveSldStyle(const QString &uri, bool &resultFlag) const
Saves the properties of this layer to an SLD format file.
QString source() const
Returns the source for the layer.
void setLegendUrl(const QString &legendUrl)
Sets the URL for the layer's legend.
Definition: qgsmaplayer.h:1011
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:91
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:391
virtual QString loadDefaultStyle(bool &resultFlag)
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
virtual QString loadNamedMetadata(const QString &uri, bool &resultFlag)
Retrieve a named metadata for this layer if one exists (either as a .qmd file on disk or as a record ...
bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
void setAttributionUrl(const QString &attribUrl)
Sets the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:400
void setAutoRefreshEnabled(bool enabled)
Sets whether auto refresh is enabled for the layer.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:90
static QString formatLayerName(const QString &name)
A convenience function to capitalize and format a layer name.
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:317
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:371
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:344
virtual QString saveDefaultStyle(bool &resultFlag)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
void setKeywordList(const QString &keywords)
Sets the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:325
void setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:382
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
virtual QString saveDefaultMetadata(bool &resultFlag)
Save the current metadata of this layer as the default metadata (either as a .qmd file on disk or as ...
void setDataUrlFormat(const QString &dataUrlFormat)
Sets the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:362
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:301
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:353
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
virtual QString loadNamedStyle(const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:465
void setMetadataUrlFormat(const QString &metaUrlFormat)
Sets the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:456
static QString extensionPropertyType(PropertyType type)
Returns the extension of a Property.
Definition: qgsmaplayer.cpp:62
void setName(const QString &name)
Set the display name of the layer.
void setAutoRefreshInterval(int interval)
Sets the auto refresh interval (in milliseconds) for the layer.
QString metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:429
QString saveNamedMetadata(const QString &uri, bool &resultFlag)
Save the current metadata of this layer as a named metadata (either as a .qmd file on disk or as a re...
bool isValid
Definition: qgsmaplayer.h:93
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:409
double minimumScale() const
Returns the minimum map scale (i.e.
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer's style manager.
QString legendUrl() const
Returns the URL for the layer's legend.
Definition: qgsmaplayer.h:1016
void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
Definition: qgsmaplayer.h:1021
virtual QString saveNamedStyle(const QString &uri, bool &resultFlag, StyleCategories categories=AllStyleCategories)
Save the properties of this layer as a named style (either as a .qml file on disk or as a record in t...
void setMetadataUrl(const QString &metaUrl)
Sets the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:420
void setMetadataUrlType(const QString &metaUrlType)
Set the metadata type of the layer used by QGIS Server in GetCapabilities request MetadataUrlType ind...
Definition: qgsmaplayer.h:438
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
virtual QString metadataUri() const
Retrieve the metadata URI for this layer (either as a .qmd file on disk or as a record in the users s...
int autoRefreshInterval
Definition: qgsmaplayer.h:89
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:447
double maximumScale() const
Returns the maximum map scale (i.e.
QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:333
void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:293
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
The QgsMapSettings class contains configuration for rendering of the map.
QgsRectangle outputExtentToLayerExtent(const QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from output CRS to layer's CRS
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
void canvasClicked(const QgsPointXY &point, Qt::MouseButton button)
signal emitted on canvas click
void deactivated()
signal emitted once the map tool is deactivated
A wizard to edit metadata on a map layer.
void acceptMetadata()
Saves the metadata to the layer.
void crsChanged()
If the CRS is updated.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas associated with the widget.
void setMetadata(const QgsAbstractMetadataBase *metadata)
Sets the metadata to display in the widget.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Renderer for multiband images with the color components.
A base dialog for options and properties dialogs that offers vertical tabs.
void insertPage(const QString &title, const QString &tooltip, const QIcon &icon, QWidget *widget, const QString &before)
Inserts a new page into the dialog pages.
virtual void optionsStackedWidget_CurrentChanged(int index)
Select relevant tab on current page change.
void addPage(const QString &title, const QString &tooltip, const QIcon &icon, QWidget *widget)
Adds a new page to the dialog pages.
void restoreOptionsBaseUi(const QString &title=QString())
Restore the base ui.
QStackedWidget * mOptStackedWidget
void initOptionsBase(bool restoreUi=true, const QString &title=QString())
Set up the base ui connections for vertical tabs.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsDateTimeRange temporalRange() const
Returns the project's temporal range, which indicates the earliest and latest datetime ranges associa...
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:501
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:552
const QgsProjectTimeSettings * timeSettings() const
Returns the project's time settings, which contains the project's temporal range and other time based...
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
Holds data provider key, description, and associated shared library file or function pointer informat...
virtual QString encodeUri(const QVariantMap &parts) const
Reassembles a provider data source URI from its component paths (e.g.
virtual QVariantMap decodeUri(const QString &uri) const
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
QgsProviderSourceWidget * createWidget(QgsMapLayer *layer, QWidget *parent=nullptr)
Creates a new widget to configure the source of the specified layer.
void validChanged(bool isValid)
Emitted whenever the validation status of the widget changes.
virtual QString sourceUri() const =0
Returns the source URI as currently defined by the widget.
virtual void setSourceUri(const QString &uri)=0
Sets the source uri to show in the widget.
Feedback object tailored for raster block reading.
static QString printValue(double value)
Print double value with all necessary significant digits.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Widget creation function (mainly for the use by the renderer registry)
IntervalHandlingMethod
Method to use when resolving a temporal range to a data provider layer or band.
@ MatchExactUsingStartOfRange
Match the start of the temporal range to a corresponding layer or band, and only use exact matching r...
@ MatchExactUsingEndOfRange
Match the end of the temporal range to a corresponding layer or band, and only use exact matching res...
@ MatchUsingWholeRange
Use an exact match to the whole temporal range.
@ FindClosestMatchToEndOfRange
Match the start of the temporal range to the least previous closest datetime.
const QgsDateTimeRange & availableReferenceTemporalRange() const
Returns the available reference datetime range, which indicates the maximum extent of datetime values...
const QgsDateTimeRange & availableTemporalRange() const
Returns the datetime range extent from which temporal data is available from the provider.
Base class for raster data providers.
virtual QgsFields fields() const
Returns the fields of the raster layer for data providers that expose them, the default implementatio...
virtual QString buildPyramids(const QList< QgsRasterPyramid > &pyramidList, const QString &resamplingMethod="NEAREST", QgsRaster::RasterPyramidsFormat format=QgsRaster::PyramidsGTiff, const QStringList &configOptions=QStringList(), QgsRasterBlockFeedback *feedback=nullptr)
Create pyramid overviews.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
virtual QList< QgsRasterPyramid > buildPyramidList(QList< int > overviewList=QList< int >())
Returns the raster layers pyramid list.
virtual bool useSourceNoDataValue(int bandNo) const
Returns the source nodata value usage.
Qgis::DataType sourceDataType(int bandNo) const override=0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
virtual void setUseSourceNoDataValue(int bandNo, bool use)
Sets the source nodata value usage.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
virtual QgsRasterIdentifyResult identify(const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Identify raster value(s) found on the point position.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Returns a list of user no data value ranges.
static QList< QPair< QString, QString > > pyramidResamplingMethods(const QString &providerKey)
Returns a list of pyramid resampling method name and label pairs for given provider.
QgsRasterDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
virtual void setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)
void setRendererWidget(const QString &name, QgsRasterRendererWidget *rendererWidget=nullptr)
Sets the renderer widget (or just its name if there is no widget)
void setActive(bool activeFlag)
Activate the histogram widget.
QMap< int, QVariant > results() const
Returns the identify results.
@ BuildPyramids
Supports building of pyramids (overviews)
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
StyleType
enumeration for the different types of style
void addPropertiesPageFactory(QgsMapLayerConfigWidgetFactory *factory)
Adds a properties page factory to the raster layer properties dialog.
QgsRasterLayerProperties(QgsMapLayer *lyr, QgsMapCanvas *canvas, QWidget *parent=nullptr, Qt::WindowFlags=QgsGuiUtils::ModalDialogFlags)
Constructor.
void optionsStackedWidget_CurrentChanged(int index) override
auto slot executed when the active page in the main widget stack is changed
A widget for configuring the temporal properties for a raster layer.
void syncToLayer()
Updates the widget state to match the current layer state.
void saveTemporalProperties()
Save widget temporal properties inputs.
Represents a raster layer.
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
QgsHueSaturationFilter * hueSaturationFilter() const
Returns the raster's hue/saturation filter.
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag=false) override
Updates the data source of the layer.
LayerType rasterType()
Returns the raster layer type (which is a read only property).
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
QgsBrightnessContrastFilter * brightnessFilter() const
Returns the raster's brightness/contrast filter.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
void setRenderer(QgsRasterRenderer *renderer)
Sets the raster's renderer.
Raster values range container.
void insertWidgetFunction(const QString &rendererName, QgsRasterRendererWidgetCreateFunc func)
virtual void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
virtual QgsRasterRenderer * renderer()=0
virtual void doComputations()
Load programmatically with current values.
Raster renderer pipe that applies colors to a raster.
QColor nodataColor() const
Returns the color to use for shading nodata pixels.
const QgsRasterTransparency * rasterTransparency() const
virtual QString type() const
double opacity() const
Returns the opacity for the renderer, where opacity is a value between 0 (totally transparent) and 1....
void setAlphaBand(int band)
void setOpacity(double opacity)
Sets the opacity for the renderer, where opacity is a value between 0 (totally transparent) and 1....
void setRasterTransparency(QgsRasterTransparency *t)
virtual QList< int > usesBands() const
Returns a list of band numbers used by the renderer.
void setNodataColor(const QColor &color)
Sets the color to use for shading nodata pixels.
Defines the list of pixel values to be considered as transparent or semi transparent when rendering r...
void setTransparentSingleValuePixelList(const QList< QgsRasterTransparency::TransparentSingleValuePixel > &newList)
Sets the transparent single value pixel list, replacing the whole existing list.
QList< QgsRasterTransparency::TransparentThreeValuePixel > transparentThreeValuePixelList() const
Returns the transparent three value pixel list.
void setTransparentThreeValuePixelList(const QList< QgsRasterTransparency::TransparentThreeValuePixel > &newList)
Sets the transparent three value pixel list, replacing the whole existing list.
QList< QgsRasterTransparency::TransparentSingleValuePixel > transparentSingleValuePixelList() const
Returns the transparent single value pixel list.
@ IdentifyFormatValue
Definition: qgsraster.h:60
RasterPyramidsFormat
Definition: qgsraster.h:82
@ MultiBandColor
Definition: qgsraster.h:100
@ SingleBandGray
Definition: qgsraster.h:92
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Creates new raster renderer widget.
void changed()
Emitted when the temporal properties have changed.
bool isActive() const
Returns true if the temporal property is active.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:263
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.
Registry for raster renderer entries.
QgsRasterRendererWidgetCreateFunc widgetCreateFunction