QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsrastertransparencywidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrastertransparencywidget.cpp
3  ---------------------
4  begin : May 2016
5  copyright : (C) 2016 by Nathan Woodrow
6  email : woodrow dot nathan at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 #include <QWidget>
16 #include <QIntValidator>
17 #include <QFile>
18 #include <QTextStream>
19 #include <QMessageBox>
20 #include <QFileDialog>
21 
22 #include "qgssettings.h"
24 #include "qgsrasterlayer.h"
25 #include "qgsraster.h"
26 #include "qgsrasterlayerrenderer.h"
27 #include "qgsrasterdataprovider.h"
28 #include "qgsrastertransparency.h"
29 #include "qgsmaptoolemitpoint.h"
30 #include "qgsmapsettings.h"
31 #include "qgsrectangle.h"
32 #include "qgsmapcanvas.h"
35 #include "qgsdoublevalidator.h"
36 
37 
39  : QgsMapLayerConfigWidget( layer, canvas, parent )
40  , TRSTRING_NOT_SET( tr( "Not Set" ) )
41  , mRasterLayer( layer )
42  , mMapCanvas( canvas )
43 {
44  setupUi( this );
45  connect( pbnAddValuesFromDisplay, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnAddValuesFromDisplay_clicked );
46  connect( pbnAddValuesManually, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnAddValuesManually_clicked );
47  connect( pbnDefaultValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnDefaultValues_clicked );
48  connect( pbnExportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnExportTransparentPixelValues_clicked );
49  connect( pbnImportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnImportTransparentPixelValues_clicked );
50  connect( pbnRemoveSelectedRow, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnRemoveSelectedRow_clicked );
51 
52  mNodataColorButton->setShowNoColor( true );
53  mNodataColorButton->setColorDialogTitle( tr( "Select No Data Color" ) );
54  syncToLayer();
55 
56  connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsPanelWidget::widgetChanged );
57  connect( cboxTransparencyBand, &QgsRasterBandComboBox::bandChanged, this, &QgsPanelWidget::widgetChanged );
58  connect( mSrcNoDataValueCheckBox, &QCheckBox::stateChanged, this, &QgsPanelWidget::widgetChanged );
59  connect( leNoDataValue, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
60  connect( mNodataColorButton, &QgsColorButton::colorChanged, this, &QgsPanelWidget::widgetChanged );
61 
62  mPixelSelectorTool = nullptr;
63  if ( mMapCanvas )
64  {
65  mPixelSelectorTool = new QgsMapToolEmitPoint( mMapCanvas );
66  connect( mPixelSelectorTool, &QgsMapToolEmitPoint::canvasClicked, this, &QgsRasterTransparencyWidget::pixelSelected );
67  }
68  else
69  {
70  pbnAddValuesFromDisplay->setEnabled( false );
71  }
72 }
73 
75 {
76  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
77  QgsRasterRenderer *renderer = mRasterLayer->renderer();
78  if ( provider )
79  {
80  if ( provider->dataType( 1 ) == Qgis::DataType::ARGB32
81  || provider->dataType( 1 ) == Qgis::DataType::ARGB32_Premultiplied )
82  {
83  gboxNoDataValue->setEnabled( false );
84  gboxCustomTransparency->setEnabled( false );
85  }
86 
87  cboxTransparencyBand->setShowNotSetOption( true, tr( "None" ) );
88  cboxTransparencyBand->setLayer( mRasterLayer );
89 
90  mOpacityWidget->setOpacity( renderer->opacity() );
91 
92  cboxTransparencyBand->setBand( renderer->alphaBand() );
93  }
94 
95  if ( mRasterLayer->dataProvider()->sourceHasNoDataValue( 1 ) )
96  {
97  lblSrcNoDataValue->setText( QgsRasterBlock::printValue( mRasterLayer->dataProvider()->sourceNoDataValue( 1 ) ) );
98  }
99  else
100  {
101  lblSrcNoDataValue->setText( tr( "not defined" ) );
102  }
103 
104  mSrcNoDataValueCheckBox->setChecked( mRasterLayer->dataProvider()->useSourceNoDataValue( 1 ) );
105 
106  bool enableSrcNoData = mRasterLayer->dataProvider()->sourceHasNoDataValue( 1 ) && !std::isnan( mRasterLayer->dataProvider()->sourceNoDataValue( 1 ) );
107 
108  mSrcNoDataValueCheckBox->setEnabled( enableSrcNoData );
109  lblSrcNoDataValue->setEnabled( enableSrcNoData );
110 
111  if ( renderer )
112  {
113  if ( renderer->nodataColor().isValid() )
114  mNodataColorButton->setColor( renderer->nodataColor() );
115  else
116  mNodataColorButton->setToNull();
117  }
118 
119  QgsRasterRangeList noDataRangeList = mRasterLayer->dataProvider()->userNoDataValues( 1 );
120  QgsDebugMsg( QStringLiteral( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ) );
121  if ( !noDataRangeList.isEmpty() )
122  {
123  double v = QgsRasterBlock::printValue( noDataRangeList.value( 0 ).min() ).toDouble();
124  leNoDataValue->setText( QLocale().toString( v ) );
125  }
126  else
127  {
128  leNoDataValue->setText( QString() );
129  }
130 
131  populateTransparencyTable( mRasterLayer->renderer() );
132 }
133 
134 void QgsRasterTransparencyWidget::transparencyCellTextEdited( const QString &text )
135 {
136  Q_UNUSED( text )
137  QgsDebugMsg( QStringLiteral( "text = %1" ).arg( text ) );
138  QgsRasterRenderer *renderer = mRasterLayer->renderer();
139  if ( !renderer )
140  {
141  return;
142  }
143  int nBands = renderer->usesBands().size();
144  if ( nBands == 1 )
145  {
146  QLineEdit *lineEdit = qobject_cast<QLineEdit *>( sender() );
147  if ( !lineEdit ) return;
148  int row = -1;
149  int column = -1;
150  for ( int r = 0; r < tableTransparency->rowCount(); r++ )
151  {
152  for ( int c = 0; c < tableTransparency->columnCount(); c++ )
153  {
154  if ( tableTransparency->cellWidget( r, c ) == sender() )
155  {
156  row = r;
157  column = c;
158  break;
159  }
160  }
161  if ( row != -1 ) break;
162  }
163  QgsDebugMsg( QStringLiteral( "row = %1 column =%2" ).arg( row ).arg( column ) );
164 
165  if ( column == 0 )
166  {
167  QLineEdit *toLineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, 1 ) );
168  if ( !toLineEdit ) return;
169  bool toChanged = mTransparencyToEdited.value( row );
170  QgsDebugMsg( QStringLiteral( "toChanged = %1" ).arg( toChanged ) );
171  if ( !toChanged )
172  {
173  toLineEdit->setText( lineEdit->text() );
174  }
175  }
176  else if ( column == 1 )
177  {
178  setTransparencyToEdited( row );
179  }
180  }
181  emit widgetChanged();
182 }
183 
184 void QgsRasterTransparencyWidget::pbnAddValuesFromDisplay_clicked()
185 {
186  if ( mMapCanvas && mPixelSelectorTool )
187  {
188  mMapCanvas->setMapTool( mPixelSelectorTool );
189  }
190 }
191 
192 void QgsRasterTransparencyWidget::pbnAddValuesManually_clicked()
193 {
194  QgsRasterRenderer *renderer = mRasterLayer->renderer();
195  if ( !renderer )
196  {
197  return;
198  }
199 
200  tableTransparency->insertRow( tableTransparency->rowCount() );
201 
202  int n = renderer->usesBands().size();
203  if ( n == 1 ) n++;
204 
205  for ( int i = 0; i < n; i++ )
206  {
207  setTransparencyCell( tableTransparency->rowCount() - 1, i, std::numeric_limits<double>::quiet_NaN() );
208  }
209 
210  setTransparencyCell( tableTransparency->rowCount() - 1, n, 100 );
211 
212  tableTransparency->resizeColumnsToContents();
213  tableTransparency->resizeRowsToContents();
214 }
215 
216 void QgsRasterTransparencyWidget::pbnDefaultValues_clicked()
217 {
218  QgsRasterRenderer *r = mRasterLayer->renderer();
219  if ( !r )
220  {
221  return;
222  }
223 
224  int nBands = r->usesBands().size();
225 
226  setupTransparencyTable( nBands );
227 
228  tableTransparency->resizeColumnsToContents(); // works only with values
229  tableTransparency->resizeRowsToContents();
230 
231 }
232 
233 void QgsRasterTransparencyWidget::pbnExportTransparentPixelValues_clicked()
234 {
235  QgsSettings myQSettings;
236  QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
237  QString myFileName = QFileDialog::getSaveFileName( this, tr( "Save Pixel Values as File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
238  if ( !myFileName.isEmpty() )
239  {
240  if ( !myFileName.endsWith( QLatin1String( ".txt" ), Qt::CaseInsensitive ) )
241  {
242  myFileName = myFileName + ".txt";
243  }
244 
245  QFile myOutputFile( myFileName );
246  if ( myOutputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
247  {
248  QTextStream myOutputStream( &myOutputFile );
249  myOutputStream << "# " << tr( "QGIS Generated Transparent Pixel Value Export File" ) << '\n';
250  if ( rasterIsMultiBandColor() )
251  {
252  myOutputStream << "#\n#\n# " << tr( "Red" ) << "\t" << tr( "Green" ) << "\t" << tr( "Blue" ) << "\t" << tr( "Percent Transparent" );
253  for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
254  {
255  myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
256  << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
257  << QString::number( transparencyCellValue( myTableRunner, 2 ) ) << "\t"
258  << QString::number( transparencyCellValue( myTableRunner, 3 ) );
259  }
260  }
261  else
262  {
263  myOutputStream << "#\n#\n# " << tr( "Value" ) << "\t" << tr( "Percent Transparent" );
264 
265  for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
266  {
267  myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
268  << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
269  << QString::number( transparencyCellValue( myTableRunner, 2 ) );
270  }
271  }
272  }
273  else
274  {
275  QMessageBox::warning( this, tr( "Save Pixel Values as File" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
276  }
277  }
278 }
279 
280 void QgsRasterTransparencyWidget::pbnImportTransparentPixelValues_clicked()
281 {
282  int myLineCounter = 0;
283  bool myImportError = false;
284  QString myBadLines;
285  QgsSettings myQSettings;
286  QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
287  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load Pixel Values from File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
288  QFile myInputFile( myFileName );
289  if ( myInputFile.open( QFile::ReadOnly ) )
290  {
291  QTextStream myInputStream( &myInputFile );
292  QString myInputLine;
293  if ( rasterIsMultiBandColor() )
294  {
295  for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
296  {
297  tableTransparency->removeRow( myTableRunner );
298  }
299 
300  while ( !myInputStream.atEnd() )
301  {
302  myLineCounter++;
303  myInputLine = myInputStream.readLine();
304  if ( !myInputLine.isEmpty() )
305  {
306  if ( !myInputLine.simplified().startsWith( '#' ) )
307  {
308 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
309  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
310 #else
311  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), Qt::SkipEmptyParts );
312 #endif
313  if ( myTokens.count() != 4 )
314  {
315  myImportError = true;
316  myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
317  }
318  else
319  {
320  tableTransparency->insertRow( tableTransparency->rowCount() );
321  for ( int col = 0; col < 4; col++ )
322  {
323  setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
324  }
325  }
326  }
327  }
328  }
329  }
330  else
331  {
332  for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
333  {
334  tableTransparency->removeRow( myTableRunner );
335  }
336 
337  while ( !myInputStream.atEnd() )
338  {
339  myLineCounter++;
340  myInputLine = myInputStream.readLine();
341  if ( !myInputLine.isEmpty() )
342  {
343  if ( !myInputLine.simplified().startsWith( '#' ) )
344  {
345 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
346  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
347 #else
348  QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), Qt::SkipEmptyParts );
349 #endif
350  if ( myTokens.count() != 3 && myTokens.count() != 2 ) // 2 for QGIS < 1.9 compatibility
351  {
352  myImportError = true;
353  myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
354  }
355  else
356  {
357  if ( myTokens.count() == 2 )
358  {
359  myTokens.insert( 1, myTokens[0] ); // add 'to' value, QGIS < 1.9 compatibility
360  }
361  tableTransparency->insertRow( tableTransparency->rowCount() );
362  for ( int col = 0; col < 3; col++ )
363  {
364  setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
365  }
366  }
367  }
368  }
369  }
370  }
371 
372  if ( myImportError )
373  {
374  QMessageBox::warning( this, tr( "Load Pixel Values from File" ), tr( "The following lines contained errors\n\n%1" ).arg( myBadLines ) );
375  }
376  }
377  else if ( !myFileName.isEmpty() )
378  {
379  QMessageBox::warning( this, tr( "Load Pixel Values from File" ), tr( "Read access denied. Adjust the file permissions and try again.\n\n" ) );
380  }
381  tableTransparency->resizeColumnsToContents();
382  tableTransparency->resizeRowsToContents();
383  emit widgetChanged();
384 }
385 
386 void QgsRasterTransparencyWidget::pbnRemoveSelectedRow_clicked()
387 {
388  if ( 0 < tableTransparency->rowCount() )
389  {
390  tableTransparency->removeRow( tableTransparency->currentRow() );
391  }
392  emit widgetChanged();
393 }
394 
395 bool QgsRasterTransparencyWidget::rasterIsMultiBandColor()
396 {
397  return mRasterLayer && nullptr != dynamic_cast<QgsMultiBandColorRenderer *>( mRasterLayer->renderer() );
398 }
399 
401 {
402  //set NoDataValue
403  QgsRasterRangeList myNoDataRangeList;
404  if ( "" != leNoDataValue->text() )
405  {
406  bool myDoubleOk = false;
407  double myNoDataValue = QgsDoubleValidator::toDouble( leNoDataValue->text(), &myDoubleOk );
408  if ( myDoubleOk )
409  {
410  QgsRasterRange myNoDataRange( myNoDataValue, myNoDataValue );
411  myNoDataRangeList << myNoDataRange;
412  }
413  }
414  for ( int bandNo = 1; bandNo <= mRasterLayer->dataProvider()->bandCount(); bandNo++ )
415  {
416  mRasterLayer->dataProvider()->setUserNoDataValue( bandNo, myNoDataRangeList );
417  mRasterLayer->dataProvider()->setUseSourceNoDataValue( bandNo, mSrcNoDataValueCheckBox->isChecked() );
418  }
419 
420  //transparency settings
421  QgsRasterRenderer *rasterRenderer = mRasterLayer->renderer();
422  if ( rasterRenderer )
423  {
424  rasterRenderer->setAlphaBand( cboxTransparencyBand->currentBand() );
425  rasterRenderer->setNodataColor( mNodataColorButton->color() );
426 
427  //Walk through each row in table and test value. If not valid set to 0.0 and continue building transparency list
428  QgsRasterTransparency *rasterTransparency = new QgsRasterTransparency();
429  if ( tableTransparency->columnCount() == 4 )
430  {
432  QList<QgsRasterTransparency::TransparentThreeValuePixel> myTransparentThreeValuePixelList;
433  myTransparentThreeValuePixelList.reserve( tableTransparency->rowCount() );
434  for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
435  {
436  myTransparentPixel.red = transparencyCellValue( myListRunner, 0 );
437  myTransparentPixel.green = transparencyCellValue( myListRunner, 1 );
438  myTransparentPixel.blue = transparencyCellValue( myListRunner, 2 );
439  myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 3 );
440  myTransparentThreeValuePixelList.append( myTransparentPixel );
441  }
442  rasterTransparency->setTransparentThreeValuePixelList( myTransparentThreeValuePixelList );
443  }
444  else if ( tableTransparency->columnCount() == 3 )
445  {
447  QList<QgsRasterTransparency::TransparentSingleValuePixel> myTransparentSingleValuePixelList;
448  myTransparentSingleValuePixelList.reserve( tableTransparency->rowCount() );
449  for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
450  {
451  myTransparentPixel.min = transparencyCellValue( myListRunner, 0 );
452  myTransparentPixel.max = transparencyCellValue( myListRunner, 1 );
453  myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 2 );
454 
455  myTransparentSingleValuePixelList.append( myTransparentPixel );
456  }
457  rasterTransparency->setTransparentSingleValuePixelList( myTransparentSingleValuePixelList );
458  }
459 
460  rasterRenderer->setRasterTransparency( rasterTransparency );
461 
462  //set global transparency
463  rasterRenderer->setOpacity( mOpacityWidget->opacity() );
464  }
465 }
466 
467 void QgsRasterTransparencyWidget::pixelSelected( const QgsPointXY &canvasPoint )
468 {
469  QgsRasterRenderer *renderer = mRasterLayer->renderer();
470  if ( !renderer )
471  {
472  return;
473  }
474 
475  //Get the pixel values and add a new entry to the transparency table
476  if ( mMapCanvas && mPixelSelectorTool )
477  {
478  mMapCanvas->unsetMapTool( mPixelSelectorTool );
479 
480  const QgsMapSettings &ms = mMapCanvas->mapSettings();
481  QgsPointXY myPoint = ms.mapToLayerCoordinates( mRasterLayer, canvasPoint );
482 
483  QgsRectangle myExtent = ms.mapToLayerCoordinates( mRasterLayer, mMapCanvas->extent() );
484  double mapUnitsPerPixel = mMapCanvas->mapUnitsPerPixel();
485  int myWidth = mMapCanvas->extent().width() / mapUnitsPerPixel;
486  int myHeight = mMapCanvas->extent().height() / mapUnitsPerPixel;
487 
488  QMap<int, QVariant> myPixelMap = mRasterLayer->dataProvider()->identify( myPoint, QgsRaster::IdentifyFormatValue, myExtent, myWidth, myHeight ).results();
489 
490  QList<int> bands = renderer->usesBands();
491 
492  QList<double> values;
493  for ( int i = 0; i < bands.size(); ++i )
494  {
495  int bandNo = bands.value( i );
496  if ( myPixelMap.count( bandNo ) == 1 )
497  {
498  if ( myPixelMap.value( bandNo ).isNull() )
499  {
500  return; // Don't add nodata, transparent anyway
501  }
502  double value = myPixelMap.value( bandNo ).toDouble();
503  QgsDebugMsg( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ) );
504  values.append( value );
505  }
506  }
507  if ( bands.size() == 1 )
508  {
509  // Set 'to'
510  values.insert( 1, values.value( 0 ) );
511  }
512  tableTransparency->insertRow( tableTransparency->rowCount() );
513  for ( int i = 0; i < values.size(); i++ )
514  {
515  setTransparencyCell( tableTransparency->rowCount() - 1, i, values.value( i ) );
516  }
517  setTransparencyCell( tableTransparency->rowCount() - 1, tableTransparency->columnCount() - 1, 100 );
518  }
519 
520  tableTransparency->resizeColumnsToContents();
521  tableTransparency->resizeRowsToContents();
522 }
523 
524 void QgsRasterTransparencyWidget::populateTransparencyTable( QgsRasterRenderer *renderer )
525 {
526  if ( !mRasterLayer )
527  {
528  return;
529  }
530 
531  if ( !renderer )
532  {
533  return;
534  }
535 
536  int nBands = renderer->usesBands().size();
537  setupTransparencyTable( nBands );
538 
539  const QgsRasterTransparency *rasterTransparency = renderer->rasterTransparency();
540  if ( !rasterTransparency )
541  {
542  return;
543  }
544 
545  if ( nBands == 1 )
546  {
547  QList<QgsRasterTransparency::TransparentSingleValuePixel> pixelList = rasterTransparency->transparentSingleValuePixelList();
548  for ( int i = 0; i < pixelList.size(); ++i )
549  {
550  tableTransparency->insertRow( i );
551  setTransparencyCell( i, 0, pixelList[i].min );
552  setTransparencyCell( i, 1, pixelList[i].max );
553  setTransparencyCell( i, 2, pixelList[i].percentTransparent );
554  // break synchronization only if values differ
555  if ( pixelList[i].min != pixelList[i].max )
556  {
557  setTransparencyToEdited( i );
558  }
559  }
560  }
561  else if ( nBands == 3 )
562  {
563  QList<QgsRasterTransparency::TransparentThreeValuePixel> pixelList = rasterTransparency->transparentThreeValuePixelList();
564  for ( int i = 0; i < pixelList.size(); ++i )
565  {
566  tableTransparency->insertRow( i );
567  setTransparencyCell( i, 0, pixelList[i].red );
568  setTransparencyCell( i, 1, pixelList[i].green );
569  setTransparencyCell( i, 2, pixelList[i].blue );
570  setTransparencyCell( i, 3, pixelList[i].percentTransparent );
571  }
572  }
573 
574  tableTransparency->resizeColumnsToContents();
575  tableTransparency->resizeRowsToContents();
576 
577 }
578 
579 void QgsRasterTransparencyWidget::setupTransparencyTable( int nBands )
580 {
581  tableTransparency->clear();
582  tableTransparency->setColumnCount( 0 );
583  tableTransparency->setRowCount( 0 );
584  mTransparencyToEdited.clear();
585 
586  if ( nBands == 3 )
587  {
588  tableTransparency->setColumnCount( 4 );
589  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Red" ) ) );
590  tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Green" ) ) );
591  tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Blue" ) ) );
592  tableTransparency->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
593  }
594  else //1 band
595  {
596  tableTransparency->setColumnCount( 3 );
597 // Is it important to distinguish the header? It becomes difficult with range.
598 #if 0
599  if ( QgsRasterLayer::PalettedColor != mRasterLayer->drawingStyle() &&
600  QgsRasterLayer::PalettedSingleBandGray != mRasterLayer->drawingStyle() &&
601  QgsRasterLayer::PalettedSingleBandPseudoColor != mRasterLayer->drawingStyle() &&
602  QgsRasterLayer::PalettedMultiBandColor != mRasterLayer->drawingStyle() )
603  {
604  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Gray" ) ) );
605  }
606  else
607  {
608  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Indexed Value" ) ) );
609  }
610 #endif
611  tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "From" ) ) );
612  tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "To" ) ) );
613  tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
614  }
615 }
616 
617 void QgsRasterTransparencyWidget::setTransparencyCell( int row, int column, double value )
618 {
619  QgsDebugMsg( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ) );
620  QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
621  if ( !provider ) return;
622 
623  QgsRasterRenderer *renderer = mRasterLayer->renderer();
624  if ( !renderer ) return;
625  int nBands = renderer->usesBands().size();
626 
627  QLineEdit *lineEdit = new QLineEdit();
628  lineEdit->setFrame( false ); // frame looks bad in table
629  // Without margins row selection is not displayed (important for delete row)
630  lineEdit->setContentsMargins( 1, 1, 1, 1 );
631 
632  if ( column == tableTransparency->columnCount() - 1 )
633  {
634  // transparency
635  // Who needs transparency as floating point?
636  lineEdit->setValidator( new QIntValidator( nullptr ) );
637  lineEdit->setText( QString::number( static_cast<int>( value ) ) );
638  }
639  else
640  {
641  // value
642  QString valueString;
643  switch ( provider->sourceDataType( 1 ) )
644  {
647  lineEdit->setValidator( new QgsDoubleValidator( nullptr ) );
648  if ( !std::isnan( value ) )
649  {
650  double v = QgsRasterBlock::printValue( value ).toDouble();
651  valueString = QLocale().toString( v );
652  }
653  break;
654  default:
655  lineEdit->setValidator( new QIntValidator( nullptr ) );
656  if ( !std::isnan( value ) )
657  {
658  valueString = QString::number( static_cast<int>( value ) );
659  }
660  break;
661  }
662  lineEdit->setText( valueString );
663  connect( lineEdit, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
664  }
665  tableTransparency->setCellWidget( row, column, lineEdit );
666  adjustTransparencyCellWidth( row, column );
667 
668  if ( nBands == 1 && ( column == 0 || column == 1 ) )
669  {
670  connect( lineEdit, &QLineEdit::textEdited, this, &QgsRasterTransparencyWidget::transparencyCellTextEdited );
671  }
672  tableTransparency->resizeColumnsToContents();
673  emit widgetChanged();
674 }
675 
676 void QgsRasterTransparencyWidget::adjustTransparencyCellWidth( int row, int column )
677 {
678  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
679  if ( !lineEdit ) return;
680 
681  int width = std::max( lineEdit->fontMetrics().boundingRect( lineEdit->text() ).width() + 10, 100 );
682  width = std::max( width, tableTransparency->columnWidth( column ) );
683 
684  lineEdit->setFixedWidth( width );
685 }
686 
687 void QgsRasterTransparencyWidget::setTransparencyToEdited( int row )
688 {
689  if ( row >= mTransparencyToEdited.size() )
690  {
691  mTransparencyToEdited.resize( row + 1 );
692  }
693  mTransparencyToEdited[row] = true;
694 }
695 
696 double QgsRasterTransparencyWidget::transparencyCellValue( int row, int column )
697 {
698  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
699  if ( !lineEdit || lineEdit->text().isEmpty() )
700  {
701  return std::numeric_limits<double>::quiet_NaN();
702  }
703  return QgsDoubleValidator::toDouble( lineEdit->text() );
704 
705 }
@ 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)
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
QgsDoubleValidator is a QLineEdit Validator that combines QDoubleValidator and QRegularExpressionVali...
static double toDouble(const QString &input, bool *ok)
Converts input string to double value.
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.
A panel widget that can be shown in the map style dock.
The QgsMapSettings class contains configuration for rendering of the map.
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
A map tool that simply emits a point when clicking on the map.
void canvasClicked(const QgsPointXY &point, Qt::MouseButton button)
signal emitted on canvas click
Renderer for multiband images with the color components.
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
void widgetChanged()
Emitted when the widget state changes.
A class to represent a 2D point.
Definition: qgspointxy.h:59
void bandChanged(int band)
Emitted when the currently selected band changes.
static QString printValue(double value)
Print double value with all necessary significant digits.
Base class for raster data providers.
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.
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.
virtual void setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)
QMap< int, QVariant > results() const
Returns the identify results.
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
Raster values range container.
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
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.
void syncToLayer()
Sync the widget state to the layer set for the widget.
QgsRasterTransparencyWidget(QgsRasterLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
Widget to control a layers transparency and related options.
void apply() override
Apply any changes on the widget to the set layer.
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
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
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
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList