QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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.toInt();
146  if ( allowNull )
147  {
148  uint stepval = step.isValid() ? step.toUInt() : 1;
149  // make sure there is room for a new value (i.e. signed integer does not overflow)
150  int minvalOverflow = uint( minval ) - stepval;
151  if ( minvalOverflow < minval )
152  {
153  minval = minvalOverflow;
154  }
155  mIntSpinBox->setValue( minval );
156  QgsSpinBox *intSpinBox( qobject_cast<QgsSpinBox *>( mIntSpinBox ) );
157  if ( intSpinBox )
159  else
160  mIntSpinBox->setSpecialValueText( QgsApplication::nullRepresentation() );
161  }
162  setupIntEditor( minval, max, step, mIntSpinBox, this );
163  if ( config( QStringLiteral( "Suffix" ) ).isValid() )
164  mIntSpinBox->setSuffix( config( QStringLiteral( "Suffix" ) ).toString() );
165  }
166  else
167  {
168  ( void )field().convertCompatible( min );
169  ( void )field().convertCompatible( max );
170  ( void )field().convertCompatible( step );
171  if ( mQgsDial )
172  setupIntEditor( min, max, step, mQgsDial, this );
173  else if ( mQgsSlider )
174  setupIntEditor( min, max, step, mQgsSlider, this );
175  else if ( mDial )
176  setupIntEditor( min, max, step, mDial, this );
177  else if ( mSlider )
178  setupIntEditor( min, max, step, mSlider, this );
179  }
180 }
181 
183 {
184  return mSlider || mDial || mQgsDial || mQgsSlider || mIntSpinBox || mDoubleSpinBox;
185 }
186 
187 void QgsRangeWidgetWrapper::valueChangedVariant( const QVariant &v )
188 {
189  if ( v.type() == QVariant::Int )
190  emit valueChanged( v.toInt() );
191  if ( v.type() == QVariant::Double )
192  emit valueChanged( v.toDouble() );
193 }
194 
196 {
197  QVariant value;
198 
199  if ( mDoubleSpinBox )
200  {
201  value = mDoubleSpinBox->value();
202  if ( value == mDoubleSpinBox->minimum() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
203  {
204  value = QVariant( field().type() );
205  }
206  }
207  else if ( mIntSpinBox )
208  {
209  value = mIntSpinBox->value();
210  if ( value == mIntSpinBox->minimum() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
211  {
212  value = QVariant( field().type() );
213  }
214  }
215  else if ( mQgsDial )
216  {
217  value = mQgsDial->variantValue();
218  }
219  else if ( mQgsSlider )
220  {
221  value = mQgsSlider->variantValue();
222  }
223  else if ( mDial )
224  {
225  value = mDial->value();
226  }
227  else if ( mSlider )
228  {
229  value = mSlider->value();
230  }
231 
232  return value;
233 }
234 
235 void QgsRangeWidgetWrapper::setValue( const QVariant &value )
236 {
237  if ( mDoubleSpinBox )
238  {
239  if ( value.isNull() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
240  {
241  mDoubleSpinBox->setValue( mDoubleSpinBox->minimum() );
242  }
243  else
244  {
245  mDoubleSpinBox->setValue( value.toDouble() );
246  }
247  }
248 
249  if ( mIntSpinBox )
250  {
251  if ( value.isNull() && config( QStringLiteral( "AllowNull" ), true ).toBool() )
252  {
253  mIntSpinBox->setValue( mIntSpinBox->minimum() );
254  }
255  else
256  {
257  mIntSpinBox->setValue( value.toInt() );
258  }
259  }
260 
261  if ( mQgsDial )
262  {
263  mQgsDial->setValue( value );
264  }
265  else if ( mQgsSlider )
266  {
267  mQgsSlider->setValue( value );
268  }
269  else if ( mDial )
270  {
271  mDial->setValue( value.toInt() );
272  }
273  else if ( mSlider )
274  {
275  mSlider->setValue( value.toInt() );
276  }
277 }
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.
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...
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
void setValue(const QVariant &value) override
void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
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:154
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.
QVariant value() const override
Will be used to access the widget&#39;s value.
QVariant variantValue() const
Definition: qgsslider.cpp:111