QGIS API Documentation 3.36.0-Maidenhead (09951dc0acf)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsvaluerelationwidgetwrapper.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvaluerelationwidgetwrapper.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
17
18#include "qgis.h"
19#include "qgsfields.h"
20#include "qgsproject.h"
22#include "qgsvectorlayer.h"
23#include "qgsfilterlineedit.h"
24#include "qgsfeatureiterator.h"
26#include "qgsattributeform.h"
27#include "qgsattributes.h"
28#include "qgsjsonutils.h"
30#include "qgsapplication.h"
31
32#include <QComboBox>
33#include <QLineEdit>
34#include <QStringListModel>
35#include <QCompleter>
36#include <QTimer>
37#include <QVBoxLayout>
38#include <QHeaderView>
39#include <QKeyEvent>
40
41#include <nlohmann/json.hpp>
42using namespace nlohmann;
43
45QgsFilteredTableWidget::QgsFilteredTableWidget( QWidget *parent, bool showSearch )
46 : QWidget( parent )
47{
48 mSearchWidget = new QgsFilterLineEdit( this );
49 mSearchWidget->setShowSearchIcon( true );
50 mSearchWidget->setShowClearButton( true );
51 mTableWidget = new QTableWidget( this );
52 mTableWidget->horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch );
53 mTableWidget->horizontalHeader()->setVisible( false );
54 mTableWidget->verticalHeader()->setSectionResizeMode( QHeaderView::Stretch );
55 mTableWidget->verticalHeader()->setVisible( false );
56 mTableWidget->setShowGrid( false );
57 mTableWidget->setEditTriggers( QAbstractItemView::NoEditTriggers );
58 mTableWidget->setSelectionMode( QAbstractItemView::NoSelection );
59 QVBoxLayout *layout = new QVBoxLayout();
60 layout->addWidget( mSearchWidget );
61 layout->addWidget( mTableWidget );
62 layout->setContentsMargins( 0, 0, 0, 0 );
63 layout->setSpacing( 0 );
64 if ( showSearch )
65 {
66 mTableWidget->setFocusProxy( mSearchWidget );
67 connect( mSearchWidget, &QgsFilterLineEdit::textChanged, this, &QgsFilteredTableWidget::filterStringChanged );
68 installEventFilter( this );
69 }
70 else
71 {
72 mSearchWidget->setVisible( false );
73 }
74 setLayout( layout );
75 connect( mTableWidget, &QTableWidget::itemChanged, this, &QgsFilteredTableWidget::itemChanged_p );
76}
77
78bool QgsFilteredTableWidget::eventFilter( QObject *watched, QEvent *event )
79{
80 Q_UNUSED( watched )
81 if ( event->type() == QEvent::KeyPress )
82 {
83 QKeyEvent *keyEvent = static_cast<QKeyEvent *>( event );
84 if ( keyEvent->key() == Qt::Key_Escape &&
85 !mSearchWidget->text().isEmpty() )
86 {
87 mSearchWidget->clear();
88 return true;
89 }
90 }
91 return false;
92}
93
94void QgsFilteredTableWidget::filterStringChanged( const QString &filterString )
95{
96 auto signalBlockedTableWidget = whileBlocking( mTableWidget );
97 Q_UNUSED( signalBlockedTableWidget )
98 mTableWidget->clearContents();
99 const int rCount = std::max( 1, ( int ) std::ceil( ( float ) mCache.count() / ( float ) mColumnCount ) );
100 mTableWidget->setRowCount( rCount );
101 int row = 0;
102 int column = 0;
103
104 for ( const QPair<QgsValueRelationFieldFormatter::ValueRelationItem, Qt::CheckState> &pair : std::as_const( mCache ) )
105 {
106 if ( column == mColumnCount )
107 {
108 row++;
109 column = 0;
110 }
111 if ( pair.first.value.contains( filterString, Qt::CaseInsensitive ) )
112 {
113 QTableWidgetItem *item = nullptr;
114 item = new QTableWidgetItem( pair.first.value );
115 item->setData( Qt::UserRole, pair.first.key );
116 item->setData( Qt::ToolTipRole, pair.first.description );
117 item->setCheckState( pair.second );
118 item->setFlags( mEnabledTable ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
119 mTableWidget->setItem( row, column, item );
120 column++;
121 }
122 }
123 mTableWidget->setRowCount( row + 1 );
124}
125
126QStringList QgsFilteredTableWidget::selection() const
127{
128 QStringList sel;
129 for ( const QPair<QgsValueRelationFieldFormatter::ValueRelationItem, Qt::CheckState> &pair : std::as_const( mCache ) )
130 {
131 if ( pair.second == Qt::Checked )
132 sel.append( pair.first.key.toString() );
133 }
134 return sel;
135}
136
137void QgsFilteredTableWidget::checkItems( const QStringList &checked )
138{
139 for ( QPair<QgsValueRelationFieldFormatter::ValueRelationItem, Qt::CheckState> &pair : mCache )
140 {
141 const bool isChecked = checked.contains( pair.first.key.toString() );
142 pair.second = isChecked ? Qt::Checked : Qt::Unchecked;
143 }
144
145 filterStringChanged( mSearchWidget->text() );
146}
147
148void QgsFilteredTableWidget::populate( QgsValueRelationFieldFormatter::ValueRelationCache cache )
149{
150 mCache.clear();
151 for ( const QgsValueRelationFieldFormatter::ValueRelationItem &element : std::as_const( cache ) )
152 {
153 mCache.append( qMakePair( element, Qt::Unchecked ) );
154 }
155 filterStringChanged( mSearchWidget->text() );
156}
157
158void QgsFilteredTableWidget::setIndeterminateState()
159{
160 for ( int rowIndex = 0; rowIndex < mTableWidget->rowCount(); rowIndex++ )
161 {
162 for ( int columnIndex = 0; columnIndex < mColumnCount; ++columnIndex )
163 {
164 if ( item( rowIndex, columnIndex ) )
165 {
166 whileBlocking( mTableWidget )->item( rowIndex, columnIndex )->setCheckState( Qt::PartiallyChecked );
167 }
168 else
169 {
170 break;
171 }
172 }
173 }
174}
175
176void QgsFilteredTableWidget::setEnabledTable( const bool enabled )
177{
178 if ( mEnabledTable == enabled )
179 return;
180
181 mEnabledTable = enabled;
182 if ( !enabled )
183 mSearchWidget->clear();
184
185 filterStringChanged( mSearchWidget->text() );
186}
187
188void QgsFilteredTableWidget::setColumnCount( const int count )
189{
190 mColumnCount = count;
191 mTableWidget->setColumnCount( count );
192}
193
194void QgsFilteredTableWidget::itemChanged_p( QTableWidgetItem *item )
195{
196 for ( QPair<QgsValueRelationFieldFormatter::ValueRelationItem, Qt::CheckState> &pair : mCache )
197 {
198 if ( pair.first.key == item->data( Qt::UserRole ) )
199 pair.second = item->checkState();
200 }
201 emit itemChanged( item );
202}
204
205
206QgsValueRelationWidgetWrapper::QgsValueRelationWidgetWrapper( QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent )
207 : QgsEditorWidgetWrapper( layer, fieldIdx, editor, parent )
208{
209}
210
212{
213 QVariant v;
214
215 if ( mComboBox )
216 {
217 int cbxIdx = mComboBox->currentIndex();
218 if ( cbxIdx > -1 )
219 {
220 v = mComboBox->currentData();
221 if ( QgsVariantUtils::isNull( v ) )
222 v = QVariant( field().type() );
223 }
224 }
225 else if ( mTableWidget )
226 {
227 QStringList selection = mTableWidget->selection();
228
229 // If there is no selection and allow NULL is not checked return NULL.
230 if ( selection.isEmpty() && ! config( QStringLiteral( "AllowNull" ) ).toBool( ) )
231 {
232 return QVariant( QVariant::Type::List );
233 }
234
235 QVariantList vl;
236 //store as QVariantList because the field type supports data structure
237 for ( const QString &s : std::as_const( selection ) )
238 {
239 // Convert to proper type
240 const QVariant::Type type { fkType() };
241 switch ( type )
242 {
243 case QVariant::Type::Int:
244 vl.push_back( s.toInt() );
245 break;
246 case QVariant::Type::LongLong:
247 vl.push_back( s.toLongLong() );
248 break;
249 default:
250 vl.push_back( s );
251 break;
252 }
253 }
254
255 if ( layer()->fields().at( fieldIdx() ).type() == QVariant::Map ||
256 layer()->fields().at( fieldIdx() ).type() == QVariant::List )
257 {
258 v = vl;
259 }
260 else
261 {
262 //make string
264 }
265 }
266 else if ( mLineEdit )
267 {
268 for ( const QgsValueRelationFieldFormatter::ValueRelationItem &item : std::as_const( mCache ) )
269 {
270 if ( item.value == mLineEdit->text() )
271 {
272 v = item.key;
273 break;
274 }
275 }
276 }
277
278 return v;
279}
280
282{
283 QgsAttributeForm *form = qobject_cast<QgsAttributeForm *>( parent );
284 if ( form )
286
287 mExpression = config().value( QStringLiteral( "FilterExpression" ) ).toString();
288
289 const bool allowMulti = config( QStringLiteral( "AllowMulti" ) ).toBool();
290 const bool useCompleter = config( QStringLiteral( "UseCompleter" ) ).toBool();
291 if ( allowMulti )
292 {
293 return new QgsFilteredTableWidget( parent, useCompleter );
294 }
295 else if ( useCompleter )
296 {
297 return new QgsFilterLineEdit( parent );
298 }
299 else
300 {
301 QgsToolTipComboBox *combo = new QgsToolTipComboBox( parent );
302 combo->setMinimumContentsLength( 1 );
303 combo->setSizeAdjustPolicy( QComboBox::SizeAdjustPolicy::AdjustToMinimumContentsLengthWithIcon );
304 return combo;
305 }
306}
307
309{
310 mComboBox = qobject_cast<QComboBox *>( editor );
311 mTableWidget = qobject_cast<QgsFilteredTableWidget *>( editor );
312 mLineEdit = qobject_cast<QLineEdit *>( editor );
313
314 // Read current initial form values from the editor context
316
317 if ( mComboBox )
318 {
319 mComboBox->view()->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
320 connect( mComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ),
321 this, static_cast<void ( QgsEditorWidgetWrapper::* )()>( &QgsEditorWidgetWrapper::emitValueChanged ), Qt::UniqueConnection );
322 }
323 else if ( mTableWidget )
324 {
325 connect( mTableWidget, &QgsFilteredTableWidget::itemChanged, this, static_cast<void ( QgsEditorWidgetWrapper::* )()>( &QgsEditorWidgetWrapper::emitValueChanged ), Qt::UniqueConnection );
326 }
327 else if ( mLineEdit )
328 {
329 if ( QgsFilterLineEdit *filterLineEdit = qobject_cast<QgsFilterLineEdit *>( editor ) )
330 {
331 connect( filterLineEdit, &QgsFilterLineEdit::valueChanged, this, [ = ]( const QString & )
332 {
333 if ( mSubWidgetSignalBlocking == 0 )
335 } );
336 }
337 else
338 {
339 connect( mLineEdit, &QLineEdit::textChanged, this, &QgsValueRelationWidgetWrapper::emitValueChangedInternal, Qt::UniqueConnection );
340 }
341 }
342}
343
345{
346 return mTableWidget || mLineEdit || mComboBox;
347}
348
349void QgsValueRelationWidgetWrapper::updateValues( const QVariant &value, const QVariantList & )
350{
351 if ( mTableWidget )
352 {
353 QStringList checkList;
354
355 if ( layer()->fields().at( fieldIdx() ).type() == QVariant::Map ||
356 layer()->fields().at( fieldIdx() ).type() == QVariant::List )
357 {
358 checkList = value.toStringList();
359 }
360 else
361 {
363 }
364
365 mTableWidget->checkItems( checkList );
366 }
367 else if ( mComboBox )
368 {
369 // findData fails to tell a 0 from a NULL
370 // See: "Value relation, value 0 = NULL" - https://github.com/qgis/QGIS/issues/27803
371 int idx = -1; // default to not found
372 for ( int i = 0; i < mComboBox->count(); i++ )
373 {
374 QVariant v( mComboBox->itemData( i ) );
375 if ( qgsVariantEqual( v, value ) )
376 {
377 idx = i;
378 break;
379 }
380 }
381
382 if ( idx == -1 )
383 {
384 // if value doesn't exist, we show it in '(...)' (just like value map widget)
386 {
387 mComboBox->setCurrentIndex( -1 );
388 }
389 else
390 {
391 mComboBox->addItem( value.toString().prepend( '(' ).append( ')' ), value );
392 mComboBox->setCurrentIndex( mComboBox->findData( value ) );
393 }
394 }
395 else
396 {
397 mComboBox->setCurrentIndex( idx );
398 }
399 }
400 else if ( mLineEdit )
401 {
402 mSubWidgetSignalBlocking ++;
403 mLineEdit->clear();
404 bool wasFound { false };
405 for ( const QgsValueRelationFieldFormatter::ValueRelationItem &i : std::as_const( mCache ) )
406 {
407 if ( i.key == value )
408 {
409 mLineEdit->setText( i.value );
410 wasFound = true;
411 break;
412 }
413 }
414 // Value could not be found
415 if ( ! wasFound )
416 {
417 mLineEdit->setText( tr( "(no selection)" ) );
418 }
419 mSubWidgetSignalBlocking --;
420 }
421}
422
423void QgsValueRelationWidgetWrapper::widgetValueChanged( const QString &attribute, const QVariant &newValue, bool attributeChanged )
424{
425
426 // Do nothing if the value has not changed
427 if ( attributeChanged )
428 {
429 QVariant oldValue( value( ) );
430 setFormFeatureAttribute( attribute, newValue );
431 // Update combos if the value used in the filter expression has changed
433 && QgsValueRelationFieldFormatter::expressionFormAttributes( mExpression ).contains( attribute ) )
434 {
435 populate();
436 // Restore value
437 updateValues( value( ) );
438 // If the value has changed as a result of another widget's value change,
439 // we need to emit the signal to make sure other dependent widgets are
440 // updated.
441 QgsFields formFields( formFeature().fields() );
442
443 // Also check for fields in the layer in case this is a multi-edit form
444 // and there is not form feature set
445 if ( formFields.count() == 0 && layer() )
446 {
447 formFields = layer()->fields();
448 }
449
450 if ( oldValue != value() && fieldIdx() < formFields.count() )
451 {
452 QString attributeName( formFields.names().at( fieldIdx() ) );
453 setFormFeatureAttribute( attributeName, value( ) );
455 }
456 }
457 }
458}
459
460
462{
463 setFormFeature( feature );
464 whileBlocking( this )->populate();
465 whileBlocking( this )->setValue( feature.attribute( fieldIdx() ) );
466
467 // As we block any signals, possible depending widgets will not being updated
468 // so we force emit signal once and for all
470
471 // A bit of logic to set the default value if AllowNull is false and this is a new feature
472 // Note that this needs to be here after the cache has been created/updated by populate()
473 // and signals unblocked (we want this to propagate to the feature itself)
474 if ( context().attributeFormMode() != QgsAttributeEditorContext::Mode::MultiEditMode
475 && ! formFeature().attribute( fieldIdx() ).isValid()
476 && ! mCache.isEmpty()
477 && ! config( QStringLiteral( "AllowNull" ) ).toBool( ) )
478 {
479 // This is deferred because at the time the feature is set in one widget it is not
480 // set in the next, which is typically the "down" in a drill-down
481 QTimer::singleShot( 0, this, [ this ]
482 {
483 if ( ! mCache.isEmpty() )
484 {
485 updateValues( formFeature().attribute( fieldIdx() ).isValid() ? formFeature().attribute( fieldIdx() ) : mCache.at( 0 ).key );
486 }
487 } );
488 }
489}
490
491int QgsValueRelationWidgetWrapper::columnCount() const
492{
493 return std::max( 1, config( QStringLiteral( "NofColumns" ) ).toInt() );
494}
495
496
497QVariant::Type QgsValueRelationWidgetWrapper::fkType() const
498{
500 if ( layer )
501 {
502 QgsFields fields = layer->fields();
503 int idx { fields.lookupField( config().value( QStringLiteral( "Key" ) ).toString() ) };
504 if ( idx >= 0 )
505 {
506 return fields.at( idx ).type();
507 }
508 }
509 return QVariant::Type::Invalid;
510}
511
512void QgsValueRelationWidgetWrapper::populate()
513{
514 // Initialize, note that signals are blocked, to avoid double signals on new features
517 {
518 if ( context().parentFormFeature().isValid() )
519 {
520 mCache = QgsValueRelationFieldFormatter::createCache( config(), formFeature(), context().parentFormFeature() );
521 }
522 else
523 {
525 }
526 }
527 else if ( mCache.empty() )
528 {
530 }
531
532 if ( mComboBox )
533 {
534 whileBlocking( mComboBox )->clear();
535 if ( config( QStringLiteral( "AllowNull" ) ).toBool( ) )
536 {
537 whileBlocking( mComboBox )->addItem( tr( "(no selection)" ), QVariant( field().type( ) ) );
538 }
539
540 for ( const QgsValueRelationFieldFormatter::ValueRelationItem &element : std::as_const( mCache ) )
541 {
542 whileBlocking( mComboBox )->addItem( element.value, element.key );
543 if ( !element.description.isEmpty() )
544 mComboBox->setItemData( mComboBox->count() - 1, element.description, Qt::ToolTipRole );
545 }
546
547 }
548 else if ( mTableWidget )
549 {
550 mTableWidget->setColumnCount( columnCount() );
551 mTableWidget->populate( mCache );
552 }
553 else if ( mLineEdit )
554 {
555 QStringList values;
556 values.reserve( mCache.size() );
557 for ( const QgsValueRelationFieldFormatter::ValueRelationItem &i : std::as_const( mCache ) )
558 {
559 values << i.value;
560 }
561 QStringListModel *m = new QStringListModel( values, mLineEdit );
562 QCompleter *completer = new QCompleter( m, mLineEdit );
563 completer->setCaseSensitivity( Qt::CaseInsensitive );
564 mLineEdit->setCompleter( completer );
565 }
566}
567
569{
570 if ( mTableWidget )
571 {
572 mTableWidget->setIndeterminateState();
573 }
574 else if ( mComboBox )
575 {
576 whileBlocking( mComboBox )->setCurrentIndex( -1 );
577 }
578 else if ( mLineEdit )
579 {
580 whileBlocking( mLineEdit )->clear();
581 }
582}
583
585{
586 if ( mEnabled == enabled )
587 return;
588
589 mEnabled = enabled;
590
591 if ( mTableWidget )
592 {
593 mTableWidget->setEnabledTable( enabled );
594 }
595 else
597}
598
599void QgsValueRelationWidgetWrapper::parentFormValueChanged( const QString &attribute, const QVariant &value )
600{
601
602 // Update the parent feature in the context ( which means to replace the whole context :/ )
604 QgsFeature feature { context().parentFormFeature() };
605 feature.setAttribute( attribute, value );
606 ctx.setParentFormFeature( feature );
607 setContext( ctx );
608
609 // Check if the change might affect the filter expression and the cache needs updates
611 && ( config( QStringLiteral( "Value" ) ).toString() == attribute ||
612 config( QStringLiteral( "Key" ) ).toString() == attribute ||
614 QgsValueRelationFieldFormatter::expressionParentFormAttributes( mExpression ).contains( attribute ) ) )
615 {
616 populate();
617 }
618
619}
620
621void QgsValueRelationWidgetWrapper::emitValueChangedInternal( const QString &value )
622{
624 emit valueChanged( value );
626 emit valuesChanged( value );
627}
This class contains context information for attribute editor widgets.
QgsFeature parentFormFeature() const
Returns the feature of the currently edited parent form in its actual state.
@ MultiEditMode
Multi edit mode, for editing fields of multiple features at once.
void widgetValueChanged(const QString &attribute, const QVariant &value, bool attributeChanged)
Notifies about changes of attributes.
Manages an editor widget Widget and wrapper share the same parent.
QgsFeature formFeature() const
The feature currently being edited, in its current state.
Q_DECL_DEPRECATED void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
void setFormFeature(const QgsFeature &feature)
Set the feature currently being edited to feature.
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.
bool setFormFeatureAttribute(const QString &attributeName, const QVariant &attributeValue)
Update the feature currently being edited by changing its attribute attributeName to attributeValue.
void emitValueChanged()
Will call the value() method to determine the emitted value.
QgsField field() const
Access the field.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:56
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
QVariant::Type type
Definition qgsfield.h:60
Container of fields for a vector layer.
Definition qgsfields.h:45
int count() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
QStringList names() const
Returns a list with field names.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
void valueChanged(const QString &value)
Same as textChanged() but with support for null values.
static QString buildArray(const QVariantList &list)
Build a postgres array like formatted list in a string from a QVariantList.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QComboBox subclass which features a tooltip when mouse hovering the combobox.
static QgsVectorLayer * resolveLayer(const QVariantMap &config, const QgsProject *project)
Returns the (possibly NULL) layer from the widget's config and project.
static bool expressionRequiresFormScope(const QString &expression)
Check if the expression requires a form scope (i.e.
static bool expressionRequiresParentFormScope(const QString &expression)
Check if the expression requires a parent form scope (i.e.
QVariant createCache(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config) const override
Create a cache for a given field.
static QSet< QString > expressionParentFormVariables(const QString &expression)
Returns a list of variables required by the parent form's form context expression.
static QSet< QString > expressionParentFormAttributes(const QString &expression)
Returns a list of attributes required by the parent form's form context expression.
static QStringList valueToStringList(const QVariant &value)
Utility to convert a list or a string representation of an (hstore style: {1,2...}) list in value to ...
static QSet< QString > expressionFormAttributes(const QString &expression)
Returns a list of attributes required by the form context expression.
QVector< QgsValueRelationFieldFormatter::ValueRelationItem > ValueRelationCache
QVariant value() const override
Will be used to access the widget's value.
bool valid() const override
Returns true if the widget has been properly initialized.
void showIndeterminateState() override
Sets the widget to display in an indeterminate "mixed value" state.
void parentFormValueChanged(const QString &attribute, const QVariant &value) override
QgsValueRelationWidgetWrapper(QgsVectorLayer *layer, int fieldIdx, QWidget *editor=nullptr, QWidget *parent=nullptr)
Constructor for QgsValueRelationWidgetWrapper.
void setEnabled(bool enabled) override
Is used to enable or disable the edit functionality of the managed widget.
void widgetValueChanged(const QString &attribute, const QVariant &newValue, bool attributeChanged)
Will be called when a value in the current edited form or table row changes.
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
void setFeature(const QgsFeature &feature) override
Will be called when the feature changes.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
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.
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
void setContext(const QgsAttributeEditorContext &context)
Set the context in which this widget is shown.
QVariantMap config() const
Returns the whole config.
bool qgsVariantEqual(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether they are equal, two NULL values are always treated a...
Definition qgis.cpp:247
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:5713
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:5712
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:5048