QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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  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  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  if ( std::isnan( min ) )
194  {
195  whileBlocking( mMinLineEdit )->clear();
196  }
197  else
198  {
199  whileBlocking( mMinLineEdit )->setText( displayValueWithMaxPrecision( min ) );
200  }
201 
202  if ( std::isnan( max ) )
203  {
204  whileBlocking( mMaxLineEdit )->clear();
205  }
206  else
207  {
208  whileBlocking( mMaxLineEdit )->setText( displayValueWithMaxPrecision( max ) );
209  }
210 
211  // We compare old min and new min as text because QString::number keeps a fixed number of significant
212  // digits (default 6) and so loaded min/max will always differ from current one, which triggers a
213  // classification, and wipe out every user modification (see https://github.com/qgis/QGIS/issues/36172)
214  if ( mMinLineEdit->text() != displayValueWithMaxPrecision( min ) || mMaxLineEdit->text() != displayValueWithMaxPrecision( max ) )
215  {
216  whileBlocking( mColorRampShaderWidget )->setRasterBand( bandNo );
217  whileBlocking( mColorRampShaderWidget )->setMinimumMaximumAndClassify( min, max );
218  }
219 }
220 
221 
223 {
224  whileBlocking( mMinLineEdit )->setText( displayValueWithMaxPrecision( min ) );
225  whileBlocking( mMaxLineEdit )->setText( displayValueWithMaxPrecision( max ) );
226  minMaxModified();
227 }
228 
229 
230 void QgsSingleBandPseudoColorRendererWidget::setLineEditValue( QLineEdit *lineEdit, double value )
231 {
232  QString s;
233  if ( !std::isnan( value ) )
234  {
235  s = displayValueWithMaxPrecision( value );
236  }
237  lineEdit->setText( s );
238 }
239 
240 double QgsSingleBandPseudoColorRendererWidget::lineEditValue( const QLineEdit *lineEdit ) const
241 {
242  if ( lineEdit->text().isEmpty() )
243  {
244  return std::numeric_limits<double>::quiet_NaN();
245  }
246 
247  return QgsDoubleValidator::toDouble( lineEdit->text() );
248 }
249 
250 void QgsSingleBandPseudoColorRendererWidget::mMinLineEdit_textEdited( const QString & )
251 {
252  minMaxModified();
253  whileBlocking( mColorRampShaderWidget )->setMinimumMaximumAndClassify( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
254  emit widgetChanged();
255 }
256 
257 void QgsSingleBandPseudoColorRendererWidget::mMaxLineEdit_textEdited( const QString & )
258 {
259  minMaxModified();
260  whileBlocking( mColorRampShaderWidget )->setMinimumMaximumAndClassify( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
261  emit widgetChanged();
262 }
263 
264 void QgsSingleBandPseudoColorRendererWidget::mMinLineEdit_textChanged( const QString & )
265 {
266  whileBlocking( mColorRampShaderWidget )->setMinimumMaximum( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
267  emit widgetChanged();
268 }
269 
270 void QgsSingleBandPseudoColorRendererWidget::mMaxLineEdit_textChanged( const QString & )
271 {
272  whileBlocking( mColorRampShaderWidget )->setMinimumMaximum( lineEditValue( mMinLineEdit ), lineEditValue( mMaxLineEdit ) );
273  emit widgetChanged();
274 }
275 
276 
277 void QgsSingleBandPseudoColorRendererWidget::minMaxModified()
278 {
279  mMinMaxWidget->userHasSetManualMinMaxValues();
280 }
281 
282 QString QgsSingleBandPseudoColorRendererWidget::displayValueWithMaxPrecision( const double value )
283 {
284  if ( mRasterLayer->dataProvider() )
285  {
286  return QgsGuiUtils::displayValueWithMaximumDecimals( mRasterLayer->dataProvider()->dataType( mBandComboBox->currentBand() ), value );
287  }
288  else
289  {
290  // Use QLocale default
291  return QLocale().toString( value, 'g' );
292  }
293 }
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:86
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.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
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
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
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:263
#define QgsDebugMsg(str)
Definition: qgslogger.h:38