QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgssinglebandpseudocolorrendererwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssinglebandpseudocolorrendererwidget.cpp
3  ------------------------------------------
4  begin : February 2012
5  copyright : (C) 2012 by Marco Hugentobler
6  email : marco 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 
20 #include "qgsrasterlayer.h"
21 #include "qgsrasterdataprovider.h"
22 #include "qgsrastershader.h"
23 #include "qgsrasterminmaxwidget.h"
24 #include "qgsdoublevalidator.h"
25 #include "qgstreewidgetitem.h"
26 #include "qgssettings.h"
27 #include "qgsmapcanvas.h"
28 #include "qgsguiutils.h"
29 
30 // for color ramps - todo add rasterStyle and refactor raster vs. vector ramps
31 #include "qgsstyle.h"
32 #include "qgscolorramp.h"
33 #include "qgscolorrampbutton.h"
34 #include "qgscolordialog.h"
35 
36 #include <QCursor>
37 #include <QPushButton>
38 #include <QInputDialog>
39 #include <QFileDialog>
40 #include <QMenu>
41 #include <QMessageBox>
42 #include <QTextStream>
43 #include <QTreeView>
44 
46  : QgsRasterRendererWidget( layer, extent )
47  , mMinMaxOrigin( 0 )
48 {
49  const QgsSettings settings;
50 
51  setupUi( this );
52 
53  mColorRampShaderWidget->initializeForUseWithRasterLayer();
54 
55  connect( mMinLineEdit, &QLineEdit::textChanged, this, &QgsSingleBandPseudoColorRendererWidget::mMinLineEdit_textChanged );
56  connect( mMaxLineEdit, &QLineEdit::textChanged, this, &QgsSingleBandPseudoColorRendererWidget::mMaxLineEdit_textChanged );
57  connect( mMinLineEdit, &QLineEdit::textEdited, this, &QgsSingleBandPseudoColorRendererWidget::mMinLineEdit_textEdited );
58  connect( mMaxLineEdit, &QLineEdit::textEdited, this, &QgsSingleBandPseudoColorRendererWidget::mMaxLineEdit_textEdited );
59 
60  if ( !mRasterLayer )
61  {
62  return;
63  }
64 
66  if ( !provider )
67  {
68  return;
69  }
70 
71  // Must be before adding items to mBandComboBox (signal)
72  mMinLineEdit->setValidator( new QgsDoubleValidator( mMinLineEdit ) );
73  mMaxLineEdit->setValidator( new QgsDoubleValidator( mMaxLineEdit ) );
74 
75  mMinMaxWidget = new QgsRasterMinMaxWidget( layer, this );
76  mMinMaxWidget->setExtent( extent );
77  mMinMaxWidget->setMapCanvas( mCanvas );
78 
79  QHBoxLayout *layout = new QHBoxLayout();
80  layout->setContentsMargins( 0, 0, 0, 0 );
81  mMinMaxContainerWidget->setLayout( layout );
82  layout->addWidget( mMinMaxWidget );
83 
84  mColorRampShaderWidget->setRasterDataProvider( provider );
85  mBandComboBox->setLayer( mRasterLayer );
86 
87  setFromRenderer( layer->renderer() );
88 
91 
92  // If there is currently no min/max, load default with user current default options
93  if ( mMinLineEdit->text().isEmpty() || mMaxLineEdit->text().isEmpty() )
94  {
95  QgsRasterMinMaxOrigin minMaxOrigin = mMinMaxWidget->minMaxOrigin();
96  if ( minMaxOrigin.limits() == QgsRasterMinMaxOrigin::None )
97  {
99  mMinMaxWidget->setFromMinMaxOrigin( minMaxOrigin );
100  }
101  mMinMaxWidget->doComputations();
102  }
103 
104  whileBlocking( mColorRampShaderWidget )->setMinimumMaximum( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
105 
106  connect( mBandComboBox, &QgsRasterBandComboBox::bandChanged, this, &QgsSingleBandPseudoColorRendererWidget::bandChanged );
109 }
110 
112 {
113  QgsRasterShader *rasterShader = new QgsRasterShader();
114 
115  mColorRampShaderWidget->setMinimumMaximum( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
116  mColorRampShaderWidget->setExtent( mMinMaxWidget->extent() );
117 
118  QgsColorRampShader *fcn = new QgsColorRampShader( mColorRampShaderWidget->shader() );
119  rasterShader->setRasterShaderFunction( fcn );
120 
121  const int bandNumber = mBandComboBox->currentBand();
123  renderer->setClassificationMin( lineEditValue( mMinLineEdit ) );
124  renderer->setClassificationMax( lineEditValue( mMaxLineEdit ) );
125  renderer->setMinMaxOrigin( mMinMaxWidget->minMaxOrigin() );
126  return renderer;
127 }
128 
130 {
131  mMinMaxWidget->doComputations();
132 }
133 
135 
137 {
138  return mBandComboBox->currentBand();
139 }
140 
142 {
144  mMinMaxWidget->setMapCanvas( canvas );
145  mColorRampShaderWidget->setExtent( mMinMaxWidget->extent() );
146 }
147 
149 {
150  const QgsSingleBandPseudoColorRenderer *pr = dynamic_cast<const QgsSingleBandPseudoColorRenderer *>( r );
151  if ( pr )
152  {
153  mBandComboBox->setBand( pr->band() );
154  mMinMaxWidget->setBands( QList< int >() << pr->band() );
155  mColorRampShaderWidget->setRasterBand( pr->band() );
156 
157  // need to set min/max properties here because if we use the raster shader below,
158  // we may set a new color ramp which needs to have min/max values defined.
159  setLineEditValue( mMinLineEdit, pr->classificationMin() );
160  setLineEditValue( mMaxLineEdit, pr->classificationMax() );
161  mMinMaxWidget->setFromMinMaxOrigin( pr->minMaxOrigin() );
162 
163  const QgsRasterShader *rasterShader = pr->shader();
164  if ( rasterShader )
165  {
166  const QgsColorRampShader *colorRampShader = dynamic_cast<const QgsColorRampShader *>( rasterShader->rasterShaderFunction() );
167  if ( colorRampShader )
168  {
169  mColorRampShaderWidget->setFromShader( *colorRampShader );
170  }
171  }
172  }
173  else
174  {
175  mMinMaxWidget->setBands( QList< int >() << mBandComboBox->currentBand() );
176  mColorRampShaderWidget->setRasterBand( mBandComboBox->currentBand() );
177  }
178 }
179 
180 void QgsSingleBandPseudoColorRendererWidget::bandChanged()
181 {
182  QList<int> bands;
183  bands.append( mBandComboBox->currentBand() );
184  mMinMaxWidget->setBands( bands );
185  mColorRampShaderWidget->setRasterBand( mBandComboBox->currentBand() );
186  mColorRampShaderWidget->classify();
187 }
188 
189 void QgsSingleBandPseudoColorRendererWidget::loadMinMax( int bandNo, double min, double max )
190 {
191  QgsDebugMsg( QStringLiteral( "theBandNo = %1 min = %2 max = %3" ).arg( bandNo ).arg( min ).arg( max ) );
192 
193  const QString oldMinTextvalue = mMinLineEdit->text();
194  const QString oldMaxTextvalue = mMaxLineEdit->text();
195 
196  if ( std::isnan( min ) )
197  {
198  whileBlocking( mMinLineEdit )->clear();
199  }
200  else
201  {
202  whileBlocking( mMinLineEdit )->setText( displayValueWithMaxPrecision( min ) );
203  }
204 
205  if ( std::isnan( max ) )
206  {
207  whileBlocking( mMaxLineEdit )->clear();
208  }
209  else
210  {
211  whileBlocking( mMaxLineEdit )->setText( displayValueWithMaxPrecision( max ) );
212  }
213 
214  // We compare old min and new min as text because QString::number keeps a fixed number of significant
215  // digits (default 6) and so loaded min/max will always differ from current one, which triggers a
216  // classification, and wipe out every user modification (see https://github.com/qgis/QGIS/issues/36172)
217  if ( mMinLineEdit->text() != oldMinTextvalue || mMaxLineEdit->text() != oldMaxTextvalue )
218  {
219  whileBlocking( mColorRampShaderWidget )->setRasterBand( bandNo );
220  whileBlocking( mColorRampShaderWidget )->setMinimumMaximumAndClassify( min, max );
221  }
222 }
223 
224 
226 {
227  whileBlocking( mMinLineEdit )->setText( displayValueWithMaxPrecision( min ) );
228  whileBlocking( mMaxLineEdit )->setText( displayValueWithMaxPrecision( max ) );
229  minMaxModified();
230 }
231 
232 
233 void QgsSingleBandPseudoColorRendererWidget::setLineEditValue( QLineEdit *lineEdit, double value )
234 {
235  QString s;
236  if ( !std::isnan( value ) )
237  {
238  s = displayValueWithMaxPrecision( value );
239  }
240  lineEdit->setText( s );
241 }
242 
243 double QgsSingleBandPseudoColorRendererWidget::lineEditValue( const QLineEdit *lineEdit ) const
244 {
245  if ( lineEdit->text().isEmpty() )
246  {
247  return std::numeric_limits<double>::quiet_NaN();
248  }
249 
250  return QgsDoubleValidator::toDouble( lineEdit->text() );
251 }
252 
253 void QgsSingleBandPseudoColorRendererWidget::mMinLineEdit_textEdited( const QString & )
254 {
255  minMaxModified();
256  whileBlocking( mColorRampShaderWidget )->setMinimumMaximumAndClassify( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
257  emit widgetChanged();
258 }
259 
260 void QgsSingleBandPseudoColorRendererWidget::mMaxLineEdit_textEdited( const QString & )
261 {
262  minMaxModified();
263  whileBlocking( mColorRampShaderWidget )->setMinimumMaximumAndClassify( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
264  emit widgetChanged();
265 }
266 
267 void QgsSingleBandPseudoColorRendererWidget::mMinLineEdit_textChanged( const QString & )
268 {
269  whileBlocking( mColorRampShaderWidget )->setMinimumMaximum( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
270  emit widgetChanged();
271 }
272 
273 void QgsSingleBandPseudoColorRendererWidget::mMaxLineEdit_textChanged( const QString & )
274 {
275  whileBlocking( mColorRampShaderWidget )->setMinimumMaximum( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
276  emit widgetChanged();
277 }
278 
279 
280 void QgsSingleBandPseudoColorRendererWidget::minMaxModified()
281 {
282  mMinMaxWidget->userHasSetManualMinMaxValues();
283 }
284 
285 QString QgsSingleBandPseudoColorRendererWidget::displayValueWithMaxPrecision( const double value )
286 {
287  if ( mRasterLayer->dataProvider() )
288  {
289  return QgsGuiUtils::displayValueWithMaximumDecimals( mRasterLayer->dataProvider()->dataType( mBandComboBox->currentBand() ), value );
290  }
291  else
292  {
293  // Use QLocale default
294  return QLocale().toString( value, 'g' );
295  }
296 }
void minimumMaximumChangedFromTree(double minimum, double maximum)
Color ramp tree has changed.
void widgetChanged()
Widget changed.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
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:88
void bandChanged(int band)
Emitted when the currently selected band changes.
Base class for raster data providers.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
Represents a raster layer.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
This class describes the origin of min/max values.
QgsRasterMinMaxOrigin::Limits limits() const
Returns the raster limits.
void setLimits(QgsRasterMinMaxOrigin::Limits limits)
Sets the limits.
@ MinMax
Real min-max values.
void setExtent(const QgsRectangle &extent)
Sets the extent to use for minimum and maximum value calculation.
QgsRectangle extent()
Returns the extent selected by the user.
void doComputations()
Load programmatically with current values.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void load(int bandNo, double min, double max)
signal emitted when new min/max values are computed from statistics.
void setFromMinMaxOrigin(const QgsRasterMinMaxOrigin &)
Sets the "source" of min/max values.
void setBands(const QList< int > &bands)
QgsRasterMinMaxOrigin minMaxOrigin()
Returns a QgsRasterMinMaxOrigin object with the widget values.
void widgetChanged()
Emitted when something on the widget has changed.
void userHasSetManualMinMaxValues()
Uncheck cumulative cut, min/max, std-dev radio buttons.
virtual void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
virtual QString max(int index=0)
virtual QString min(int index=0)
QgsMapCanvas * mCanvas
Associated map canvas.
void widgetChanged()
Emitted when something on the widget has changed.
Raster renderer pipe that applies colors to a raster.
void setMinMaxOrigin(const QgsRasterMinMaxOrigin &origin)
Sets origin of min/max values.
const QgsRasterMinMaxOrigin & minMaxOrigin() const
Returns const reference to origin of min/max values.
Interface for all raster shaders.
QgsRasterShaderFunction * rasterShaderFunction()
void setRasterShaderFunction(QgsRasterShaderFunction *function)
A public method that allows the user to set their own shader function.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsSingleBandPseudoColorRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())
Creates new raster renderer widget.
void doComputations() override
Load programmatically with current values.
QgsRasterMinMaxWidget * minMaxWidget() override
Returns min/max widget when it exists.
int currentBand() const
Returns the current raster band number.
void setMapCanvas(QgsMapCanvas *canvas) override
Sets the map canvas associated with the widget.
void setFromRenderer(const QgsRasterRenderer *r)
Set state of the widget from renderer settings.
void loadMinMax(int bandNo, double min, double max)
called when new min/max values are loaded
void loadMinMaxFromTree(double min, double max)
called when the color ramp tree has changed
Raster renderer pipe for single band pseudocolor.
int band() const
Returns the band used by the renderer.
QgsRasterShader * shader()
Returns the raster shader.
void setBand(int bandNo)
Sets the band used by the renderer.
QString displayValueWithMaximumDecimals(const Qgis::DataType dataType, const double value, bool displayTrailingZeroes)
Returns a localized string representation of the value with the appropriate number of decimals suppor...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:1173
#define QgsDebugMsg(str)
Definition: qgslogger.h:38