QGIS API Documentation  3.23.0-Master (c716e02dd3)
qgsrangewidgetwrapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrangewidgetwrapper.cpp
3  --------------------------------------
4  Date : 5.1.2014
5  Copyright : (C) 2014 Matthias Kuhn
6  Email : matthias at opengis dot ch
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 
16 #include <QSettings>
17 
18 #include "qgsrangewidgetwrapper.h"
19 #include "qgsspinbox.h"
20 #include "qgsdoublespinbox.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsdial.h"
23 #include "qgsslider.h"
24 #include "qgsapplication.h"
25 
26 
27 
28 QgsRangeWidgetWrapper::QgsRangeWidgetWrapper( QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent )
29  : QgsEditorWidgetWrapper( layer, fieldIdx, editor, parent )
30 
31 {
32 }
33 
34 QWidget *QgsRangeWidgetWrapper::createWidget( QWidget *parent )
35 {
36  QWidget *editor = nullptr;
37 
38  if ( config( QStringLiteral( "Style" ) ).toString() == QLatin1String( "Dial" ) )
39  {
40  editor = new QgsDial( parent );
41  }
42  else if ( config( QStringLiteral( "Style" ) ).toString() == QLatin1String( "Slider" ) )
43  {
44  editor = new QgsSlider( Qt::Horizontal, parent );
45  }
46  else
47  {
48  switch ( layer()->fields().at( fieldIdx() ).type() )
49  {
50  case QVariant::Double:
51  // for long long field types we have to use a double spin box with 0 decimal places,
52  // as the min/max value supported by QSpinBox is not large enough
53  case QVariant::LongLong:
54  {
55 
56  editor = new QgsDoubleSpinBox( parent );
57  static_cast<QgsDoubleSpinBox *>( editor )->setLineEditAlignment( Qt::AlignRight );
58  break;
59  }
60 
61  case QVariant::Int:
62  default:
63  editor = new QgsSpinBox( parent );
64  static_cast<QgsSpinBox *>( editor )->setLineEditAlignment( Qt::AlignRight );
65  break;
66  }
67  }
68 
69  return editor;
70 }
71 
72 template<class T>
73 static void setupIntEditor( const QVariant &min, const QVariant &max, const QVariant &step, T *slider, QgsRangeWidgetWrapper *wrapper )
74 {
75  // must use a template function because those methods are overloaded and not inherited by some classes
76  slider->setMinimum( min.isValid() ? min.toInt() : std::numeric_limits<int>::lowest() );
77  slider->setMaximum( max.isValid() ? max.toInt() : std::numeric_limits<int>::max() );
78  slider->setSingleStep( step.isValid() ? step.toInt() : 1 );
79  QObject::connect( slider, SIGNAL( valueChanged( int ) ), wrapper, SLOT( emitValueChanged() ) );
80 }
81 
82 void QgsRangeWidgetWrapper::initWidget( QWidget *editor )
83 {
84  mDoubleSpinBox = qobject_cast<QDoubleSpinBox *>( editor );
85  mIntSpinBox = qobject_cast<QSpinBox *>( editor );
86 
87  mDial = qobject_cast<QDial *>( editor );
88  mSlider = qobject_cast<QSlider *>( editor );
89  mQgsDial = qobject_cast<QgsDial *>( editor );
90  mQgsSlider = qobject_cast<QgsSlider *>( editor );
91 
92  const bool allowNull = config( QStringLiteral( "AllowNull" ), true ).toBool();
93 
94  QVariant min( config( QStringLiteral( "Min" ) ) );
95  QVariant max( config( QStringLiteral( "Max" ) ) );
96  QVariant step( config( QStringLiteral( "Step" ) ) );
97  const QVariant precision( config( QStringLiteral( "Precision" ) ) );
98 
99  if ( mDoubleSpinBox )
100  {
101  const double stepval = step.isValid() ? step.toDouble() : 1.0;
102  double minval = min.isValid() ? min.toDouble() : std::numeric_limits<double>::lowest();
103  const double maxval = max.isValid() ? max.toDouble() : std::numeric_limits<double>::max();
104 
105  const QgsField field = layer()->fields().at( fieldIdx() );
106  // we use the double spin box for long long fields in order to get sufficient range of min/max values
107  const int precisionval = field.type() == QVariant::LongLong ? 0 : ( precision.isValid() ? precision.toInt() : field.precision() );
108 
109  mDoubleSpinBox->setDecimals( precisionval );
110 
111  QgsDoubleSpinBox *qgsWidget = qobject_cast<QgsDoubleSpinBox *>( mDoubleSpinBox );
112 
113 
114  if ( qgsWidget )
115  qgsWidget->setShowClearButton( allowNull );
116  // Make room for null value: lower the minimum to allow for NULL special values
117  if ( allowNull )
118  {
119  double decr;
120  if ( precisionval > 0 )
121  {
122  decr = std::pow( 10, -precisionval );
123  }
124  else
125  {
126  decr = stepval;
127  }
128  minval -= decr;
129  // Note: call setMinimum here or setValue won't work
130  mDoubleSpinBox->setMinimum( minval );
131  mDoubleSpinBox->setValue( minval );
132  QgsDoubleSpinBox *doubleSpinBox( qobject_cast<QgsDoubleSpinBox *>( mDoubleSpinBox ) );
133  if ( doubleSpinBox )
135  else
136  mDoubleSpinBox->setSpecialValueText( QgsApplication::nullRepresentation() );
137  }
138  mDoubleSpinBox->setMinimum( minval );
139  mDoubleSpinBox->setMaximum( maxval );
140  mDoubleSpinBox->setSingleStep( stepval );
141  if ( config( QStringLiteral( "Suffix" ) ).isValid() )
142  mDoubleSpinBox->setSuffix( config( QStringLiteral( "Suffix" ) ).toString() );
143 
144  connect( mDoubleSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ),
145  this, [ = ]( double ) { emitValueChanged(); } );
146  }
147  else if ( mIntSpinBox )
148  {
149  QgsSpinBox *qgsWidget = qobject_cast<QgsSpinBox *>( mIntSpinBox );
150  if ( qgsWidget )
151  qgsWidget->setShowClearButton( allowNull );
152  int minval = min.isValid() ? min.toInt() : std::numeric_limits<int>::lowest();
153  const int maxval = max.isValid() ? max.toInt() : std::numeric_limits<int>::max();
154  const uint stepval = step.isValid() ? step.toUInt() : 1;
155  if ( allowNull )
156  {
157  // make sure there is room for a new value (i.e. signed integer does not overflow)
158  const int minvalOverflow = uint( minval ) - stepval;
159  if ( minvalOverflow < minval )
160  {
161  minval = minvalOverflow;
162  }
163  mIntSpinBox->setValue( minval );
164  QgsSpinBox *intSpinBox( qobject_cast<QgsSpinBox *>( mIntSpinBox ) );
165  if ( intSpinBox )
167  else
168  mIntSpinBox->setSpecialValueText( QgsApplication::nullRepresentation() );
169  }
170  setupIntEditor( minval, maxval, stepval, mIntSpinBox, this );
171  if ( config( QStringLiteral( "Suffix" ) ).isValid() )
172  mIntSpinBox->setSuffix( config( QStringLiteral( "Suffix" ) ).toString() );
173  }
174  else
175  {
176  ( void )field().convertCompatible( min );
177  ( void )field().convertCompatible( max );
178  ( void )field().convertCompatible( step );
179  if ( mQgsDial )
180  setupIntEditor( min, max, step, mQgsDial, this );
181  else if ( mQgsSlider )
182  setupIntEditor( min, max, step, mQgsSlider, this );
183  else if ( mDial )
184  setupIntEditor( min, max, step, mDial, this );
185  else if ( mSlider )
186  setupIntEditor( min, max, step, mSlider, this );
187  }
188 }
189 
191 {
192  return mSlider || mDial || mQgsDial || mQgsSlider || mIntSpinBox || mDoubleSpinBox;
193 }
194 
195 void QgsRangeWidgetWrapper::valueChangedVariant( const QVariant &v )
196 {
197  if ( v.type() == QVariant::Int )
198  {
200  emit valueChanged( v.toInt() );
202  emit valuesChanged( v.toInt() );
203  }
204  else if ( v.type() == QVariant::LongLong )
205  {
207  emit valueChanged( v.toLongLong() );
209  emit valuesChanged( v.toLongLong() );
210  }
211  else if ( v.type() == QVariant::Double )
212  {
214  emit valueChanged( v.toDouble() );
216  emit valuesChanged( v.toDouble() );
217  }
218 }
219 
221 {
222  QVariant value;
223 
224  if ( mDoubleSpinBox )
225  {
226  const QVariant::Type fieldType = field().type();
227  switch ( fieldType )
228  {
229  case QVariant::Double:
230  value = mDoubleSpinBox->value();
231  break;
232 
233  case QVariant::LongLong:
234  value = static_cast< long long >( mDoubleSpinBox->value() );
235  break;
236 
237  default:
238  break;
239  }
240 
241  if ( value == mDoubleSpinBox->minimum() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
242  {
243  value = QVariant( fieldType );
244  }
245  }
246  else if ( mIntSpinBox )
247  {
248  value = mIntSpinBox->value();
249  if ( value == mIntSpinBox->minimum() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
250  {
251  value = QVariant( field().type() );
252  }
253  }
254  else if ( mQgsDial )
255  {
256  value = mQgsDial->variantValue();
257  }
258  else if ( mQgsSlider )
259  {
260  value = mQgsSlider->variantValue();
261  }
262  else if ( mDial )
263  {
264  value = mDial->value();
265  }
266  else if ( mSlider )
267  {
268  value = mSlider->value();
269  }
270 
271  return value;
272 }
273 
274 void QgsRangeWidgetWrapper::updateValues( const QVariant &value, const QVariantList & )
275 {
276  if ( mDoubleSpinBox )
277  {
278  if ( value.isNull() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
279  {
280  mDoubleSpinBox->setValue( mDoubleSpinBox->minimum() );
281  }
282  else
283  {
284  mDoubleSpinBox->setValue( value.toDouble() );
285  }
286  }
287 
288  if ( mIntSpinBox )
289  {
290  if ( value.isNull() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
291  {
292  mIntSpinBox->setValue( mIntSpinBox->minimum() );
293  }
294  else
295  {
296  mIntSpinBox->setValue( value.toInt() );
297  }
298  }
299 
300  if ( mQgsDial )
301  {
302  mQgsDial->setValue( value );
303  }
304  else if ( mQgsSlider )
305  {
306  mQgsSlider->setValue( value );
307  }
308  else if ( mDial )
309  {
310  mDial->setValue( value.toInt() );
311  }
312  else if ( mSlider )
313  {
314  mSlider->setValue( value.toInt() );
315  }
316 }
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
void setValue(const QVariant &value)
Definition: qgsdial.cpp:60
QVariant variantValue() const
Definition: qgsdial.cpp:106
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
void setSpecialValueText(const QString &txt)
Set the special-value text to be txt If set, the spin box will display this text instead of a numeric...
void setShowClearButton(bool showClearButton)
Sets whether the widget will show a clear button.
Manages an editor widget Widget and wrapper share the same parent.
Q_DECL_DEPRECATED void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
int fieldIdx() const
Access the field index.
void valuesChanged(const QVariant &value, const QVariantList &additionalFieldValues=QVariantList())
Emit this signal, whenever the value changed.
void emitValueChanged()
Will call the value() method to determine the emitted value.
QgsField field() const
Access the field.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
int precision
Definition: qgsfield.h:57
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:402
QVariant::Type type
Definition: qgsfield.h:58
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
Wraps a range widget.
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
bool valid() const override
Returns true if the widget has been properly initialized.
QgsRangeWidgetWrapper(QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent=nullptr)
Constructor for QgsRangeWidgetWrapper.
QVariant value() const override
Will be used to access the widget's value.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
void setValue(const QVariant &value)
Definition: qgsslider.cpp:65
QVariant variantValue() const
Definition: qgsslider.cpp:111
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
Definition: qgsspinbox.h:43
void setShowClearButton(bool showClearButton)
Sets whether the widget will show a clear button.
Definition: qgsspinbox.cpp:52
void setSpecialValueText(const QString &txt)
Set the special-value text to be txt If set, the spin box will display this text instead of a numeric...
Definition: qgsspinbox.cpp:168
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
QVariantMap config() const
Returns the whole config.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2042
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2041
int precision