1 /***************************************************************************
2                           qgsrastercalcdialog.h  -  description
3                           ---------------------
4     begin                : September 28th, 2010
5     copyright            : (C) 2010 by Marco Hugentobler
6     email                : marco dot hugentobler at sourcepole dot ch
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 "qgsgdalutils.h"
19 #include "qgsrastercalcdialog.h"
20 #include "qgsproject.h"
21 #include "qgsrastercalcnode.h"
22 #include "qgsrasterdataprovider.h"
23 #include "qgsrasterlayer.h"
24 #include "qgssettings.h"
25 #include "qgsgui.h"
26 
27 #include "cpl_string.h"
28 #include "gdal.h"
29 
30 #include <QFileDialog>
31 #include <QFontDatabase>
32 
QgsRasterCalcDialog(QgsRasterLayer * rasterLayer,QWidget * parent,Qt::WindowFlags f)33 QgsRasterCalcDialog::QgsRasterCalcDialog( QgsRasterLayer *rasterLayer, QWidget *parent, Qt::WindowFlags f ): QDialog( parent, f )
34 {
35   setupUi( this );
36   QgsGui::enableAutoGeometryRestore( this );
37 
38   mXMaxSpinBox->setShowClearButton( false );
39   mXMinSpinBox->setShowClearButton( false );
40   mYMaxSpinBox->setShowClearButton( false );
41   mYMinSpinBox->setShowClearButton( false );
42   mNColumnsSpinBox->setShowClearButton( false );
43   mNRowsSpinBox->setShowClearButton( false );
44 
45   connect( mRasterBandsListWidget, &QListWidget::itemDoubleClicked, this, &QgsRasterCalcDialog::mRasterBandsListWidget_itemDoubleClicked );
46   connect( mButtonBox, &QDialogButtonBox::accepted, this, &QgsRasterCalcDialog::mButtonBox_accepted );
47   connect( mCurrentLayerExtentButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mCurrentLayerExtentButton_clicked );
48   connect( mExpressionTextEdit, &QTextEdit::textChanged, this, &QgsRasterCalcDialog::mExpressionTextEdit_textChanged );
49   connect( mPlusPushButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mPlusPushButton_clicked );
50   connect( mMinusPushButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mMinusPushButton_clicked );
51   connect( mMultiplyPushButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mMultiplyPushButton_clicked );
52   connect( mDividePushButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mDividePushButton_clicked );
53   connect( mSqrtButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mSqrtButton_clicked );
54   connect( mCosButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mCosButton_clicked );
55   connect( mSinButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mSinButton_clicked );
56   connect( mASinButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mASinButton_clicked );
57   connect( mExpButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mExpButton_clicked );
58   connect( mLnButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mLnButton_clicked );
59   connect( mLogButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mLogButton_clicked );
60   connect( mNotEqualButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mNotEqualButton_clicked );
61   connect( mTanButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mTanButton_clicked );
62   connect( mACosButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mACosButton_clicked );
63   connect( mATanButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mATanButton_clicked );
64   connect( mOpenBracketPushButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mOpenBracketPushButton_clicked );
65   connect( mCloseBracketPushButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mCloseBracketPushButton_clicked );
66   connect( mLessButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mLessButton_clicked );
67   connect( mGreaterButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mGreaterButton_clicked );
68   connect( mEqualButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mEqualButton_clicked );
69   connect( mLesserEqualButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mLesserEqualButton_clicked );
70   connect( mGreaterEqualButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mGreaterEqualButton_clicked );
71   connect( mAndButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mAndButton_clicked );
72   connect( mAbsButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mAbsButton_clicked );
73   connect( mMinButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mMinButton_clicked );
74   connect( mMaxButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mMaxButton_clicked );
75   connect( mOrButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mOrButton_clicked );
76   connect( mConditionalStatButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mConditionalStatButton_clicked );
77   connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsRasterCalcDialog::showHelp );
78 
79   if ( rasterLayer && rasterLayer->dataProvider() && rasterLayer->providerType() == QLatin1String( "gdal" ) )
80   {
81     setExtentSize( rasterLayer->width(), rasterLayer->height(), rasterLayer->extent() );
82     mCrsSelector->setCrs( rasterLayer->crs() );
83   }
84   mCrsSelector->setShowAccuracyWarnings( true );
85 
86   mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
87 
88   //add supported output formats
89   insertAvailableOutputFormats();
90   insertAvailableRasterBands();
91 
92   mExpressionTextEdit->setCurrentFont( QFontDatabase::systemFont( QFontDatabase::FixedFont ) );
93 
94   QgsSettings settings;
95   mOutputLayer->setStorageMode( QgsFileWidget::SaveFile );
96   mOutputLayer->setDialogTitle( tr( "Enter Result File" ) );
97   mOutputLayer->setDefaultRoot( settings.value( QStringLiteral( "/RasterCalculator/lastOutputDir" ), QDir::homePath() ).toString() );
98   connect( mOutputLayer, &QgsFileWidget::fileChanged, this, [ = ]() { setAcceptButtonState(); } );
99 
100   connect( mUseVirtualProviderCheckBox, &QCheckBox::clicked, this, &QgsRasterCalcDialog::setOutputToVirtual );
101 
102   if ( ! useVirtualProvider() )
103   {
104     setOutputToVirtual();
105   }
106 
107 }
108 
formulaString() const109 QString QgsRasterCalcDialog::formulaString() const
110 {
111   return mExpressionTextEdit->toPlainText();
112 }
113 
outputFile() const114 QString QgsRasterCalcDialog::outputFile() const
115 {
116   QString outputFileName = mOutputLayer->filePath();
117   QFileInfo fileInfo( outputFileName );
118   QString suffix = fileInfo.suffix();
119   if ( !suffix.isEmpty() )
120   {
121     return outputFileName;
122   }
123 
124   //add the file format extension if the user did not specify it
125   int index = mOutputFormatComboBox->currentIndex();
126   if ( index == -1 )
127   {
128     return outputFileName;
129   }
130 
131   QString driverShortName = mOutputFormatComboBox->itemData( index ).toString();
132   QMap<QString, QString>::const_iterator it = mDriverExtensionMap.find( driverShortName );
133   if ( it == mDriverExtensionMap.constEnd() )
134   {
135     return outputFileName;
136   }
137 
138   return outputFileName + '.' + it.value();
139 }
140 
outputFormat() const141 QString QgsRasterCalcDialog::outputFormat() const
142 {
143   int index = mOutputFormatComboBox->currentIndex();
144   if ( index == -1 )
145   {
146     return QString();
147   }
148   return mOutputFormatComboBox->itemData( index ).toString();
149 }
150 
outputCrs() const151 QgsCoordinateReferenceSystem QgsRasterCalcDialog::outputCrs() const
152 {
153   return mCrsSelector->crs();
154 }
155 
addLayerToProject() const156 bool QgsRasterCalcDialog::addLayerToProject() const
157 {
158   return mAddResultToProjectCheckBox->isChecked();
159 }
160 
useVirtualProvider() const161 bool QgsRasterCalcDialog::useVirtualProvider() const
162 {
163   return mUseVirtualProviderCheckBox->isChecked();
164 }
165 
virtualLayerName() const166 QString QgsRasterCalcDialog::virtualLayerName() const
167 {
168   return mVirtualLayerName->text();
169 }
170 
rasterEntries() const171 QVector<QgsRasterCalculatorEntry> QgsRasterCalcDialog::rasterEntries() const
172 {
173   QVector<QgsRasterCalculatorEntry> entries;
174   QString expressionString = mExpressionTextEdit->toPlainText();
175 
176   QList<QgsRasterCalculatorEntry>::const_iterator bandIt = mAvailableRasterBands.constBegin();
177   for ( ; bandIt != mAvailableRasterBands.constEnd(); ++bandIt )
178   {
179     if ( expressionString.contains( bandIt->ref ) )
180     {
181       entries.push_back( *bandIt );
182     }
183   }
184 
185   return entries;
186 }
187 
188 
setExtentSize(int width,int height,QgsRectangle bbox)189 void QgsRasterCalcDialog::setExtentSize( int width, int height, QgsRectangle bbox )
190 {
191   mNColumnsSpinBox->setValue( width );
192   mNRowsSpinBox->setValue( height );
193   mXMinSpinBox->setValue( bbox.xMinimum() );
194   mXMaxSpinBox->setValue( bbox.xMaximum() );
195   mYMinSpinBox->setValue( bbox.yMinimum() );
196   mYMaxSpinBox->setValue( bbox.yMaximum() );
197   mExtentSizeSet = true;
198 }
199 
200 
insertAvailableRasterBands()201 void QgsRasterCalcDialog::insertAvailableRasterBands()
202 {
203   mAvailableRasterBands = QgsRasterCalculatorEntry::rasterEntries().toList();
204   mRasterBandsListWidget->clear();
205   for ( const auto &entry : std::as_const( mAvailableRasterBands ) )
206   {
207     QgsRasterLayer *rlayer = entry.raster;
208     if ( !mExtentSizeSet ) //set bounding box / resolution of output to the values of the first possible input layer
209     {
210       setExtentSize( rlayer->width(), rlayer->height(), rlayer->extent() );
211       mCrsSelector->setCrs( rlayer->crs() );
212     }
213     QListWidgetItem *item = new QListWidgetItem( entry.ref, mRasterBandsListWidget );
214     item->setData( Qt::ToolTipRole, rlayer->publicSource() );
215     mRasterBandsListWidget->addItem( item );
216   }
217 }
218 
insertAvailableOutputFormats()219 void QgsRasterCalcDialog::insertAvailableOutputFormats()
220 {
221   GDALAllRegister();
222 
223   int nDrivers = GDALGetDriverCount();
224   for ( int i = 0; i < nDrivers; ++i )
225   {
226     GDALDriverH driver = GDALGetDriver( i );
227     if ( driver )
228     {
229       if ( QgsGdalUtils::supportsRasterCreate( driver ) )
230       {
231         QString driverShortName = GDALGetDriverShortName( driver );
232         QString driverLongName = GDALGetDriverLongName( driver );
233         if ( driverShortName == QLatin1String( "MEM" ) )
234         {
235           // in memory rasters are not (yet) supported because the GDAL dataset handle
236           // would need to be passed directly to QgsRasterLayer (it is not possible to
237           // close it in raster calculator and reopen the dataset again in raster layer)
238           continue;
239         }
240 
241         mOutputFormatComboBox->addItem( driverLongName, driverShortName );
242 
243         //store the driver shortnames and the corresponding extensions
244         //(just in case the user does not give an extension for the output file name)
245         QString driverExtension = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSION, nullptr );
246         mDriverExtensionMap.insert( driverShortName, driverExtension );
247       }
248     }
249   }
250 
251   //and set last used driver in combo box
252   QgsSettings s;
253   QString lastUsedDriver = s.value( QStringLiteral( "/RasterCalculator/lastOutputFormat" ), "GeoTIFF" ).toString();
254   int lastDriverIndex = mOutputFormatComboBox->findText( lastUsedDriver );
255   if ( lastDriverIndex != -1 )
256   {
257     mOutputFormatComboBox->setCurrentIndex( lastDriverIndex );
258   }
259 }
260 
outputRectangle() const261 QgsRectangle QgsRasterCalcDialog::outputRectangle() const
262 {
263   return QgsRectangle( mXMinSpinBox->value(), mYMinSpinBox->value(), mXMaxSpinBox->value(), mYMaxSpinBox->value() );
264 }
265 
numberOfColumns() const266 int QgsRasterCalcDialog::numberOfColumns() const
267 {
268   return mNColumnsSpinBox->value();
269 }
270 
numberOfRows() const271 int QgsRasterCalcDialog::numberOfRows() const
272 {
273   return mNRowsSpinBox->value();
274 }
275 
276 //slots
277 
mButtonBox_accepted()278 void QgsRasterCalcDialog::mButtonBox_accepted()
279 {
280   //save last output format
281   QgsSettings s;
282   s.setValue( QStringLiteral( "/RasterCalculator/lastOutputFormat" ), QVariant( mOutputFormatComboBox->currentText() ) );
283   s.setValue( QStringLiteral( "/RasterCalculator/lastOutputDir" ), QVariant( QFileInfo( mOutputLayer->filePath() ).absolutePath() ) );
284 }
285 
showHelp()286 void QgsRasterCalcDialog::showHelp()
287 {
288   QgsHelp::openHelp( QStringLiteral( "working_with_raster/raster_analysis.html#raster-calculator" ) );
289 }
290 
mCurrentLayerExtentButton_clicked()291 void QgsRasterCalcDialog::mCurrentLayerExtentButton_clicked()
292 {
293   QListWidgetItem *currentLayerItem = mRasterBandsListWidget->currentItem();
294   if ( currentLayerItem )
295   {
296     QgsRasterLayer *rlayer = nullptr;
297     QList<QgsRasterCalculatorEntry>::const_iterator rasterIt = mAvailableRasterBands.constBegin();
298     for ( ; rasterIt != mAvailableRasterBands.constEnd(); ++rasterIt )
299     {
300       if ( rasterIt->ref == currentLayerItem->text() )
301       {
302         rlayer = rasterIt->raster;
303       }
304     }
305 
306     if ( !rlayer )
307     {
308       return;
309     }
310 
311     QgsRectangle layerExtent = rlayer->extent();
312     mXMinSpinBox->setValue( layerExtent.xMinimum() );
313     mXMaxSpinBox->setValue( layerExtent.xMaximum() );
314     mYMinSpinBox->setValue( layerExtent.yMinimum() );
315     mYMaxSpinBox->setValue( layerExtent.yMaximum() );
316     mNColumnsSpinBox->setValue( rlayer->width() );
317     mNRowsSpinBox->setValue( rlayer->height() );
318     mCrsSelector->setCrs( rlayer->crs() );
319   }
320 }
321 
mExpressionTextEdit_textChanged()322 void QgsRasterCalcDialog::mExpressionTextEdit_textChanged()
323 {
324   if ( expressionValid() )
325   {
326     mExpressionValidLabel->setText( tr( "Expression valid" ) );
327     if ( filePathValid() || useVirtualProvider() )
328     {
329       mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( true );
330       return;
331     }
332   }
333   else
334   {
335     mExpressionValidLabel->setText( tr( "Expression invalid" ) );
336   }
337   mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
338 }
339 
setAcceptButtonState()340 void QgsRasterCalcDialog::setAcceptButtonState()
341 {
342   if ( ( expressionValid() && filePathValid() ) || ( expressionValid() && useVirtualProvider() ) )
343   {
344     mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( true );
345   }
346   else
347   {
348     mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
349   }
350 }
351 
setOutputToVirtual()352 void QgsRasterCalcDialog::setOutputToVirtual()
353 {
354   if ( useVirtualProvider() )
355   {
356     mOutputFormatComboBox->hide();
357     mOutputLayer->hide();
358     mOutputLayerLabel->hide();
359     mOutputFormatLabel->hide();
360     mAddResultToProjectCheckBox->isChecked();
361     mAddResultToProjectCheckBox->setEnabled( false );
362     mVirtualLayerLabel->show();
363     mVirtualLayerName->show();
364     setAcceptButtonState();
365   }
366   else
367   {
368     mOutputFormatComboBox->show();
369     mOutputLayer->show();
370     mOutputLayerLabel->show();
371     mOutputFormatLabel->show();
372     mAddResultToProjectCheckBox->setEnabled( true );
373     mVirtualLayerLabel->hide();
374     mVirtualLayerName->hide();
375     setAcceptButtonState();
376   }
377 }
378 
expressionValid() const379 bool QgsRasterCalcDialog::expressionValid() const
380 {
381   QString errorString;
382   QgsRasterCalcNode *testNode = QgsRasterCalcNode::parseRasterCalcString( mExpressionTextEdit->toPlainText(), errorString );
383   if ( testNode )
384   {
385     delete testNode;
386     return true;
387   }
388   return false;
389 }
390 
filePathValid() const391 bool QgsRasterCalcDialog::filePathValid() const
392 {
393   QString outputPath = mOutputLayer->filePath();
394   if ( outputPath.isEmpty() )
395     return false;
396 
397   outputPath = QFileInfo( outputPath ).absolutePath();
398   return QFileInfo( outputPath ).isWritable();
399 }
400 
mRasterBandsListWidget_itemDoubleClicked(QListWidgetItem * item)401 void QgsRasterCalcDialog::mRasterBandsListWidget_itemDoubleClicked( QListWidgetItem *item )
402 {
403   mExpressionTextEdit->insertPlainText( quoteBandEntry( item->text() ) );
404   //to enable the "ok" button if someone checks the virtual provider checkbox before adding a valid expression,
405   if ( expressionValid() && useVirtualProvider() ) setAcceptButtonState();
406 }
407 
mPlusPushButton_clicked()408 void QgsRasterCalcDialog::mPlusPushButton_clicked()
409 {
410   mExpressionTextEdit->insertPlainText( QStringLiteral( " + " ) );
411 }
412 
mMinusPushButton_clicked()413 void QgsRasterCalcDialog::mMinusPushButton_clicked()
414 {
415   mExpressionTextEdit->insertPlainText( QStringLiteral( " - " ) );
416 }
417 
mMultiplyPushButton_clicked()418 void QgsRasterCalcDialog::mMultiplyPushButton_clicked()
419 {
420   mExpressionTextEdit->insertPlainText( QStringLiteral( " * " ) );
421 }
422 
mDividePushButton_clicked()423 void QgsRasterCalcDialog::mDividePushButton_clicked()
424 {
425   mExpressionTextEdit->insertPlainText( QStringLiteral( " / " ) );
426 }
427 
mSqrtButton_clicked()428 void QgsRasterCalcDialog::mSqrtButton_clicked()
429 {
430   mExpressionTextEdit->insertPlainText( QStringLiteral( " sqrt ( " ) );
431 }
432 
mCosButton_clicked()433 void QgsRasterCalcDialog::mCosButton_clicked()
434 {
435   mExpressionTextEdit->insertPlainText( QStringLiteral( " cos ( " ) );
436 }
437 
mSinButton_clicked()438 void QgsRasterCalcDialog::mSinButton_clicked()
439 {
440   mExpressionTextEdit->insertPlainText( QStringLiteral( " sin ( " ) );
441 }
442 
mASinButton_clicked()443 void QgsRasterCalcDialog::mASinButton_clicked()
444 {
445   mExpressionTextEdit->insertPlainText( QStringLiteral( " asin ( " ) );
446 }
447 
mExpButton_clicked()448 void QgsRasterCalcDialog::mExpButton_clicked()
449 {
450   mExpressionTextEdit->insertPlainText( QStringLiteral( " ^ " ) );
451 }
452 
mTanButton_clicked()453 void QgsRasterCalcDialog::mTanButton_clicked()
454 {
455   mExpressionTextEdit->insertPlainText( QStringLiteral( " tan ( " ) );
456 }
457 
mACosButton_clicked()458 void QgsRasterCalcDialog::mACosButton_clicked()
459 {
460   mExpressionTextEdit->insertPlainText( QStringLiteral( " acos ( " ) );
461 }
462 
mATanButton_clicked()463 void QgsRasterCalcDialog::mATanButton_clicked()
464 {
465   mExpressionTextEdit->insertPlainText( QStringLiteral( " atan ( " ) );
466 }
467 
mLnButton_clicked()468 void QgsRasterCalcDialog::mLnButton_clicked()
469 {
470   mExpressionTextEdit->insertPlainText( QStringLiteral( " ln ( " ) );
471 }
472 
mLogButton_clicked()473 void QgsRasterCalcDialog::mLogButton_clicked()
474 {
475   mExpressionTextEdit->insertPlainText( QStringLiteral( " log10 ( " ) );
476 }
477 
mNotEqualButton_clicked()478 void QgsRasterCalcDialog::mNotEqualButton_clicked()
479 {
480   mExpressionTextEdit->insertPlainText( QStringLiteral( " != " ) );
481 }
482 
mOpenBracketPushButton_clicked()483 void QgsRasterCalcDialog::mOpenBracketPushButton_clicked()
484 {
485   mExpressionTextEdit->insertPlainText( QStringLiteral( " ( " ) );
486 }
487 
mCloseBracketPushButton_clicked()488 void QgsRasterCalcDialog::mCloseBracketPushButton_clicked()
489 {
490   mExpressionTextEdit->insertPlainText( QStringLiteral( " ) " ) );
491 }
492 
mLessButton_clicked()493 void QgsRasterCalcDialog::mLessButton_clicked()
494 {
495   mExpressionTextEdit->insertPlainText( QStringLiteral( " < " ) );
496 }
497 
mGreaterButton_clicked()498 void QgsRasterCalcDialog::mGreaterButton_clicked()
499 {
500   mExpressionTextEdit->insertPlainText( QStringLiteral( " > " ) );
501 }
502 
mEqualButton_clicked()503 void QgsRasterCalcDialog::mEqualButton_clicked()
504 {
505   mExpressionTextEdit->insertPlainText( QStringLiteral( " = " ) );
506 }
507 
mLesserEqualButton_clicked()508 void QgsRasterCalcDialog::mLesserEqualButton_clicked()
509 {
510   mExpressionTextEdit->insertPlainText( QStringLiteral( " <= " ) );
511 }
512 
mGreaterEqualButton_clicked()513 void QgsRasterCalcDialog::mGreaterEqualButton_clicked()
514 {
515   mExpressionTextEdit->insertPlainText( QStringLiteral( " >= " ) );
516 }
517 
mAndButton_clicked()518 void QgsRasterCalcDialog::mAndButton_clicked()
519 {
520   mExpressionTextEdit->insertPlainText( QStringLiteral( " AND " ) );
521 }
522 
mOrButton_clicked()523 void QgsRasterCalcDialog::mOrButton_clicked()
524 {
525   mExpressionTextEdit->insertPlainText( QStringLiteral( " OR " ) );
526 }
527 
mAbsButton_clicked()528 void QgsRasterCalcDialog::mAbsButton_clicked()
529 {
530   mExpressionTextEdit->insertPlainText( QStringLiteral( " ABS ( " ) );
531 }
532 
mMinButton_clicked()533 void QgsRasterCalcDialog::mMinButton_clicked()
534 {
535   mExpressionTextEdit->insertPlainText( QStringLiteral( " MIN ( " ) );
536 }
537 
mMaxButton_clicked()538 void QgsRasterCalcDialog::mMaxButton_clicked()
539 {
540   mExpressionTextEdit->insertPlainText( QStringLiteral( " MAX ( " ) );
541 }
542 
mConditionalStatButton_clicked()543 void QgsRasterCalcDialog::mConditionalStatButton_clicked()
544 {
545   mExpressionTextEdit->insertPlainText( QStringLiteral( " if ( " ) );
546 }
547 
quoteBandEntry(const QString & layerName)548 QString QgsRasterCalcDialog::quoteBandEntry( const QString &layerName )
549 {
550   // '"' -> '\\"'
551   QString quotedName = layerName;
552   quotedName.replace( '\"', QLatin1String( "\\\"" ) );
553   quotedName.append( '\"' );
554   quotedName.prepend( '\"' );
555   return quotedName;
556 }
557