QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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}
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 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:412
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: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:168
static bool isNull(const QVariant &variant)
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:3061
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:3060
int precision