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
QgsRangeWidgetWrapper(QgsVectorLayer * layer,int fieldIdx,QWidget * editor,QWidget * parent)28 QgsRangeWidgetWrapper::QgsRangeWidgetWrapper( QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent )
29 : QgsEditorWidgetWrapper( layer, fieldIdx, editor, parent )
30
31 {
32 }
33
createWidget(QWidget * parent)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>
setupIntEditor(const QVariant & min,const QVariant & max,const QVariant & step,T * slider,QgsRangeWidgetWrapper * wrapper)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
initWidget(QWidget * editor)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 )
127 doubleSpinBox->setSpecialValueText( QgsApplication::nullRepresentation() );
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 )
159 intSpinBox->setSpecialValueText( QgsApplication::nullRepresentation() );
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
valid() const183 bool QgsRangeWidgetWrapper::valid() const
184 {
185 return mSlider || mDial || mQgsDial || mQgsSlider || mIntSpinBox || mDoubleSpinBox;
186 }
187
valueChangedVariant(const QVariant & v)188 void QgsRangeWidgetWrapper::valueChangedVariant( const QVariant &v )
189 {
190 if ( v.type() == QVariant::Int )
191 {
192 Q_NOWARN_DEPRECATED_PUSH
193 emit valueChanged( v.toInt() );
194 Q_NOWARN_DEPRECATED_POP
195 emit valuesChanged( v.toInt() );
196 }
197 if ( v.type() == QVariant::Double )
198 {
199 Q_NOWARN_DEPRECATED_PUSH
200 emit valueChanged( v.toDouble() );
201 Q_NOWARN_DEPRECATED_POP
202 emit valuesChanged( v.toDouble() );
203 }
204 }
205
value() const206 QVariant QgsRangeWidgetWrapper::value() const
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
updateValues(const QVariant & value,const QVariantList &)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 }
289