QGIS API Documentation  3.20.0-Odense (decaadbb31)
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  mSourceGroupBox->hide();
126 
127  mBtnStyle = new QPushButton( tr( "Style" ) );
128  QMenu *menuStyle = new QMenu( this );
129  menuStyle->addAction( tr( "Load Style…" ), this, &QgsRasterLayerProperties::loadStyle_clicked );
130  menuStyle->addAction( tr( "Save Style…" ), this, &QgsRasterLayerProperties::saveStyleAs_clicked );
131  menuStyle->addSeparator();
132  menuStyle->addAction( tr( "Save as Default" ), this, &QgsRasterLayerProperties::saveDefaultStyle_clicked );
133  menuStyle->addAction( tr( "Restore Default" ), this, &QgsRasterLayerProperties::loadDefaultStyle_clicked );
134  mBtnStyle->setMenu( menuStyle );
135  connect( menuStyle, &QMenu::aboutToShow, this, &QgsRasterLayerProperties::aboutToShowStyleMenu );
136  buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
137 
138  mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
139  QMenu *menuMetadata = new QMenu( this );
140  mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata…" ), this, &QgsRasterLayerProperties::loadMetadata );
141  mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata…" ), this, &QgsRasterLayerProperties::saveMetadataAs );
142  menuMetadata->addSeparator();
143  menuMetadata->addAction( tr( "Save as Default" ), this, &QgsRasterLayerProperties::saveDefaultMetadata );
144  menuMetadata->addAction( tr( "Restore Default" ), this, &QgsRasterLayerProperties::loadDefaultMetadata );
145  mBtnMetadata->setMenu( menuMetadata );
146  buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
147 
148  connect( lyr->styleManager(), &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsRasterLayerProperties::syncToLayer );
149 
150  connect( this, &QDialog::accepted, this, &QgsRasterLayerProperties::apply );
151  connect( this, &QDialog::rejected, this, &QgsRasterLayerProperties::onCancel );
152 
153  connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsRasterLayerProperties::apply );
154 
155  // brightness/contrast controls
156  connect( mSliderBrightness, &QAbstractSlider::valueChanged, mBrightnessSpinBox, &QSpinBox::setValue );
157  connect( mBrightnessSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), mSliderBrightness, &QAbstractSlider::setValue );
158  mBrightnessSpinBox->setClearValue( 0 );
159 
160  connect( mSliderContrast, &QAbstractSlider::valueChanged, mContrastSpinBox, &QSpinBox::setValue );
161  connect( mContrastSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), mSliderContrast, &QAbstractSlider::setValue );
162  mContrastSpinBox->setClearValue( 0 );
163 
164  // gamma correction controls
165  connect( mSliderGamma, &QAbstractSlider::valueChanged, this, &QgsRasterLayerProperties::updateGammaSpinBox );
166  connect( mGammaSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsRasterLayerProperties::updateGammaSlider );
167  mGammaSpinBox->setClearValue( 1.0 );
168 
169  // Connect saturation slider and spin box
170  connect( sliderSaturation, &QAbstractSlider::valueChanged, spinBoxSaturation, &QSpinBox::setValue );
171  connect( spinBoxSaturation, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), sliderSaturation, &QAbstractSlider::setValue );
172  spinBoxSaturation->setClearValue( 0 );
173 
174  // Connect colorize strength slider and spin box
175  connect( sliderColorizeStrength, &QAbstractSlider::valueChanged, spinColorizeStrength, &QSpinBox::setValue );
176  connect( spinColorizeStrength, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), sliderColorizeStrength, &QAbstractSlider::setValue );
177  spinColorizeStrength->setClearValue( 100 );
178 
179  // enable or disable saturation slider and spin box depending on grayscale combo choice
180  connect( comboGrayscale, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRasterLayerProperties::toggleSaturationControls );
181 
182  // enable or disable colorize colorbutton with colorize checkbox
183  connect( mColorizeCheck, &QAbstractButton::toggled, this, &QgsRasterLayerProperties::toggleColorizeControls );
184 
185  // enable or disable Build Pyramids button depending on selection in pyramid list
186  connect( lbxPyramidResolutions, &QListWidget::itemSelectionChanged, this, &QgsRasterLayerProperties::toggleBuildPyramidsButton );
187 
188  connect( mRefreshLayerCheckBox, &QCheckBox::toggled, mRefreshLayerIntervalSpinBox, &QDoubleSpinBox::setEnabled );
189 
190  // set up the scale based layer visibility stuff....
191  mScaleRangeWidget->setMapCanvas( mMapCanvas );
192  chkUseScaleDependentRendering->setChecked( lyr->hasScaleBasedVisibility() );
193  mScaleRangeWidget->setScaleRange( lyr->minimumScale(), lyr->maximumScale() );
194 
195  leNoDataValue->setValidator( new QgsDoubleValidator( -std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), 1000, this ) );
196 
197  // build GUI components
198  QIcon myPyramidPixmap( QgsApplication::getThemeIcon( "/mIconPyramid.svg" ) );
199  QIcon myNoPyramidPixmap( QgsApplication::getThemeIcon( "/mIconNoPyramid.svg" ) );
200 
201  pbnAddValuesManually->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
202  pbnAddValuesFromDisplay->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionContextHelp.png" ) ) );
203  pbnRemoveSelectedRow->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyRemove.svg" ) ) );
204  pbnDefaultValues->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOpenTable.svg" ) ) );
205  pbnImportTransparentPixelValues->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileOpen.svg" ) ) );
206  pbnExportTransparentPixelValues->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileSave.svg" ) ) );
207 
208  if ( mMapCanvas )
209  {
210  mPixelSelectorTool = std::make_unique<QgsMapToolEmitPoint>( canvas );
211  connect( mPixelSelectorTool.get(), &QgsMapToolEmitPoint::canvasClicked, this, &QgsRasterLayerProperties::pixelSelected );
212  connect( mPixelSelectorTool.get(), &QgsMapToolEmitPoint::deactivated, this, &QgsRasterLayerProperties::restoreWindowModality );
213  }
214  else
215  {
216  pbnAddValuesFromDisplay->setEnabled( false );
217  }
218 
219  if ( !mRasterLayer )
220  {
221  return;
222  }
223 
224  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
225 
226  // Only do pyramids if dealing directly with GDAL.
227  if ( provider && provider->capabilities() & QgsRasterDataProvider::BuildPyramids )
228  {
229  // initialize resampling methods
230  cboResamplingMethod->clear();
231 
232  const auto constProviderType = QgsRasterDataProvider::pyramidResamplingMethods( mRasterLayer->providerType() );
233  for ( QPair<QString, QString> method : constProviderType )
234  {
235  cboResamplingMethod->addItem( method.second, method.first );
236  }
237 
238  // keep it in sync with qgsrasterpyramidsoptionwidget.cpp
239  QString prefix = provider->name() + "/driverOptions/_pyramids/";
240  QgsSettings mySettings;
241  QString defaultMethod = mySettings.value( prefix + "resampling", "AVERAGE" ).toString();
242  int idx = cboResamplingMethod->findData( defaultMethod );
243  if ( idx >= 0 )
244  cboResamplingMethod->setCurrentIndex( idx );
245 
246 
247  // build pyramid list
248  const QList< QgsRasterPyramid > myPyramidList = provider->buildPyramidList();
249 
250  for ( const QgsRasterPyramid &pyramid : myPyramidList )
251  {
252  if ( pyramid.getExists() )
253  {
254  lbxPyramidResolutions->addItem( new QListWidgetItem( myPyramidPixmap,
255  QString::number( pyramid.getXDim() ) + QStringLiteral( " x " ) +
256  QString::number( pyramid.getYDim() ) ) );
257  }
258  else
259  {
260  lbxPyramidResolutions->addItem( new QListWidgetItem( myNoPyramidPixmap,
261  QString::number( pyramid.getXDim() ) + QStringLiteral( " x " ) +
262  QString::number( pyramid.getYDim() ) ) );
263  }
264  }
265  }
266  else
267  {
268  // disable Pyramids tab completely
269  mOptsPage_Pyramids->setEnabled( false );
270  }
271 
272  // We can calculate histogram for all data sources but estimated only if
273  // size is unknown - could also be enabled if well supported (estimated histogram
274  // and let user know that it is estimated)
275  if ( !provider || !( provider->capabilities() & QgsRasterDataProvider::Size ) )
276  {
277  // disable Histogram tab completely
278  mOptsPage_Histogram->setEnabled( false );
279  }
280 
281  QVBoxLayout *layout = new QVBoxLayout( metadataFrame );
282  layout->setContentsMargins( 0, 0, 0, 0 );
283  mMetadataWidget = new QgsMetadataWidget( this, mRasterLayer );
284  mMetadataWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
285  mMetadataWidget->setMapCanvas( mMapCanvas );
286  layout->addWidget( mMetadataWidget );
287  metadataFrame->setLayout( layout );
288 
289  QVBoxLayout *temporalLayout = new QVBoxLayout( temporalFrame );
290  temporalLayout->setContentsMargins( 0, 0, 0, 0 );
291  mTemporalWidget = new QgsRasterLayerTemporalPropertiesWidget( this, mRasterLayer );
292  temporalLayout->addWidget( mTemporalWidget );
293 
294  QgsDebugMsgLevel( "Setting crs to " + mRasterLayer->crs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ), 2 );
295  QgsDebugMsgLevel( "Setting crs to " + mRasterLayer->crs().userFriendlyIdentifier(), 2 );
296  mCrsSelector->setCrs( mRasterLayer->crs() );
297 
298  // Set text for pyramid info box
299  QString pyramidFormat( QStringLiteral( "<h2>%1</h2><p>%2 %3 %4</p><b><font color='red'><p>%5</p><p>%6</p>" ) );
300  QString pyramidHeader = tr( "Description" );
301  QString pyramidSentence1 = tr( "Large resolution raster layers can slow navigation in QGIS." );
302  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." );
303  QString pyramidSentence3 = tr( "You must have write access in the directory where the original data is stored to build pyramids." );
304  QString pyramidSentence4 = tr( "Please note that building internal pyramids may alter the original data file and once created they cannot be removed!" );
305  QString pyramidSentence5 = tr( "Please note that building internal pyramids could corrupt your image - always make a backup of your data first!" );
306 
307  tePyramidDescription->setHtml( pyramidFormat.arg( pyramidHeader,
308  pyramidSentence1,
309  pyramidSentence2,
310  pyramidSentence3,
311  pyramidSentence4,
312  pyramidSentence5 ) );
313 
314  //resampling
315  mResamplingGroupBox->setSaveCheckedState( true );
316  mResamplingUtils.initWidgets( mRasterLayer, mZoomedInResamplingComboBox, mZoomedOutResamplingComboBox, mMaximumOversamplingSpinBox, mCbEarlyResampling );
317  mResamplingUtils.refreshWidgetsFromLayer();
318 
319  const QgsRasterRenderer *renderer = mRasterLayer->renderer();
320 
321  btnColorizeColor->setColorDialogTitle( tr( "Select Color" ) );
322  btnColorizeColor->setContext( QStringLiteral( "symbology" ) );
323 
324  // Hue and saturation color control
325  const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter();
326  //set hue and saturation controls to current values
327  if ( hueSaturationFilter )
328  {
329  sliderSaturation->setValue( hueSaturationFilter->saturation() );
330  comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
331 
332  // Set initial state of saturation controls based on grayscale mode choice
333  toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
334 
335  // Set initial state of colorize controls
336  mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
337  btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
338  toggleColorizeControls( hueSaturationFilter->colorizeOn() );
339  sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
340  }
341 
342  //blend mode
343  mBlendModeComboBox->setBlendMode( mRasterLayer->blendMode() );
344 
345  //transparency band
346  if ( provider )
347  {
348  cboxTransparencyBand->setShowNotSetOption( true, tr( "None" ) );
349  cboxTransparencyBand->setLayer( mRasterLayer );
350 
351 // Alpha band is set in sync()
352 #if 0
353  if ( renderer )
354  {
355  QgsDebugMsg( QStringLiteral( "alphaBand = %1" ).arg( renderer->alphaBand() ) );
356  if ( renderer->alphaBand() > 0 )
357  {
358  cboxTransparencyBand->setCurrentIndex( cboxTransparencyBand->findData( renderer->alphaBand() ) );
359  }
360  }
361 #endif
362  }
363 
364  // create histogram widget
365  mHistogramWidget = nullptr;
366  if ( mOptsPage_Histogram->isEnabled() )
367  {
368  mHistogramWidget = new QgsRasterHistogramWidget( mRasterLayer, mOptsPage_Histogram );
369  mHistogramStackedWidget->addWidget( mHistogramWidget );
370  }
371 
372  //insert renderer widgets into registry
379 
380  //fill available renderers into combo box
382  mDisableRenderTypeComboBoxCurrentIndexChanged = true;
383  const auto constRenderersList = QgsApplication::rasterRendererRegistry()->renderersList();
384  for ( const QString &name : constRenderersList )
385  {
386  if ( QgsApplication::rasterRendererRegistry()->rendererData( name, entry ) )
387  {
388  if ( ( mRasterLayer->rasterType() != QgsRasterLayer::ColorLayer && entry.name != QLatin1String( "singlebandcolordata" ) ) ||
389  ( mRasterLayer->rasterType() == QgsRasterLayer::ColorLayer && entry.name == QLatin1String( "singlebandcolordata" ) ) )
390  {
391  mRenderTypeComboBox->addItem( entry.visibleName, entry.name );
392  }
393  }
394  }
395  mDisableRenderTypeComboBoxCurrentIndexChanged = false;
396 
397  int widgetIndex = 0;
398  if ( renderer )
399  {
400  QString rendererType = renderer->type();
401  widgetIndex = mRenderTypeComboBox->findData( rendererType );
402  if ( widgetIndex != -1 )
403  {
404  mDisableRenderTypeComboBoxCurrentIndexChanged = true;
405  mRenderTypeComboBox->setCurrentIndex( widgetIndex );
406  mDisableRenderTypeComboBoxCurrentIndexChanged = false;
407  }
408 
409  if ( rendererType == QLatin1String( "singlebandcolordata" ) && mRenderTypeComboBox->count() == 1 )
410  {
411  // no band rendering options for singlebandcolordata, so minimize group box
412  QSizePolicy sizep = mBandRenderingGrpBx->sizePolicy();
413  sizep.setVerticalStretch( 0 );
414  sizep.setVerticalPolicy( QSizePolicy::Maximum );
415  mBandRenderingGrpBx->setSizePolicy( sizep );
416  mBandRenderingGrpBx->updateGeometry();
417  }
418 
419  if ( mRasterLayer->providerType() != QLatin1String( "wms" ) )
420  {
421  mWMSPrintGroupBox->hide();
422  mPublishDataSourceUrlCheckBox->hide();
423  mBackgroundLayerCheckBox->hide();
424  }
425  }
426 
427 #ifdef WITH_QTWEBKIT
428  // Setup information tab
429 
430  const int horizontalDpi = logicalDpiX();
431 
432  // Adjust zoom: text is ok, but HTML seems rather big at least on Linux/KDE
433  if ( horizontalDpi > 96 )
434  {
435  mMetadataViewer->setZoomFactor( mMetadataViewer->zoomFactor() * 0.9 );
436  }
437  mMetadataViewer->page()->setLinkDelegationPolicy( QWebPage::LinkDelegationPolicy::DelegateAllLinks );
438  connect( mMetadataViewer->page(), &QWebPage::linkClicked, this, &QgsRasterLayerProperties::urlClicked );
439  mMetadataViewer->page()->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
440  mMetadataViewer->page()->settings()->setAttribute( QWebSettings::JavascriptEnabled, true );
441 
442 #endif
443 
444  mRenderTypeComboBox_currentIndexChanged( widgetIndex );
445 
446  // update based on lyr's current state
447  sync();
448 
449  QgsSettings settings;
450  // if dialog hasn't been opened/closed yet, default to Styles tab, which is used most often
451  // this will be read by restoreOptionsBaseUi()
452  if ( !settings.contains( QStringLiteral( "/Windows/RasterLayerProperties/tab" ) ) )
453  {
454  settings.setValue( QStringLiteral( "Windows/RasterLayerProperties/tab" ),
455  mOptStackedWidget->indexOf( mOptsPage_Style ) );
456  }
457 
458  mResetColorRenderingBtn->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUndo.svg" ) ) );
459 
460  QString title = tr( "Layer Properties — %1" ).arg( lyr->name() );
461 
462  if ( !mRasterLayer->styleManager()->isDefault( mRasterLayer->styleManager()->currentStyle() ) )
463  title += QStringLiteral( " (%1)" ).arg( mRasterLayer->styleManager()->currentStyle() );
464  restoreOptionsBaseUi( title );
465  optionsStackedWidget_CurrentChanged( mOptionsStackedWidget->currentIndex() );
466 
467  //Add help page references
468  mOptsPage_Information->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#information-properties" ) );
469  mOptsPage_Source->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#source-properties" ) );
470  mOptsPage_Style->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#symbology-properties" ) );
471  mOptsPage_Transparency->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#transparency-properties" ) );
472 
473  if ( mOptsPage_Histogram )
474  mOptsPage_Histogram->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#histogram-properties" ) );
475 
476  mOptsPage_Rendering->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#rendering-properties" ) );
477 
478  if ( mOptsPage_Pyramids )
479  mOptsPage_Pyramids->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#pyramids-properties" ) );
480 
481  mOptsPage_Metadata->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#metadata-properties" ) );
482  mOptsPage_Legend->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#legend-properties" ) );
483  mOptsPage_Server->setProperty( "helpPage", QStringLiteral( "working_with_raster/raster_properties.html#server-properties" ) );
484 }
485 
487 {
488  if ( !factory->supportsLayer( mRasterLayer ) || !factory->supportLayerPropertiesDialog() )
489  {
490  return;
491  }
492 
493  QgsMapLayerConfigWidget *page = factory->createWidget( mRasterLayer, nullptr, false, this );
494  switch ( factory->parentPage() )
495  {
497  {
498  mLayerPropertiesPages << page;
499 
500  const QString beforePage = factory->layerPropertiesPagePositionHint();
501  if ( beforePage.isEmpty() )
502  addPage( factory->title(), factory->title(), factory->icon(), page );
503  else
504  insertPage( factory->title(), factory->title(), factory->icon(), page, beforePage );
505  break;
506  }
507 
509  mTemporalWidget->addWidget( page );
510  break;
511  }
512 }
513 
514 void QgsRasterLayerProperties::setupTransparencyTable( int nBands )
515 {
516  tableTransparency->clear();
517  tableTransparency->setColumnCount( 0 );
518  tableTransparency->setRowCount( 0 );
519  mTransparencyToEdited.clear();
520 
521  if ( nBands == 3 )
522  {
523  tableTransparency->setColumnCount( 4 );
524  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Red" ) ) );
525  tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Green" ) ) );
526  tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Blue" ) ) );
527  tableTransparency->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
528  }
529  else //1 band
530  {
531  tableTransparency->setColumnCount( 3 );
532 // Is it important to distinguish the header? It becomes difficult with range.
533 #if 0
534  if ( QgsRasterLayer::PalettedColor != mRasterLayer->drawingStyle() &&
535  QgsRasterLayer::PalettedSingleBandGray != mRasterLayer->drawingStyle() &&
536  QgsRasterLayer::PalettedSingleBandPseudoColor != mRasterLayer->drawingStyle() &&
537  QgsRasterLayer::PalettedMultiBandColor != mRasterLayer->drawingStyle() )
538  {
539  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Gray" ) ) );
540  }
541  else
542  {
543  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Indexed Value" ) ) );
544  }
545 #endif
546  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "From" ) ) );
547  tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "To" ) ) );
548  tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
549  }
550 
551  tableTransparency->horizontalHeader()->setSectionResizeMode( 0, QHeaderView::Stretch );
552  tableTransparency->horizontalHeader()->setSectionResizeMode( 1, QHeaderView::Stretch );
553 }
554 
555 void QgsRasterLayerProperties::populateTransparencyTable( QgsRasterRenderer *renderer )
556 {
557  if ( !mRasterLayer )
558  {
559  return;
560  }
561 
562  if ( !renderer )
563  {
564  return;
565  }
566 
567  int nBands = renderer->usesBands().size();
568  setupTransparencyTable( nBands );
569 
570  const QgsRasterTransparency *rasterTransparency = renderer->rasterTransparency();
571  if ( !rasterTransparency )
572  {
573  return;
574  }
575 
576  if ( nBands == 1 )
577  {
578  QList<QgsRasterTransparency::TransparentSingleValuePixel> pixelList = rasterTransparency->transparentSingleValuePixelList();
579  for ( int i = 0; i < pixelList.size(); ++i )
580  {
581  tableTransparency->insertRow( i );
582  setTransparencyCell( i, 0, pixelList[i].min );
583  setTransparencyCell( i, 1, pixelList[i].max );
584  setTransparencyCell( i, 2, pixelList[i].percentTransparent );
585  // break synchronization only if values differ
586  if ( pixelList[i].min != pixelList[i].max )
587  {
588  setTransparencyToEdited( i );
589  }
590  }
591  }
592  else if ( nBands == 3 )
593  {
594  QList<QgsRasterTransparency::TransparentThreeValuePixel> pixelList = rasterTransparency->transparentThreeValuePixelList();
595  for ( int i = 0; i < pixelList.size(); ++i )
596  {
597  tableTransparency->insertRow( i );
598  setTransparencyCell( i, 0, pixelList[i].red );
599  setTransparencyCell( i, 1, pixelList[i].green );
600  setTransparencyCell( i, 2, pixelList[i].blue );
601  setTransparencyCell( i, 3, pixelList[i].percentTransparent );
602  }
603  }
604 
605  tableTransparency->resizeColumnsToContents();
606  tableTransparency->resizeRowsToContents();
607 }
608 
609 void QgsRasterLayerProperties::setRendererWidget( const QString &rendererName )
610 {
611  QgsDebugMsgLevel( "rendererName = " + rendererName, 3 );
612  QgsRasterRendererWidget *oldWidget = mRendererWidget;
613  QgsRasterRenderer *oldRenderer = mRasterLayer->renderer();
614 
615  int alphaBand = -1;
616  double opacity = 1;
617  QColor nodataColor;
618  if ( oldRenderer )
619  {
620  // Retain alpha band and opacity when switching renderer
621  alphaBand = oldRenderer->alphaBand();
622  opacity = oldRenderer->opacity();
623  nodataColor = oldRenderer->nodataColor();
624  }
625 
626  QgsRasterRendererRegistryEntry rendererEntry;
627  if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
628  {
629  if ( rendererEntry.widgetCreateFunction ) //single band color data renderer e.g. has no widget
630  {
631  QgsDebugMsgLevel( QStringLiteral( "renderer has widgetCreateFunction" ), 3 );
632  // Current canvas extent (used to calc min/max) in layer CRS
633  QgsRectangle myExtent = mMapCanvas->mapSettings().outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() );
634  if ( oldWidget && ( !oldRenderer || rendererName != oldRenderer->type() ) )
635  {
636  if ( rendererName == QLatin1String( "singlebandgray" ) )
637  {
638  whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::SingleBandGray, mRasterLayer->dataProvider() ) );
639  whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
640  }
641  else if ( rendererName == QLatin1String( "multibandcolor" ) )
642  {
643  whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::MultiBandColor, mRasterLayer->dataProvider() ) );
644  whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
645  }
646  }
647  mRasterLayer->renderer()->setAlphaBand( alphaBand );
648  mRasterLayer->renderer()->setOpacity( opacity );
649  mRasterLayer->renderer()->setNodataColor( nodataColor );
650  mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
651  mRendererWidget->setMapCanvas( mMapCanvas );
652  mRendererStackedWidget->addWidget( mRendererWidget );
653  if ( oldWidget )
654  {
655  //compare used bands in new and old renderer and reset transparency dialog if different
656  QgsRasterRenderer *oldRenderer = oldWidget->renderer();
657  QgsRasterRenderer *newRenderer = mRendererWidget->renderer();
658  QList<int> oldBands = oldRenderer->usesBands();
659  QList<int> newBands = newRenderer->usesBands();
660  if ( oldBands != newBands )
661  {
662  populateTransparencyTable( newRenderer );
663  }
664  delete oldRenderer;
665  delete newRenderer;
666  }
667  }
668  }
669 
670  const int widgetIndex = mRenderTypeComboBox->findData( rendererName );
671  if ( widgetIndex != -1 )
672  {
673  mDisableRenderTypeComboBoxCurrentIndexChanged = true;
674  mRenderTypeComboBox->setCurrentIndex( widgetIndex );
675  mDisableRenderTypeComboBoxCurrentIndexChanged = false;
676  }
677 
678  if ( mRendererWidget != oldWidget )
679  delete oldWidget;
680 
681  if ( mHistogramWidget )
682  {
683  mHistogramWidget->setRendererWidget( rendererName, mRendererWidget );
684  }
685 }
686 
687 void QgsRasterLayerProperties::sync()
688 {
689  QgsSettings myQSettings;
690 
691  if ( !mSourceWidget )
692  {
693  mSourceWidget = QgsGui::sourceWidgetProviderRegistry()->createWidget( mRasterLayer );
694  if ( mSourceWidget )
695  {
696  QHBoxLayout *layout = new QHBoxLayout();
697  layout->addWidget( mSourceWidget );
698  mSourceGroupBox->setLayout( layout );
699  mSourceGroupBox->show();
700 
701  connect( mSourceWidget, &QgsProviderSourceWidget::validChanged, this, [ = ]( bool isValid )
702  {
703  buttonBox->button( QDialogButtonBox::Apply )->setEnabled( isValid );
704  buttonBox->button( QDialogButtonBox::Ok )->setEnabled( isValid );
705  } );
706  }
707  }
708 
709  if ( mSourceWidget )
710  mSourceWidget->setSourceUri( mRasterLayer->source() );
711 
712  const QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
713  if ( !provider )
714  return;
715 
716  if ( provider->dataType( 1 ) == Qgis::DataType::ARGB32
717  || provider->dataType( 1 ) == Qgis::DataType::ARGB32_Premultiplied )
718  {
719  gboxNoDataValue->setEnabled( false );
720  gboxCustomTransparency->setEnabled( false );
721  mOptionsStackedWidget->setCurrentWidget( mOptsPage_Server );
722  }
723 
724  // TODO: Wouldn't it be better to just removeWidget() the tabs than delete them? [LS]
725  if ( !( provider->capabilities() & QgsRasterDataProvider::BuildPyramids ) )
726  {
727  if ( mOptsPage_Pyramids )
728  {
729  delete mOptsPage_Pyramids;
730  mOptsPage_Pyramids = nullptr;
731  }
732  }
733 
734  if ( !( provider->capabilities() & QgsRasterDataProvider::Size ) )
735  {
736  if ( mOptsPage_Histogram )
737  {
738  delete mOptsPage_Histogram;
739  mOptsPage_Histogram = nullptr;
740  delete mHistogramWidget;
741  mHistogramWidget = nullptr;
742  }
743  }
744 
745  QgsDebugMsgLevel( QStringLiteral( "populate transparency tab" ), 3 );
746 
747  /*
748  * Style tab
749  */
750 
751  //set brightness, contrast and gamma
752  QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter();
753  if ( brightnessFilter )
754  {
755  mSliderBrightness->setValue( brightnessFilter->brightness() );
756  mSliderContrast->setValue( brightnessFilter->contrast() );
757  mGammaSpinBox->setValue( brightnessFilter->gamma() );
758  }
759 
760  // Hue and saturation color control
761  const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter();
762  //set hue and saturation controls to current values
763  if ( hueSaturationFilter )
764  {
765  sliderSaturation->setValue( hueSaturationFilter->saturation() );
766  comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
767 
768  // Set state of saturation controls based on grayscale mode choice
769  toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
770 
771  // Set state of colorize controls
772  mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
773  btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
774  toggleColorizeControls( hueSaturationFilter->colorizeOn() );
775  sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
776  }
777 
778  /*
779  * Transparent Pixel Tab
780  */
781 
782  //set the transparency slider
783  QgsRasterRenderer *renderer = mRasterLayer->renderer();
784  if ( renderer )
785  {
786  mOpacityWidget->setOpacity( renderer->opacity() );
787  cboxTransparencyBand->setBand( renderer->alphaBand() );
788  }
789 
790  //add current NoDataValue to NoDataValue line edit
791  // TODO: should be per band
792  // TODO: no data ranges
793  if ( provider->sourceHasNoDataValue( 1 ) )
794  {
795  double v = QgsRasterBlock::printValue( provider->sourceNoDataValue( 1 ) ).toDouble();
796  lblSrcNoDataValue->setText( QLocale().toString( v, 'g' ) );
797  }
798  else
799  {
800  lblSrcNoDataValue->setText( tr( "not defined" ) );
801  }
802 
803  mSrcNoDataValueCheckBox->setChecked( provider->useSourceNoDataValue( 1 ) );
804 
805  bool enableSrcNoData = provider->sourceHasNoDataValue( 1 ) && !std::isnan( provider->sourceNoDataValue( 1 ) );
806 
807  mSrcNoDataValueCheckBox->setEnabled( enableSrcNoData );
808  lblSrcNoDataValue->setEnabled( enableSrcNoData );
809 
810  QgsRasterRangeList noDataRangeList = provider->userNoDataValues( 1 );
811  QgsDebugMsgLevel( QStringLiteral( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ), 3 );
812  if ( !noDataRangeList.isEmpty() )
813  {
814  leNoDataValue->insert( QgsRasterBlock::printValue( noDataRangeList.value( 0 ).min() ) );
815  }
816  else
817  {
818  leNoDataValue->insert( QString() );
819  }
820 
821  mRefreshLayerCheckBox->setChecked( mRasterLayer->hasAutoRefreshEnabled() );
822  mRefreshLayerIntervalSpinBox->setEnabled( mRasterLayer->hasAutoRefreshEnabled() );
823  mRefreshLayerIntervalSpinBox->setValue( mRasterLayer->autoRefreshInterval() / 1000.0 );
824 
825  populateTransparencyTable( mRasterLayer->renderer() );
826 
827  QgsDebugMsgLevel( QStringLiteral( "populate colormap tab" ), 3 );
828  /*
829  * Transparent Pixel Tab
830  */
831 
832  QgsDebugMsgLevel( QStringLiteral( "populate general tab" ), 3 );
833  /*
834  * General Tab
835  */
836 
837  //these properties (layer name and label) are provided by the qgsmaplayer superclass
838  mLayerOrigNameLineEd->setText( mRasterLayer->name() );
839  leDisplayName->setText( mRasterLayer->name() );
840 
841  QgsDebugMsgLevel( QStringLiteral( "populate metadata tab" ), 2 );
842  /*
843  * Metadata Tab
844  */
845  //populate the metadata tab's text browser widget with gdal metadata info
846  updateInformationContent();
847 
848  // WMS Name as layer short name
849  mLayerShortNameLineEdit->setText( mRasterLayer->shortName() );
850  // WMS Name validator
851  QValidator *shortNameValidator = new QRegExpValidator( QgsApplication::shortNameRegExp(), this );
852  mLayerShortNameLineEdit->setValidator( shortNameValidator );
853 
854  //layer title and abstract
855  mLayerTitleLineEdit->setText( mRasterLayer->title() );
856  mLayerAbstractTextEdit->setPlainText( mRasterLayer->abstract() );
857  mLayerKeywordListLineEdit->setText( mRasterLayer->keywordList() );
858  mLayerDataUrlLineEdit->setText( mRasterLayer->dataUrl() );
859  mLayerDataUrlFormatComboBox->setCurrentIndex(
860  mLayerDataUrlFormatComboBox->findText(
861  mRasterLayer->dataUrlFormat()
862  )
863  );
864 
865  //layer attribution and metadataUrl
866  mLayerAttributionLineEdit->setText( mRasterLayer->attribution() );
867  mLayerAttributionUrlLineEdit->setText( mRasterLayer->attributionUrl() );
868  mLayerMetadataUrlLineEdit->setText( mRasterLayer->metadataUrl() );
869  mLayerMetadataUrlTypeComboBox->setCurrentIndex(
870  mLayerMetadataUrlTypeComboBox->findText(
871  mRasterLayer->metadataUrlType()
872  )
873  );
874  mLayerMetadataUrlFormatComboBox->setCurrentIndex(
875  mLayerMetadataUrlFormatComboBox->findText(
876  mRasterLayer->metadataUrlFormat()
877  )
878  );
879 
880  mLayerLegendUrlLineEdit->setText( mRasterLayer->legendUrl() );
881  mLayerLegendUrlFormatComboBox->setCurrentIndex( mLayerLegendUrlFormatComboBox->findText( mRasterLayer->legendUrlFormat() ) );
882 
883  //WMS print layer
884  QVariant wmsPrintLayer = mRasterLayer->customProperty( QStringLiteral( "WMSPrintLayer" ) );
885  if ( wmsPrintLayer.isValid() )
886  {
887  mWMSPrintLayerLineEdit->setText( wmsPrintLayer.toString() );
888  }
889 
890  QVariant wmsPublishDataSourceUrl = mRasterLayer->customProperty( QStringLiteral( "WMSPublishDataSourceUrl" ), false );
891  mPublishDataSourceUrlCheckBox->setChecked( wmsPublishDataSourceUrl.toBool() );
892 
893  QVariant wmsBackgroundLayer = mRasterLayer->customProperty( QStringLiteral( "WMSBackgroundLayer" ), false );
894  mBackgroundLayerCheckBox->setChecked( wmsBackgroundLayer.toBool() );
895 
896  mLegendConfigEmbeddedWidget->setLayer( mRasterLayer );
897 
898  mTemporalWidget->syncToLayer();
899 
900  for ( QgsMapLayerConfigWidget *page : std::as_const( mLayerPropertiesPages ) )
901  {
902  page->syncToLayer( mRasterLayer );
903  }
904 
905 }
906 
907 void QgsRasterLayerProperties::apply()
908 {
909  if ( mSourceWidget )
910  {
911  const QString newSource = mSourceWidget->sourceUri();
912  if ( newSource != mRasterLayer->source() )
913  {
914  mRasterLayer->setDataSource( newSource, mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );
915  }
916  }
917 
918  // Do nothing on "bad" layers
919  if ( !mRasterLayer->isValid() )
920  return;
921 
922  /*
923  * Legend Tab
924  */
925  mLegendConfigEmbeddedWidget->applyToLayer();
926 
927  QgsDebugMsgLevel( QStringLiteral( "apply processing symbology tab" ), 3 );
928  /*
929  * Symbology Tab
930  */
931 
932  //set whether the layer histogram should be inverted
933  //mRasterLayer->setInvertHistogram( cboxInvertColorMap->isChecked() );
934 
935  mRasterLayer->brightnessFilter()->setBrightness( mSliderBrightness->value() );
936  mRasterLayer->brightnessFilter()->setContrast( mSliderContrast->value() );
937  mRasterLayer->brightnessFilter()->setGamma( mGammaSpinBox->value() );
938 
939  QgsDebugMsgLevel( QStringLiteral( "processing transparency tab" ), 3 );
940  /*
941  * Transparent Pixel Tab
942  */
943 
944  //set NoDataValue
945  QgsRasterRangeList myNoDataRangeList;
946  if ( "" != leNoDataValue->text() )
947  {
948  bool myDoubleOk = false;
949  double myNoDataValue = QgsDoubleValidator::toDouble( leNoDataValue->text(), &myDoubleOk );
950  if ( myDoubleOk )
951  {
952  QgsRasterRange myNoDataRange( myNoDataValue, myNoDataValue );
953  myNoDataRangeList << myNoDataRange;
954  }
955  }
956  for ( int bandNo = 1; bandNo <= mRasterLayer->dataProvider()->bandCount(); bandNo++ )
957  {
958  mRasterLayer->dataProvider()->setUserNoDataValue( bandNo, myNoDataRangeList );
959  mRasterLayer->dataProvider()->setUseSourceNoDataValue( bandNo, mSrcNoDataValueCheckBox->isChecked() );
960  }
961 
962  //set renderer from widget
963  QgsRasterRendererWidget *rendererWidget = dynamic_cast<QgsRasterRendererWidget *>( mRendererStackedWidget->currentWidget() );
964  if ( rendererWidget )
965  {
966  rendererWidget->doComputations();
967 
968  mRasterLayer->setRenderer( rendererWidget->renderer() );
969  }
970 
971  mMetadataWidget->acceptMetadata();
972  mMetadataFilled = false;
973 
974  //transparency settings
975  QgsRasterRenderer *rasterRenderer = mRasterLayer->renderer();
976  if ( rasterRenderer )
977  {
978  rasterRenderer->setAlphaBand( cboxTransparencyBand->currentBand() );
979 
980  //Walk through each row in table and test value. If not valid set to 0.0 and continue building transparency list
981  QgsRasterTransparency *rasterTransparency = new QgsRasterTransparency();
982  if ( tableTransparency->columnCount() == 4 )
983  {
985  QList<QgsRasterTransparency::TransparentThreeValuePixel> myTransparentThreeValuePixelList;
986  for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
987  {
988  myTransparentPixel.red = transparencyCellValue( myListRunner, 0 );
989  myTransparentPixel.green = transparencyCellValue( myListRunner, 1 );
990  myTransparentPixel.blue = transparencyCellValue( myListRunner, 2 );
991  myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 3 );
992  myTransparentThreeValuePixelList.append( myTransparentPixel );
993  }
994  rasterTransparency->setTransparentThreeValuePixelList( myTransparentThreeValuePixelList );
995  }
996  else if ( tableTransparency->columnCount() == 3 )
997  {
999  QList<QgsRasterTransparency::TransparentSingleValuePixel> myTransparentSingleValuePixelList;
1000  for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
1001  {
1002  myTransparentPixel.min = transparencyCellValue( myListRunner, 0 );
1003  myTransparentPixel.max = transparencyCellValue( myListRunner, 1 );
1004  myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 2 );
1005 
1006  myTransparentSingleValuePixelList.append( myTransparentPixel );
1007  }
1008  rasterTransparency->setTransparentSingleValuePixelList( myTransparentSingleValuePixelList );
1009  }
1010 
1011  rasterRenderer->setRasterTransparency( rasterTransparency );
1012 
1013  //set global transparency
1014  rasterRenderer->setOpacity( mOpacityWidget->opacity() );
1015  }
1016 
1017  QgsDebugMsgLevel( QStringLiteral( "processing general tab" ), 3 );
1018  /*
1019  * General Tab
1020  */
1021  mRasterLayer->setName( mLayerOrigNameLineEd->text() );
1022 
1023  // set up the scale based layer visibility stuff....
1024  mRasterLayer->setScaleBasedVisibility( chkUseScaleDependentRendering->isChecked() );
1025  mRasterLayer->setMinimumScale( mScaleRangeWidget->minimumScale() );
1026  mRasterLayer->setMaximumScale( mScaleRangeWidget->maximumScale() );
1027 
1028  mRasterLayer->setAutoRefreshInterval( mRefreshLayerIntervalSpinBox->value() * 1000.0 );
1029  mRasterLayer->setAutoRefreshEnabled( mRefreshLayerCheckBox->isChecked() );
1030 
1031  //update the legend pixmap
1032  // pixmapLegend->setPixmap( mRasterLayer->legendAsPixmap() );
1033  // pixmapLegend->setScaledContents( true );
1034  // pixmapLegend->repaint();
1035 
1036  mResamplingUtils.refreshLayerFromWidgets();
1037 
1038  // Hue and saturation controls
1039  QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter();
1040  if ( hueSaturationFilter )
1041  {
1042  hueSaturationFilter->setSaturation( sliderSaturation->value() );
1043  hueSaturationFilter->setGrayscaleMode( ( QgsHueSaturationFilter::GrayscaleMode ) comboGrayscale->currentIndex() );
1044  hueSaturationFilter->setColorizeOn( mColorizeCheck->checkState() );
1045  hueSaturationFilter->setColorizeColor( btnColorizeColor->color() );
1046  hueSaturationFilter->setColorizeStrength( sliderColorizeStrength->value() );
1047  }
1048 
1049  //set the blend mode for the layer
1050  mRasterLayer->setBlendMode( mBlendModeComboBox->blendMode() );
1051 
1052  // Update temporal properties
1053  mTemporalWidget->saveTemporalProperties();
1054 
1055  mRasterLayer->setCrs( mCrsSelector->crs() );
1056 
1057  if ( mRasterLayer->shortName() != mLayerShortNameLineEdit->text() )
1058  mMetadataFilled = false;
1059  mRasterLayer->setShortName( mLayerShortNameLineEdit->text() );
1060 
1061  if ( mRasterLayer->title() != mLayerTitleLineEdit->text() )
1062  mMetadataFilled = false;
1063  mRasterLayer->setTitle( mLayerTitleLineEdit->text() );
1064 
1065  if ( mRasterLayer->abstract() != mLayerAbstractTextEdit->toPlainText() )
1066  mMetadataFilled = false;
1067  mRasterLayer->setAbstract( mLayerAbstractTextEdit->toPlainText() );
1068 
1069  if ( mRasterLayer->keywordList() != mLayerKeywordListLineEdit->text() )
1070  mMetadataFilled = false;
1071  mRasterLayer->setKeywordList( mLayerKeywordListLineEdit->text() );
1072 
1073  if ( mRasterLayer->dataUrl() != mLayerDataUrlLineEdit->text() )
1074  mMetadataFilled = false;
1075  mRasterLayer->setDataUrl( mLayerDataUrlLineEdit->text() );
1076 
1077  if ( mRasterLayer->dataUrlFormat() != mLayerDataUrlFormatComboBox->currentText() )
1078  mMetadataFilled = false;
1079  mRasterLayer->setDataUrlFormat( mLayerDataUrlFormatComboBox->currentText() );
1080 
1081  //layer attribution and metadataUrl
1082  if ( mRasterLayer->attribution() != mLayerAttributionLineEdit->text() )
1083  mMetadataFilled = false;
1084  mRasterLayer->setAttribution( mLayerAttributionLineEdit->text() );
1085 
1086  if ( mRasterLayer->attributionUrl() != mLayerAttributionUrlLineEdit->text() )
1087  mMetadataFilled = false;
1088  mRasterLayer->setAttributionUrl( mLayerAttributionUrlLineEdit->text() );
1089 
1090  if ( mRasterLayer->metadataUrl() != mLayerMetadataUrlLineEdit->text() )
1091  mMetadataFilled = false;
1092  mRasterLayer->setMetadataUrl( mLayerMetadataUrlLineEdit->text() );
1093 
1094  if ( mRasterLayer->metadataUrlType() != mLayerMetadataUrlTypeComboBox->currentText() )
1095  mMetadataFilled = false;
1096  mRasterLayer->setMetadataUrlType( mLayerMetadataUrlTypeComboBox->currentText() );
1097 
1098  if ( mRasterLayer->metadataUrlFormat() != mLayerMetadataUrlFormatComboBox->currentText() )
1099  mMetadataFilled = false;
1100  mRasterLayer->setMetadataUrlFormat( mLayerMetadataUrlFormatComboBox->currentText() );
1101 
1102  if ( mRasterLayer->legendUrl() != mLayerLegendUrlLineEdit->text() )
1103  mMetadataFilled = false;
1104  mRasterLayer->setLegendUrl( mLayerLegendUrlLineEdit->text() );
1105 
1106  if ( mRasterLayer->legendUrlFormat() != mLayerLegendUrlFormatComboBox->currentText() )
1107  mMetadataFilled = false;
1108  mRasterLayer->setLegendUrlFormat( mLayerLegendUrlFormatComboBox->currentText() );
1109 
1110  if ( !mWMSPrintLayerLineEdit->text().isEmpty() )
1111  {
1112  mRasterLayer->setCustomProperty( QStringLiteral( "WMSPrintLayer" ), mWMSPrintLayerLineEdit->text() );
1113  }
1114 
1115  mRasterLayer->setCustomProperty( "WMSPublishDataSourceUrl", mPublishDataSourceUrlCheckBox->isChecked() );
1116  mRasterLayer->setCustomProperty( "WMSBackgroundLayer", mBackgroundLayerCheckBox->isChecked() );
1117 
1118  // Force a redraw of the legend
1119  mRasterLayer->setLegend( QgsMapLayerLegend::defaultRasterLegend( mRasterLayer ) );
1120 
1121  //make sure the layer is redrawn
1122  mRasterLayer->triggerRepaint();
1123 
1124  // notify the project we've made a change
1125  QgsProject::instance()->setDirty( true );
1126 }
1127 
1128 void QgsRasterLayerProperties::mLayerOrigNameLineEd_textEdited( const QString &text )
1129 {
1130  leDisplayName->setText( mRasterLayer->formatLayerName( text ) );
1131 }
1132 
1133 void QgsRasterLayerProperties::buttonBuildPyramids_clicked()
1134 {
1135  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
1136 
1137  std::unique_ptr< QgsRasterBlockFeedback > feedback( new QgsRasterBlockFeedback() );
1138 
1139  connect( feedback.get(), &QgsRasterBlockFeedback::progressChanged, mPyramidProgress, &QProgressBar::setValue );
1140  //
1141  // Go through the list marking any files that are selected in the listview
1142  // as true so that we can generate pyramids for them.
1143  //
1144  QList< QgsRasterPyramid> myPyramidList = provider->buildPyramidList();
1145  for ( int myCounterInt = 0; myCounterInt < lbxPyramidResolutions->count(); myCounterInt++ )
1146  {
1147  QListWidgetItem *myItem = lbxPyramidResolutions->item( myCounterInt );
1148  //mark to be pyramided
1149  myPyramidList[myCounterInt].setBuild( myItem->isSelected() || myPyramidList[myCounterInt].getExists() );
1150  }
1151 
1152  // keep it in sync with qgsrasterpyramidsoptionwidget.cpp
1153  QString prefix = provider->name() + "/driverOptions/_pyramids/";
1154  QgsSettings mySettings;
1155  QString resamplingMethod( cboResamplingMethod->currentData().toString() );
1156  mySettings.setValue( prefix + "resampling", resamplingMethod );
1157 
1158  //
1159  // Ask raster layer to build the pyramids
1160  //
1161 
1162  // let the user know we're going to possibly be taking a while
1163  QApplication::setOverrideCursor( Qt::WaitCursor );
1164  QString res = provider->buildPyramids(
1165  myPyramidList,
1166  resamplingMethod,
1167  ( QgsRaster::RasterPyramidsFormat ) cbxPyramidsFormat->currentIndex(),
1168  QStringList(),
1169  feedback.get() );
1170  QApplication::restoreOverrideCursor();
1171  mPyramidProgress->setValue( 0 );
1172  buttonBuildPyramids->setEnabled( false );
1173  if ( !res.isNull() )
1174  {
1175  if ( res == QLatin1String( "CANCELED" ) )
1176  {
1177  // user canceled
1178  }
1179  else if ( res == QLatin1String( "ERROR_WRITE_ACCESS" ) )
1180  {
1181  QMessageBox::warning( this, tr( "Building Pyramids" ),
1182  tr( "Write access denied. Adjust the file permissions and try again." ) );
1183  }
1184  else if ( res == QLatin1String( "ERROR_WRITE_FORMAT" ) )
1185  {
1186  QMessageBox::warning( this, tr( "Building Pyramids" ),
1187  tr( "The file was not writable. Some formats do not "
1188  "support pyramid overviews. Consult the GDAL documentation if in doubt." ) );
1189  }
1190  else if ( res == QLatin1String( "FAILED_NOT_SUPPORTED" ) )
1191  {
1192  QMessageBox::warning( this, tr( "Building Pyramids" ),
1193  tr( "Building pyramid overviews is not supported on this type of raster." ) );
1194  }
1195  else if ( res == QLatin1String( "ERROR_JPEG_COMPRESSION" ) )
1196  {
1197  QMessageBox::warning( this, tr( "Building Pyramids" ),
1198  tr( "Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." ) );
1199  }
1200  else if ( res == QLatin1String( "ERROR_VIRTUAL" ) )
1201  {
1202  QMessageBox::warning( this, tr( "Building Pyramids" ),
1203  tr( "Building pyramid overviews is not supported on this type of raster." ) );
1204  }
1205 
1206  }
1207 
1208  //
1209  // repopulate the pyramids list
1210  //
1211  lbxPyramidResolutions->clear();
1212  // Need to rebuild list as some or all pyramids may have failed to build
1213  myPyramidList = provider->buildPyramidList();
1214  QIcon myPyramidPixmap( QgsApplication::getThemeIcon( "/mIconPyramid.svg" ) );
1215  QIcon myNoPyramidPixmap( QgsApplication::getThemeIcon( "/mIconNoPyramid.svg" ) );
1216 
1217  QList< QgsRasterPyramid >::iterator myRasterPyramidIterator;
1218  for ( const QgsRasterPyramid &pyramid : std::as_const( myPyramidList ) )
1219  {
1220  if ( pyramid.getExists() )
1221  {
1222  lbxPyramidResolutions->addItem( new QListWidgetItem( myPyramidPixmap,
1223  QString::number( pyramid.getXDim() ) + QStringLiteral( " x " ) +
1224  QString::number( pyramid.getYDim() ) ) );
1225  }
1226  else
1227  {
1228  lbxPyramidResolutions->addItem( new QListWidgetItem( myNoPyramidPixmap,
1229  QString::number( pyramid.getXDim() ) + QStringLiteral( " x " ) +
1230  QString::number( pyramid.getYDim() ) ) );
1231  }
1232  }
1233  //update the legend pixmap
1234  // pixmapLegend->setPixmap( mRasterLayer->legendAsPixmap() );
1235  // pixmapLegend->setScaledContents( true );
1236  // pixmapLegend->repaint();
1237 
1238  //populate the metadata tab's text browser widget with gdal metadata info
1239  updateInformationContent();
1240 }
1241 
1242 void QgsRasterLayerProperties::urlClicked( const QUrl &url )
1243 {
1244  QFileInfo file( url.toLocalFile() );
1245  if ( file.exists() && !file.isDir() )
1246  QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
1247  else
1248  QDesktopServices::openUrl( url );
1249 }
1250 
1251 void QgsRasterLayerProperties::mRenderTypeComboBox_currentIndexChanged( int index )
1252 {
1253  if ( index < 0 || mDisableRenderTypeComboBoxCurrentIndexChanged || ! mRasterLayer->renderer() )
1254  {
1255  return;
1256  }
1257 
1258  QString rendererName = mRenderTypeComboBox->itemData( index ).toString();
1259  setRendererWidget( rendererName );
1260 }
1261 
1262 void QgsRasterLayerProperties::pbnAddValuesFromDisplay_clicked()
1263 {
1264  if ( mMapCanvas && mPixelSelectorTool )
1265  {
1266  //Need to work around the modality of the dialog but can not just hide() it.
1267  // According to Qt5 docs, to change modality the dialog needs to be hidden
1268  // and shown again.
1269  hide();
1270  setModal( false );
1271 
1272  // Transfer focus to the canvas to use the selector tool
1273  mMapCanvas->window()->raise();
1274  mMapCanvas->window()->activateWindow();
1275  mMapCanvas->window()->setFocus();
1276  mMapCanvas->setMapTool( mPixelSelectorTool.get() );
1277 
1278  }
1279 }
1280 
1281 void QgsRasterLayerProperties::pbnAddValuesManually_clicked()
1282 {
1283  QgsRasterRenderer *renderer = mRendererWidget->renderer();
1284  if ( !renderer )
1285  {
1286  return;
1287  }
1288 
1289  tableTransparency->insertRow( tableTransparency->rowCount() );
1290 
1291  int n = renderer->usesBands().size();
1292  if ( n == 1 ) n++;
1293 
1294  for ( int i = 0; i < n; i++ )
1295  {
1296  setTransparencyCell( tableTransparency->rowCount() - 1, i, std::numeric_limits<double>::quiet_NaN() );
1297  }
1298 
1299  setTransparencyCell( tableTransparency->rowCount() - 1, n, 100 );
1300 
1301  tableTransparency->resizeColumnsToContents();
1302  tableTransparency->resizeRowsToContents();
1303 }
1304 
1305 void QgsRasterLayerProperties::mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem &crs )
1306 {
1307  QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mMapCanvas, tr( "Select Transformation" ) );
1308  mRasterLayer->setCrs( crs );
1309  mMetadataWidget->crsChanged();
1310 }
1311 
1312 void QgsRasterLayerProperties::pbnDefaultValues_clicked()
1313 {
1314  if ( !mRendererWidget )
1315  {
1316  return;
1317  }
1318 
1319  QgsRasterRenderer *r = mRendererWidget->renderer();
1320  if ( !r )
1321  {
1322  return;
1323  }
1324 
1325  int nBands = r->usesBands().size();
1326  delete r; // really delete?
1327 
1328  setupTransparencyTable( nBands );
1329 
1330  tableTransparency->resizeColumnsToContents(); // works only with values
1331  tableTransparency->resizeRowsToContents();
1332 }
1333 
1334 void QgsRasterLayerProperties::setTransparencyCell( int row, int column, double value )
1335 {
1336  QgsDebugMsgLevel( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ), 3 );
1337  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
1338  if ( !provider ) return;
1339 
1340  QgsRasterRenderer *renderer = mRendererWidget->renderer();
1341  if ( !renderer ) return;
1342  int nBands = renderer->usesBands().size();
1343 
1344  QLineEdit *lineEdit = new QLineEdit();
1345  lineEdit->setFrame( false ); // frame looks bad in table
1346  // Without margins row selection is not displayed (important for delete row)
1347  lineEdit->setContentsMargins( 1, 1, 1, 1 );
1348 
1349  if ( column == tableTransparency->columnCount() - 1 )
1350  {
1351  // transparency
1352  // Who needs transparency as floating point?
1353  lineEdit->setValidator( new QIntValidator( nullptr ) );
1354  lineEdit->setText( QString::number( static_cast<int>( value ) ) );
1355  }
1356  else
1357  {
1358  // value
1359  QString valueString;
1360  switch ( provider->sourceDataType( 1 ) )
1361  {
1364  lineEdit->setValidator( new QgsDoubleValidator( nullptr ) );
1365  if ( !std::isnan( value ) )
1366  {
1367  double v = QgsRasterBlock::printValue( value ).toDouble();
1368  valueString = QLocale().toString( v, 'g' ) ;
1369  }
1370  break;
1371  default:
1372  lineEdit->setValidator( new QIntValidator( nullptr ) );
1373  if ( !std::isnan( value ) )
1374  {
1375  valueString = QLocale().toString( static_cast<int>( value ) );
1376  }
1377  break;
1378  }
1379  lineEdit->setText( valueString );
1380  }
1381  tableTransparency->setCellWidget( row, column, lineEdit );
1382  adjustTransparencyCellWidth( row, column );
1383 
1384  if ( nBands == 1 && ( column == 0 || column == 1 ) )
1385  {
1386  connect( lineEdit, &QLineEdit::textEdited, this, &QgsRasterLayerProperties::transparencyCellTextEdited );
1387  }
1388  tableTransparency->resizeColumnsToContents();
1389 }
1390 
1391 void QgsRasterLayerProperties::setTransparencyCellValue( int row, int column, double value )
1392 {
1393  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
1394  if ( !lineEdit ) return;
1395  double v = QgsRasterBlock::printValue( value ).toDouble();
1396  lineEdit->setText( QLocale().toString( v, 'g' ) );
1397  lineEdit->adjustSize();
1398  adjustTransparencyCellWidth( row, column );
1399  tableTransparency->resizeColumnsToContents();
1400 }
1401 
1402 double QgsRasterLayerProperties::transparencyCellValue( int row, int column )
1403 {
1404  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
1405  if ( !lineEdit || lineEdit->text().isEmpty() )
1406  {
1407  return std::numeric_limits<double>::quiet_NaN();
1408  }
1409  return lineEdit->text().toDouble();
1410 }
1411 
1412 void QgsRasterLayerProperties::adjustTransparencyCellWidth( int row, int column )
1413 {
1414  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
1415  if ( !lineEdit ) return;
1416 
1417  int width = std::max( lineEdit->fontMetrics().boundingRect( lineEdit->text() ).width() + 10, 100 );
1418  width = std::max( width, tableTransparency->columnWidth( column ) );
1419 
1420  lineEdit->setFixedWidth( width );
1421 }
1422 
1423 void QgsRasterLayerProperties::pbnExportTransparentPixelValues_clicked()
1424 {
1425  QgsSettings myQSettings;
1426  QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
1427  QString myFileName = QFileDialog::getSaveFileName( this, tr( "Save File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
1428  if ( !myFileName.isEmpty() )
1429  {
1430  if ( !myFileName.endsWith( QLatin1String( ".txt" ), Qt::CaseInsensitive ) )
1431  {
1432  myFileName = myFileName + ".txt";
1433  }
1434 
1435  QFile myOutputFile( myFileName );
1436  if ( myOutputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
1437  {
1438  QTextStream myOutputStream( &myOutputFile );
1439  myOutputStream << "# " << tr( "QGIS Generated Transparent Pixel Value Export File" ) << '\n';
1440  if ( rasterIsMultiBandColor() )
1441  {
1442  myOutputStream << "#\n#\n# " << tr( "Red" ) << "\t" << tr( "Green" ) << "\t" << tr( "Blue" ) << "\t" << tr( "Percent Transparent" );
1443  for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
1444  {
1445  myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
1446  << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
1447  << QString::number( transparencyCellValue( myTableRunner, 2 ) ) << "\t"
1448  << QString::number( transparencyCellValue( myTableRunner, 3 ) );
1449  }
1450  }
1451  else
1452  {
1453  myOutputStream << "#\n#\n# " << tr( "Value" ) << "\t" << tr( "Percent Transparent" );
1454 
1455  for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
1456  {
1457  myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
1458  << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
1459  << QString::number( transparencyCellValue( myTableRunner, 2 ) );
1460  }
1461  }
1462  }
1463  else
1464  {
1465  QMessageBox::warning( this, tr( "Export Transparent Pixels" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
1466  }
1467  }
1468 }
1469 
1470 void QgsRasterLayerProperties::transparencyCellTextEdited( const QString &text )
1471 {
1472  Q_UNUSED( text )
1473  QgsDebugMsgLevel( QStringLiteral( "text = %1" ).arg( text ), 3 );
1474  QgsRasterRenderer *renderer = mRendererWidget->renderer();
1475  if ( !renderer )
1476  {
1477  return;
1478  }
1479  int nBands = renderer->usesBands().size();
1480  if ( nBands == 1 )
1481  {
1482  QLineEdit *lineEdit = qobject_cast<QLineEdit *>( sender() );
1483  if ( !lineEdit ) return;
1484  int row = -1;
1485  int column = -1;
1486  for ( int r = 0; r < tableTransparency->rowCount(); r++ )
1487  {
1488  for ( int c = 0; c < tableTransparency->columnCount(); c++ )
1489  {
1490  if ( tableTransparency->cellWidget( r, c ) == sender() )
1491  {
1492  row = r;
1493  column = c;
1494  break;
1495  }
1496  }
1497  if ( row != -1 ) break;
1498  }
1499  QgsDebugMsgLevel( QStringLiteral( "row = %1 column =%2" ).arg( row ).arg( column ), 3 );
1500 
1501  if ( column == 0 )
1502  {
1503  QLineEdit *toLineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, 1 ) );
1504  if ( !toLineEdit ) return;
1505  bool toChanged = mTransparencyToEdited.value( row );
1506  QgsDebugMsgLevel( QStringLiteral( "toChanged = %1" ).arg( toChanged ), 3 );
1507  if ( !toChanged )
1508  {
1509  toLineEdit->setText( lineEdit->text() );
1510  }
1511  }
1512  else if ( column == 1 )
1513  {
1514  setTransparencyToEdited( row );
1515  }
1516  }
1517 }
1518 
1519 void QgsRasterLayerProperties::aboutToShowStyleMenu()
1520 {
1521  // this should be unified with QgsVectorLayerProperties::aboutToShowStyleMenu()
1522 
1523  QMenu *m = qobject_cast<QMenu *>( sender() );
1524 
1526  // re-add style manager actions!
1527  m->addSeparator();
1529 }
1530 
1531 void QgsRasterLayerProperties::syncToLayer()
1532 {
1533  QgsRasterRenderer *renderer = mRasterLayer->renderer();
1534  if ( renderer )
1535  {
1536  setRendererWidget( renderer->type() );
1537  }
1538  sync();
1539  mRasterLayer->triggerRepaint();
1540 }
1541 
1542 void QgsRasterLayerProperties::setTransparencyToEdited( int row )
1543 {
1544  if ( row >= mTransparencyToEdited.size() )
1545  {
1546  mTransparencyToEdited.resize( row + 1 );
1547  }
1548  mTransparencyToEdited[row] = true;
1549 }
1550 
1552 {
1554 
1555  bool isMetadataPanel = ( index == mOptStackedWidget->indexOf( mOptsPage_Metadata ) );
1556  mBtnStyle->setVisible( ! isMetadataPanel );
1557  mBtnMetadata->setVisible( isMetadataPanel );
1558 
1559  if ( !mHistogramWidget )
1560  return;
1561 
1562  if ( index == mOptStackedWidget->indexOf( mOptsPage_Histogram ) )
1563  {
1564  mHistogramWidget->setActive( true );
1565  }
1566  else
1567  {
1568  mHistogramWidget->setActive( false );
1569  }
1570 
1571  if ( index == mOptStackedWidget->indexOf( mOptsPage_Information ) || !mMetadataFilled )
1572  {
1573  //set the metadata contents (which can be expensive)
1574  updateInformationContent();
1575  }
1576 }
1577 
1578 void QgsRasterLayerProperties::pbnImportTransparentPixelValues_clicked()
1579 {
1580  int myLineCounter = 0;
1581  bool myImportError = false;
1582  QString myBadLines;
1583  QgsSettings myQSettings;
1584  QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
1585  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Open file" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
1586  QFile myInputFile( myFileName );
1587  if ( myInputFile.open( QFile::ReadOnly ) )
1588  {
1589  QTextStream myInputStream( &myInputFile );
1590  QString myInputLine;
1591  if ( rasterIsMultiBandColor() )
1592  {
1593  for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
1594  {
1595  tableTransparency->removeRow( myTableRunner );
1596  }
1597 
1598  while ( !myInputStream.atEnd() )
1599  {
1600  myLineCounter++;
1601  myInputLine = myInputStream.readLine();
1602  if ( !myInputLine.isEmpty() )
1603  {
1604  if ( !myInputLine.simplified().startsWith( '#' ) )
1605  {
1606 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1607  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
1608 #else
1609  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), Qt::SkipEmptyParts );
1610 #endif
1611  if ( myTokens.count() != 4 )
1612  {
1613  myImportError = true;
1614  myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
1615  }
1616  else
1617  {
1618  tableTransparency->insertRow( tableTransparency->rowCount() );
1619  for ( int col = 0; col < 4; col++ )
1620  {
1621  setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
1622  }
1623  }
1624  }
1625  }
1626  }
1627  }
1628  else
1629  {
1630  for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
1631  {
1632  tableTransparency->removeRow( myTableRunner );
1633  }
1634 
1635  while ( !myInputStream.atEnd() )
1636  {
1637  myLineCounter++;
1638  myInputLine = myInputStream.readLine();
1639  if ( !myInputLine.isEmpty() )
1640  {
1641  if ( !myInputLine.simplified().startsWith( '#' ) )
1642  {
1643 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1644  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
1645 #else
1646  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), Qt::SkipEmptyParts );
1647 #endif
1648  if ( myTokens.count() != 3 && myTokens.count() != 2 ) // 2 for QGIS < 1.9 compatibility
1649  {
1650  myImportError = true;
1651  myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
1652  }
1653  else
1654  {
1655  if ( myTokens.count() == 2 )
1656  {
1657  myTokens.insert( 1, myTokens[0] ); // add 'to' value, QGIS < 1.9 compatibility
1658  }
1659  tableTransparency->insertRow( tableTransparency->rowCount() );
1660  for ( int col = 0; col < 3; col++ )
1661  {
1662  setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
1663  }
1664  }
1665  }
1666  }
1667  }
1668  }
1669 
1670  if ( myImportError )
1671  {
1672  QMessageBox::warning( this, tr( "Import Transparent Pixels" ), tr( "The following lines contained errors\n\n%1" ).arg( myBadLines ) );
1673  }
1674  }
1675  else if ( !myFileName.isEmpty() )
1676  {
1677  QMessageBox::warning( this, tr( "Import Transparent Pixels" ), tr( "Read access denied. Adjust the file permissions and try again.\n\n" ) );
1678  }
1679  tableTransparency->resizeColumnsToContents();
1680  tableTransparency->resizeRowsToContents();
1681 }
1682 
1683 void QgsRasterLayerProperties::pbnRemoveSelectedRow_clicked()
1684 {
1685  if ( 0 < tableTransparency->rowCount() )
1686  {
1687  tableTransparency->removeRow( tableTransparency->currentRow() );
1688  }
1689 }
1690 
1691 void QgsRasterLayerProperties::pixelSelected( const QgsPointXY &canvasPoint, const Qt::MouseButton &btn )
1692 {
1693  Q_UNUSED( btn )
1694  QgsRasterRenderer *renderer = mRendererWidget->renderer();
1695  if ( !renderer )
1696  {
1697  return;
1698  }
1699 
1700  //Get the pixel values and add a new entry to the transparency table
1701  if ( mMapCanvas && mPixelSelectorTool )
1702  {
1703  mMapCanvas->unsetMapTool( mPixelSelectorTool.get() );
1704 
1705  const QgsMapSettings &ms = mMapCanvas->mapSettings();
1706  QgsPointXY myPoint = ms.mapToLayerCoordinates( mRasterLayer, canvasPoint );
1707 
1708  QgsRectangle myExtent = ms.mapToLayerCoordinates( mRasterLayer, mMapCanvas->extent() );
1709  double mapUnitsPerPixel = mMapCanvas->mapUnitsPerPixel();
1710  int myWidth = mMapCanvas->extent().width() / mapUnitsPerPixel;
1711  int myHeight = mMapCanvas->extent().height() / mapUnitsPerPixel;
1712 
1713  QMap<int, QVariant> myPixelMap = mRasterLayer->dataProvider()->identify( myPoint, QgsRaster::IdentifyFormatValue, myExtent, myWidth, myHeight ).results();
1714 
1715  QList<int> bands = renderer->usesBands();
1716 
1717  QList<double> values;
1718  for ( int i = 0; i < bands.size(); ++i )
1719  {
1720  int bandNo = bands.value( i );
1721  if ( myPixelMap.count( bandNo ) == 1 )
1722  {
1723  if ( myPixelMap.value( bandNo ).isNull() )
1724  {
1725  return; // Don't add nodata, transparent anyway
1726  }
1727  double value = myPixelMap.value( bandNo ).toDouble();
1728  QgsDebugMsgLevel( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ), 3 );
1729  values.append( value );
1730  }
1731  }
1732  if ( bands.size() == 1 )
1733  {
1734  // Set 'to'
1735  values.insert( 1, values.value( 0 ) );
1736  }
1737  tableTransparency->insertRow( tableTransparency->rowCount() );
1738  for ( int i = 0; i < values.size(); i++ )
1739  {
1740  setTransparencyCell( tableTransparency->rowCount() - 1, i, values.value( i ) );
1741  }
1742  setTransparencyCell( tableTransparency->rowCount() - 1, tableTransparency->columnCount() - 1, 100 );
1743  }
1744  delete renderer;
1745 
1746  tableTransparency->resizeColumnsToContents();
1747  tableTransparency->resizeRowsToContents();
1748 }
1749 
1750 void QgsRasterLayerProperties::toggleSaturationControls( int grayscaleMode )
1751 {
1752  // Enable or disable saturation controls based on choice of grayscale mode
1753  if ( grayscaleMode == 0 )
1754  {
1755  sliderSaturation->setEnabled( true );
1756  spinBoxSaturation->setEnabled( true );
1757  }
1758  else
1759  {
1760  sliderSaturation->setEnabled( false );
1761  spinBoxSaturation->setEnabled( false );
1762  }
1763 }
1764 
1765 void QgsRasterLayerProperties::toggleColorizeControls( bool colorizeEnabled )
1766 {
1767  // Enable or disable colorize controls based on checkbox
1768  btnColorizeColor->setEnabled( colorizeEnabled );
1769  sliderColorizeStrength->setEnabled( colorizeEnabled );
1770  spinColorizeStrength->setEnabled( colorizeEnabled );
1771 }
1772 
1773 
1774 QLinearGradient QgsRasterLayerProperties::redGradient()
1775 {
1776  //define a gradient
1777  // TODO change this to actual polygon dims
1778  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
1779  myGradient.setColorAt( 0.0, QColor( 242, 14, 25, 190 ) );
1780  myGradient.setColorAt( 0.5, QColor( 175, 29, 37, 190 ) );
1781  myGradient.setColorAt( 1.0, QColor( 114, 17, 22, 190 ) );
1782  return myGradient;
1783 }
1784 QLinearGradient QgsRasterLayerProperties::greenGradient()
1785 {
1786  //define a gradient
1787  // TODO change this to actual polygon dims
1788  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
1789  myGradient.setColorAt( 0.0, QColor( 48, 168, 5, 190 ) );
1790  myGradient.setColorAt( 0.8, QColor( 36, 122, 4, 190 ) );
1791  myGradient.setColorAt( 1.0, QColor( 21, 71, 2, 190 ) );
1792  return myGradient;
1793 }
1794 QLinearGradient QgsRasterLayerProperties::blueGradient()
1795 {
1796  //define a gradient
1797  // TODO change this to actual polygon dims
1798  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
1799  myGradient.setColorAt( 0.0, QColor( 30, 0, 106, 190 ) );
1800  myGradient.setColorAt( 0.2, QColor( 30, 72, 128, 190 ) );
1801  myGradient.setColorAt( 1.0, QColor( 30, 223, 196, 190 ) );
1802  return myGradient;
1803 }
1804 QLinearGradient QgsRasterLayerProperties::grayGradient()
1805 {
1806  //define a gradient
1807  // TODO change this to actual polygon dims
1808  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
1809  myGradient.setColorAt( 0.0, QColor( 5, 5, 5, 190 ) );
1810  myGradient.setColorAt( 0.8, QColor( 122, 122, 122, 190 ) );
1811  myGradient.setColorAt( 1.0, QColor( 220, 220, 220, 190 ) );
1812  return myGradient;
1813 }
1814 QLinearGradient QgsRasterLayerProperties::highlightGradient()
1815 {
1816  //define another gradient for the highlight
1817  // TODO change this to actual polygon dims
1818  QLinearGradient myGradient = QLinearGradient( mGradientWidth, 0, mGradientWidth, mGradientHeight );
1819  myGradient.setColorAt( 1.0, QColor( 255, 255, 255, 50 ) );
1820  myGradient.setColorAt( 0.5, QColor( 255, 255, 255, 100 ) );
1821  myGradient.setColorAt( 0.0, QColor( 255, 255, 255, 150 ) );
1822  return myGradient;
1823 }
1824 
1825 
1826 
1827 //
1828 //
1829 // Next four methods for saving and restoring qml style state
1830 //
1831 //
1832 void QgsRasterLayerProperties::loadDefaultStyle_clicked()
1833 {
1834  bool defaultLoadedFlag = false;
1835  QString myMessage = mRasterLayer->loadDefaultStyle( defaultLoadedFlag );
1836  //reset if the default style was loaded OK only
1837  if ( defaultLoadedFlag )
1838  {
1839  syncToLayer();
1840  }
1841  else
1842  {
1843  //otherwise let the user know what went wrong
1844  QMessageBox::information( this,
1845  tr( "Default Style" ),
1846  myMessage
1847  );
1848  }
1849 }
1850 
1851 void QgsRasterLayerProperties::saveDefaultStyle_clicked()
1852 {
1853 
1854  apply(); // make sure the style to save is up-to-date
1855 
1856  // a flag passed by reference
1857  bool defaultSavedFlag = false;
1858  // after calling this the above flag will be set true for success
1859  // or false if the save operation failed
1860  QString myMessage = mRasterLayer->saveDefaultStyle( defaultSavedFlag );
1861  if ( !defaultSavedFlag )
1862  {
1863  //let the user know what went wrong
1864  QMessageBox::information( this,
1865  tr( "Default Style" ),
1866  myMessage
1867  );
1868  }
1869 }
1870 
1871 
1872 void QgsRasterLayerProperties::loadStyle_clicked()
1873 {
1874  QgsSettings settings;
1875  QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
1876 
1877  QString fileName = QFileDialog::getOpenFileName(
1878  this,
1879  tr( "Load layer properties from style file" ),
1880  lastUsedDir,
1881  tr( "QGIS Layer Style File" ) + " (*.qml)" );
1882  if ( fileName.isEmpty() )
1883  return;
1884 
1885  // ensure the user never omits the extension from the file name
1886  if ( !fileName.endsWith( QLatin1String( ".qml" ), Qt::CaseInsensitive ) )
1887  fileName += QLatin1String( ".qml" );
1888 
1889  mOldStyle = mRasterLayer->styleManager()->style( mRasterLayer->styleManager()->currentStyle() );
1890 
1891  bool defaultLoadedFlag = false;
1892  QString message = mRasterLayer->loadNamedStyle( fileName, defaultLoadedFlag );
1893  if ( defaultLoadedFlag )
1894  {
1895  settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( fileName ).absolutePath() );
1896  syncToLayer();
1897  }
1898  else
1899  {
1900  QMessageBox::information( this, tr( "Save Style" ), message );
1901  }
1902 }
1903 
1904 
1905 void QgsRasterLayerProperties::saveStyleAs_clicked()
1906 {
1907  QgsSettings settings;
1908  QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
1909 
1910  QString selectedFilter;
1911  QString outputFileName = QFileDialog::getSaveFileName(
1912  this,
1913  tr( "Save layer properties as style file" ),
1914  lastUsedDir,
1915  tr( "QGIS Layer Style File" ) + " (*.qml)" + ";;" + tr( "Styled Layer Descriptor" ) + " (*.sld)",
1916  &selectedFilter );
1917  if ( outputFileName.isEmpty() )
1918  return;
1919 
1920  StyleType type;
1921  // use selectedFilter to set style type
1922  if ( selectedFilter.contains( QStringLiteral( ".qml" ), Qt::CaseInsensitive ) )
1923  {
1924  outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "qml" ) );
1925  type = StyleType::QML;
1926  }
1927  else
1928  {
1929  outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "sld" ) );
1930  type = StyleType::SLD;
1931  }
1932 
1933  apply(); // make sure the style to save is up-to-date
1934 
1935  // then export style
1936  bool defaultLoadedFlag = false;
1937  QString message;
1938  switch ( type )
1939  {
1940  case QML:
1941  {
1942  message = mRasterLayer->saveNamedStyle( outputFileName, defaultLoadedFlag );
1943  break;
1944  }
1945  case SLD:
1946  {
1947  message = mRasterLayer->saveSldStyle( outputFileName, defaultLoadedFlag );
1948  break;
1949  }
1950  }
1951  if ( defaultLoadedFlag )
1952  {
1953  settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( outputFileName ).absolutePath() );
1954  sync();
1955  }
1956  else
1957  QMessageBox::information( this, tr( "Save Style" ), message );
1958 }
1959 
1960 void QgsRasterLayerProperties::restoreWindowModality()
1961 {
1962  hide();
1963  setModal( true );
1964  show();
1965  raise();
1966  activateWindow();
1967 }
1968 
1969 //
1970 //
1971 // Next four methods for saving and restoring QMD metadata
1972 //
1973 //
1974 
1975 void QgsRasterLayerProperties::loadMetadata()
1976 {
1977  QgsSettings myQSettings; // where we keep last used filter in persistent state
1978  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
1979 
1980  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer metadata from metadata file" ), myLastUsedDir,
1981  tr( "QGIS Layer Metadata File" ) + " (*.qmd)" );
1982  if ( myFileName.isNull() )
1983  {
1984  return;
1985  }
1986 
1987  QString myMessage;
1988  bool defaultLoadedFlag = false;
1989  myMessage = mRasterLayer->loadNamedMetadata( myFileName, defaultLoadedFlag );
1990 
1991  //reset if the default style was loaded OK only
1992  if ( defaultLoadedFlag )
1993  {
1994  mMetadataWidget->setMetadata( &mRasterLayer->metadata() );
1995  }
1996  else
1997  {
1998  //let the user know what went wrong
1999  QMessageBox::warning( this, tr( "Load Metadata" ), myMessage );
2000  }
2001 
2002  QFileInfo myFI( myFileName );
2003  QString myPath = myFI.path();
2004  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
2005 
2006  activateWindow(); // set focus back to properties dialog
2007 }
2008 
2009 void QgsRasterLayerProperties::saveMetadataAs()
2010 {
2011  QgsSettings myQSettings; // where we keep last used filter in persistent state
2012  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
2013 
2014  QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save Layer Metadata as QMD" ),
2015  myLastUsedDir, tr( "QMD File" ) + " (*.qmd)" );
2016  if ( myOutputFileName.isNull() ) //dialog canceled
2017  {
2018  return;
2019  }
2020 
2021  mMetadataWidget->acceptMetadata();
2022 
2023  //ensure the user never omitted the extension from the file name
2024  if ( !myOutputFileName.endsWith( QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata ), Qt::CaseInsensitive ) )
2025  {
2027  }
2028 
2029  bool defaultLoadedFlag = false;
2030  QString message = mRasterLayer->saveNamedMetadata( myOutputFileName, defaultLoadedFlag );
2031  if ( defaultLoadedFlag )
2032  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( myOutputFileName ).absolutePath() );
2033  else
2034  QMessageBox::information( this, tr( "Save Metadata" ), message );
2035 }
2036 
2037 void QgsRasterLayerProperties::saveDefaultMetadata()
2038 {
2039  mMetadataWidget->acceptMetadata();
2040 
2041  bool defaultSavedFlag = false;
2042  QString errorMsg = mRasterLayer->saveDefaultMetadata( defaultSavedFlag );
2043  if ( !defaultSavedFlag )
2044  {
2045  QMessageBox::warning( this, tr( "Default Metadata" ), errorMsg );
2046  }
2047 }
2048 
2049 void QgsRasterLayerProperties::loadDefaultMetadata()
2050 {
2051  bool defaultLoadedFlag = false;
2052  QString myMessage = mRasterLayer->loadNamedMetadata( mRasterLayer->metadataUri(), defaultLoadedFlag );
2053  //reset if the default metadata was loaded OK only
2054  if ( defaultLoadedFlag )
2055  {
2056  mMetadataWidget->setMetadata( &mRasterLayer->metadata() );
2057  }
2058  else
2059  {
2060  QMessageBox::information( this, tr( "Default Metadata" ), myMessage );
2061  }
2062 }
2063 
2064 
2065 void QgsRasterLayerProperties::toggleBuildPyramidsButton()
2066 {
2067  if ( lbxPyramidResolutions->selectedItems().empty() )
2068  {
2069  buttonBuildPyramids->setEnabled( false );
2070  }
2071  else
2072  {
2073  buttonBuildPyramids->setEnabled( true );
2074  }
2075 }
2076 
2077 void QgsRasterLayerProperties::mResetColorRenderingBtn_clicked()
2078 {
2079  mBlendModeComboBox->setBlendMode( QPainter::CompositionMode_SourceOver );
2080  mSliderBrightness->setValue( 0 );
2081  mSliderContrast->setValue( 0 );
2082  mGammaSpinBox->setValue( 1.0 );
2083  sliderSaturation->setValue( 0 );
2084  comboGrayscale->setCurrentIndex( ( int ) QgsHueSaturationFilter::GrayscaleOff );
2085  mColorizeCheck->setChecked( false );
2086  sliderColorizeStrength->setValue( 100 );
2087 }
2088 
2089 bool QgsRasterLayerProperties::rasterIsMultiBandColor()
2090 {
2091  return mRasterLayer && nullptr != dynamic_cast<QgsMultiBandColorRenderer *>( mRasterLayer->renderer() );
2092 }
2093 
2094 void QgsRasterLayerProperties::updateInformationContent()
2095 {
2096  const QString myStyle = QgsApplication::reportStyleSheet( QgsApplication::StyleSheetType::WebBrowser );
2097  // Inject the stylesheet
2098  const QString html { mRasterLayer->htmlMetadata().replace( QLatin1String( "<head>" ), QStringLiteral( R"raw(<head><style type="text/css">%1</style>)raw" ) ).arg( myStyle ) };
2099  mMetadataViewer->setHtml( html );
2100  mMetadataFilled = true;
2101 }
2102 
2103 void QgsRasterLayerProperties::onCancel()
2104 {
2105  if ( mOldStyle.xmlData() != mRasterLayer->styleManager()->style( mRasterLayer->styleManager()->currentStyle() ).xmlData() )
2106  {
2107  // need to reset style to previous - style applied directly to the layer (not in apply())
2108  QString myMessage;
2109  QDomDocument doc( QStringLiteral( "qgis" ) );
2110  int errorLine, errorColumn;
2111  doc.setContent( mOldStyle.xmlData(), false, &myMessage, &errorLine, &errorColumn );
2112  mRasterLayer->importNamedStyle( doc, myMessage );
2113  syncToLayer();
2114  }
2115 }
2116 
2117 void QgsRasterLayerProperties::showHelp()
2118 {
2119  const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
2120 
2121  if ( helpPage.isValid() )
2122  {
2123  QgsHelp::openHelp( helpPage.toString() );
2124  }
2125  else
2126  {
2127  QgsHelp::openHelp( QStringLiteral( "working_with_raster/raster_properties.html" ) );
2128  }
2129 }
2130 
2131 void QgsRasterLayerProperties::updateGammaSpinBox( int value )
2132 {
2133  whileBlocking( mGammaSpinBox )->setValue( value / 100.0 );
2134 }
2135 
2136 void QgsRasterLayerProperties::updateGammaSlider( double value )
2137 {
2138  whileBlocking( mSliderGamma )->setValue( value * 100 );
2139 }
@ Float32
Thirty two bit floating point (float)
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Float64
Sixty four bit floating point (double)
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, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
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.
virtual QString name() const =0
Returns a provider name.
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.
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 ParentPage parentPage() const
Returns the associated parent page, for factories which create sub-components of a standard page.
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.
@ Temporal
Factory creates sub-components of the temporal properties page (only supported for raster layer tempo...
@ NoParent
Factory creates pages itself, not sub-components.
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:70
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:265
QString name
Definition: qgsmaplayer.h:73
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:1053
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:295
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:1038
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:76
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:377
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:386
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:75
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:303
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:357
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:330
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:311
void setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:368
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:348
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:287
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:339
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:451
void setMetadataUrlFormat(const QString &metaUrlFormat)
Sets the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:442
static QString extensionPropertyType(PropertyType type)
Returns the extension of a Property.
Definition: qgsmaplayer.cpp:67
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:415
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:78
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:395
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
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:1043
void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
Definition: qgsmaplayer.h:1048
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:406
void setMetadataUrlType(const QString &metaUrlType)
Set the metadata type of the layer used by QGIS Server in GetCapabilities request MetadataUrlType ind...
Definition: qgsmaplayer.h:424
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:74
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:433
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:319
void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:279
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:59
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:518
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
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)
Base class for raster data providers.
virtual QString buildPyramids(const QList< QgsRasterPyramid > &pyramidList, const QString &resamplingMethod="NEAREST", QgsRaster::RasterPyramidsFormat format=QgsRaster::PyramidsGTiff, const QStringList &configOptions=QStringList(), QgsRasterBlockFeedback *feedback=nullptr)
Creates pyramid overviews.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
virtual bool useSourceNoDataValue(int bandNo) const
Returns the source nodata value usage.
virtual QList< QgsRasterPyramid > buildPyramidList(const QList< int > &overviewList=QList< int >())
Returns the raster layers pyramid list.
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.
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(const 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.
void addWidget(QgsMapLayerConfigWidget *widget SIP_TRANSFER)
Adds a child widget to the properties widget.
Represents a raster layer.
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
QgsHueSaturationFilter * hueSaturationFilter() const
Returns the raster's hue/saturation filter.
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.
This struct is used to store pyramid info for the raster layer.
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:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Creates new raster renderer widget.
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:537
#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