QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
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
28QgsRangeWidgetWrapper::QgsRangeWidgetWrapper( QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent )
29 : QgsEditorWidgetWrapper( layer, fieldIdx, editor, parent )
30
31{
32}
33
34QWidget *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
72template<class T>
73static 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
82void 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
195void 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
274void QgsRangeWidgetWrapper::updateValues( const QVariant &value, const QVariantList & )
275{
276 if ( mDoubleSpinBox )
277 {
278 if ( QgsVariantUtils::isNull( value ) && 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 ( QgsVariantUtils::isNull( value ) && 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}
317
319{
320 if ( mDoubleSpinBox )
321 {
322 mDoubleSpinBox->setReadOnly( !enabled );
323 mDoubleSpinBox->setFrame( enabled );
324 }
325 else if ( mIntSpinBox )
326 {
327 mIntSpinBox->setReadOnly( !enabled );
328 mIntSpinBox->setFrame( enabled );
329 }
330 else
331 {
333 }
334}
335
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
void setValue(const QVariant &value)
Definition: qgsdial.cpp:61
QVariant variantValue() const
Definition: qgsdial.cpp:107
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 setEnabled(bool enabled) override
Is used to enable or disable the edit functionality of the managed widget.
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:53
int precision
Definition: qgsfield.h:59
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:452
QVariant::Type type
Definition: qgsfield.h:60
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 setEnabled(bool enabled) override
void setValue(const QVariant &value)
Definition: qgsslider.cpp:66
QVariant variantValue() const
Definition: qgsslider.cpp:108
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:178
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
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:5776
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:5775
int precision