QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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  {
52  editor = new QgsDoubleSpinBox( parent );
53  static_cast<QgsDoubleSpinBox *>( editor )->setLineEditAlignment( Qt::AlignRight );
54  break;
55  }
56  case QVariant::Int:
57  case QVariant::LongLong:
58  default:
59  editor = new QgsSpinBox( parent );
60  static_cast<QgsSpinBox *>( editor )->setLineEditAlignment( Qt::AlignRight );
61  break;
62  }
63  }
64 
65  return editor;
66 }
67 
68 template<class T>
69 static void setupIntEditor( const QVariant &min, const QVariant &max, const QVariant &step, T *slider, QgsRangeWidgetWrapper *wrapper )
70 {
71  // must use a template function because those methods are overloaded and not inherited by some classes
72  slider->setMinimum( min.isValid() ? min.toInt() : std::numeric_limits<int>::lowest() );
73  slider->setMaximum( max.isValid() ? max.toInt() : std::numeric_limits<int>::max() );
74  slider->setSingleStep( step.isValid() ? step.toInt() : 1 );
75  QObject::connect( slider, SIGNAL( valueChanged( int ) ), wrapper, SLOT( emitValueChanged() ) );
76 }
77 
78 void QgsRangeWidgetWrapper::initWidget( QWidget *editor )
79 {
80  mDoubleSpinBox = qobject_cast<QDoubleSpinBox *>( editor );
81  mIntSpinBox = qobject_cast<QSpinBox *>( editor );
82 
83  mDial = qobject_cast<QDial *>( editor );
84  mSlider = qobject_cast<QSlider *>( editor );
85  mQgsDial = qobject_cast<QgsDial *>( editor );
86  mQgsSlider = qobject_cast<QgsSlider *>( editor );
87 
88  bool allowNull = config( QStringLiteral( "AllowNull" ), true ).toBool();
89 
90  QVariant min( config( QStringLiteral( "Min" ) ) );
91  QVariant max( config( QStringLiteral( "Max" ) ) );
92  QVariant step( config( QStringLiteral( "Step" ) ) );
93  QVariant precision( config( QStringLiteral( "Precision" ) ) );
94 
95  if ( mDoubleSpinBox )
96  {
97  double stepval = step.isValid() ? step.toDouble() : 1.0;
98  double minval = min.isValid() ? min.toDouble() : std::numeric_limits<double>::lowest();
99  double maxval = max.isValid() ? max.toDouble() : std::numeric_limits<double>::max();
100  int precisionval = precision.isValid() ? precision.toInt() : layer()->fields().at( fieldIdx() ).precision();
101 
102  mDoubleSpinBox->setDecimals( precisionval );
103 
104  QgsDoubleSpinBox *qgsWidget = qobject_cast<QgsDoubleSpinBox *>( mDoubleSpinBox );
105 
106 
107  if ( qgsWidget )
108  qgsWidget->setShowClearButton( allowNull );
109  // Make room for null value: lower the minimum to allow for NULL special values
110  if ( allowNull )
111  {
112  double decr;
113  if ( precisionval > 0 )
114  {
115  decr = std::pow( 10, -precisionval );
116  }
117  else
118  {
119  decr = stepval;
120  }
121  minval -= decr;
122  // Note: call setMinimum here or setValue won't work
123  mDoubleSpinBox->setMinimum( minval );
124  mDoubleSpinBox->setValue( minval );
125  QgsDoubleSpinBox *doubleSpinBox( qobject_cast<QgsDoubleSpinBox *>( mDoubleSpinBox ) );
126  if ( doubleSpinBox )
128  else
129  mDoubleSpinBox->setSpecialValueText( QgsApplication::nullRepresentation() );
130  }
131  mDoubleSpinBox->setMinimum( minval );
132  mDoubleSpinBox->setMaximum( maxval );
133  mDoubleSpinBox->setSingleStep( stepval );
134  if ( config( QStringLiteral( "Suffix" ) ).isValid() )
135  mDoubleSpinBox->setSuffix( config( QStringLiteral( "Suffix" ) ).toString() );
136 
137  connect( mDoubleSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ),
138  this, [ = ]( double ) { emitValueChanged(); } );
139  }
140  else if ( mIntSpinBox )
141  {
142  QgsSpinBox *qgsWidget = qobject_cast<QgsSpinBox *>( mIntSpinBox );
143  if ( qgsWidget )
144  qgsWidget->setShowClearButton( allowNull );
145  int minval = min.isValid() ? min.toInt() : std::numeric_limits<int>::lowest();
146  int maxval = max.isValid() ? max.toInt() : std::numeric_limits<int>::max();
147  uint stepval = step.isValid() ? step.toUInt() : 1;
148  if ( allowNull )
149  {
150  // make sure there is room for a new value (i.e. signed integer does not overflow)
151  int minvalOverflow = uint( minval ) - stepval;
152  if ( minvalOverflow < minval )
153  {
154  minval = minvalOverflow;
155  }
156  mIntSpinBox->setValue( minval );
157  QgsSpinBox *intSpinBox( qobject_cast<QgsSpinBox *>( mIntSpinBox ) );
158  if ( intSpinBox )
160  else
161  mIntSpinBox->setSpecialValueText( QgsApplication::nullRepresentation() );
162  }
163  setupIntEditor( minval, maxval, stepval, mIntSpinBox, this );
164  if ( config( QStringLiteral( "Suffix" ) ).isValid() )
165  mIntSpinBox->setSuffix( config( QStringLiteral( "Suffix" ) ).toString() );
166  }
167  else
168  {
169  ( void )field().convertCompatible( min );
170  ( void )field().convertCompatible( max );
171  ( void )field().convertCompatible( step );
172  if ( mQgsDial )
173  setupIntEditor( min, max, step, mQgsDial, this );
174  else if ( mQgsSlider )
175  setupIntEditor( min, max, step, mQgsSlider, this );
176  else if ( mDial )
177  setupIntEditor( min, max, step, mDial, this );
178  else if ( mSlider )
179  setupIntEditor( min, max, step, mSlider, this );
180  }
181 }
182 
184 {
185  return mSlider || mDial || mQgsDial || mQgsSlider || mIntSpinBox || mDoubleSpinBox;
186 }
187 
188 void QgsRangeWidgetWrapper::valueChangedVariant( const QVariant &v )
189 {
190  if ( v.type() == QVariant::Int )
191  {
193  emit valueChanged( v.toInt() );
195  emit valuesChanged( v.toInt() );
196  }
197  if ( v.type() == QVariant::Double )
198  {
200  emit valueChanged( v.toDouble() );
202  emit valuesChanged( v.toDouble() );
203  }
204 }
205 
207 {
208  QVariant value;
209 
210  if ( mDoubleSpinBox )
211  {
212  value = mDoubleSpinBox->value();
213  if ( value == mDoubleSpinBox->minimum() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
214  {
215  value = QVariant( field().type() );
216  }
217  }
218  else if ( mIntSpinBox )
219  {
220  value = mIntSpinBox->value();
221  if ( value == mIntSpinBox->minimum() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
222  {
223  value = QVariant( field().type() );
224  }
225  }
226  else if ( mQgsDial )
227  {
228  value = mQgsDial->variantValue();
229  }
230  else if ( mQgsSlider )
231  {
232  value = mQgsSlider->variantValue();
233  }
234  else if ( mDial )
235  {
236  value = mDial->value();
237  }
238  else if ( mSlider )
239  {
240  value = mSlider->value();
241  }
242 
243  return value;
244 }
245 
246 void QgsRangeWidgetWrapper::updateValues( const QVariant &value, const QVariantList & )
247 {
248  if ( mDoubleSpinBox )
249  {
250  if ( value.isNull() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
251  {
252  mDoubleSpinBox->setValue( mDoubleSpinBox->minimum() );
253  }
254  else
255  {
256  mDoubleSpinBox->setValue( value.toDouble() );
257  }
258  }
259 
260  if ( mIntSpinBox )
261  {
262  if ( value.isNull() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
263  {
264  mIntSpinBox->setValue( mIntSpinBox->minimum() );
265  }
266  else
267  {
268  mIntSpinBox->setValue( value.toInt() );
269  }
270  }
271 
272  if ( mQgsDial )
273  {
274  mQgsDial->setValue( value );
275  }
276  else if ( mQgsSlider )
277  {
278  mQgsSlider->setValue( value );
279  }
280  else if ( mDial )
281  {
282  mDial->setValue( value.toInt() );
283  }
284  else if ( mSlider )
285  {
286  mSlider->setValue( value.toInt() );
287  }
288 }
void setValue(const QVariant &value)
Definition: qgsslider.cpp:65
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value...
bool valid() const override
Returns true if the widget has been properly initialized.
int precision
void emitValueChanged()
Will call the value() method to determine the emitted value.
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
int precision
Definition: qgsfield.h:55
QgsField field() const
Access the field.
void setShowClearButton(bool showClearButton)
Sets whether the widget will show a clear button.
Manages an editor widget Widget and wrapper share the same parent.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:649
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:281
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value...
Definition: qgsspinbox.h:42
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 valuesChanged(const QVariant &value, const QVariantList &additionalFieldValues=QVariantList())
Emit this signal, whenever the value changed.
QVariantMap config() const
Returns the whole config.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
void setShowClearButton(bool showClearButton)
Sets whether the widget will show a clear button.
Definition: qgsspinbox.cpp:49
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Wraps a range widget.
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
void setValue(const QVariant &value)
Definition: qgsdial.cpp:60
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:650
QgsRangeWidgetWrapper(QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent=nullptr)
Constructor for QgsRangeWidgetWrapper.
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:165
QVariant variantValue() const
Definition: qgsdial.cpp:106
int fieldIdx() const
Access the field index.
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Represents a vector layer which manages a vector based data sets.
Q_DECL_DEPRECATED void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
QVariant value() const override
Will be used to access the widget&#39;s value.
QVariant variantValue() const
Definition: qgsslider.cpp:111