QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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"
29 #include "qgspostgresstringutils.h"
30 
31 #include <QHeaderView>
32 #include <QComboBox>
33 #include <QLineEdit>
34 #include <QTableWidget>
35 #include <QStringListModel>
36 #include <QCompleter>
37 
38 #include <nlohmann/json.hpp>
39 using namespace nlohmann;
40 
41 
42 QgsValueRelationWidgetWrapper::QgsValueRelationWidgetWrapper( QgsVectorLayer *layer, int fieldIdx, QWidget *editor, QWidget *parent )
43  : QgsEditorWidgetWrapper( layer, fieldIdx, editor, parent )
44 {
45 }
46 
47 
49 {
50  QVariant v;
51 
52  if ( mComboBox )
53  {
54  int cbxIdx = mComboBox->currentIndex();
55  if ( cbxIdx > -1 )
56  {
57  v = mComboBox->currentData();
58  }
59  }
60 
61  const int nofColumns = columnCount();
62 
63  if ( mTableWidget )
64  {
65  QStringList selection;
66  for ( int j = 0; j < mTableWidget->rowCount(); j++ )
67  {
68  for ( int i = 0; i < nofColumns; ++i )
69  {
70  QTableWidgetItem *item = mTableWidget->item( j, i );
71  if ( item )
72  {
73  if ( item->checkState() == Qt::Checked )
74  selection << item->data( Qt::UserRole ).toString();
75  }
76  }
77  }
78 
79  QVariantList vl;
80  //store as QVariantList because the field type supports data structure
81  for ( const QString &s : qgis::as_const( selection ) )
82  {
83  // Convert to proper type
84  const QVariant::Type type { fkType() };
85  switch ( type )
86  {
87  case QVariant::Type::Int:
88  vl.push_back( s.toInt() );
89  break;
90  case QVariant::Type::LongLong:
91  vl.push_back( s.toLongLong() );
92  break;
93  default:
94  vl.push_back( s );
95  break;
96  }
97  }
98 
99  if ( layer()->fields().at( fieldIdx() ).type() == QVariant::Map ||
100  layer()->fields().at( fieldIdx() ).type() == QVariant::List )
101  {
102  v = vl;
103  }
104  else
105  {
106  //make string
108  }
109  }
110 
111  if ( mLineEdit )
112  {
113  for ( const QgsValueRelationFieldFormatter::ValueRelationItem &item : qgis::as_const( mCache ) )
114  {
115  if ( item.value == mLineEdit->text() )
116  {
117  v = item.key;
118  break;
119  }
120  }
121  }
122 
123  return v;
124 }
125 
127 {
128  QgsAttributeForm *form = qobject_cast<QgsAttributeForm *>( parent );
129  if ( form )
131 
132  mExpression = config().value( QStringLiteral( "FilterExpression" ) ).toString();
133 
134  if ( config( QStringLiteral( "AllowMulti" ) ).toBool() )
135  {
136  return new QTableWidget( parent );
137  }
138  else if ( config( QStringLiteral( "UseCompleter" ) ).toBool() )
139  {
140  return new QgsFilterLineEdit( parent );
141  }
142  else
143  {
144  return new QComboBox( parent );
145  }
146 }
147 
149 {
150 
151  mComboBox = qobject_cast<QComboBox *>( editor );
152  mTableWidget = qobject_cast<QTableWidget *>( editor );
153  mLineEdit = qobject_cast<QLineEdit *>( editor );
154 
155  // Read current initial form values from the editor context
157 
158  if ( mComboBox )
159  {
160  connect( mComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ),
161  this, static_cast<void ( QgsEditorWidgetWrapper::* )()>( &QgsEditorWidgetWrapper::emitValueChanged ), Qt::UniqueConnection );
162  }
163  else if ( mTableWidget )
164  {
165  mTableWidget->horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch );
166  mTableWidget->horizontalHeader()->setVisible( false );
167  mTableWidget->verticalHeader()->setSectionResizeMode( QHeaderView::Stretch );
168  mTableWidget->verticalHeader()->setVisible( false );
169  mTableWidget->setShowGrid( false );
170  mTableWidget->setEditTriggers( QAbstractItemView::NoEditTriggers );
171  mTableWidget->setSelectionMode( QAbstractItemView::NoSelection );
172  connect( mTableWidget, &QTableWidget::itemChanged, this, static_cast<void ( QgsEditorWidgetWrapper::* )()>( &QgsEditorWidgetWrapper::emitValueChanged ), Qt::UniqueConnection );
173  }
174  else if ( mLineEdit )
175  {
176  connect( mLineEdit, &QLineEdit::textChanged, this, &QgsValueRelationWidgetWrapper::emitValueChangedInternal, Qt::UniqueConnection );
177  }
178 }
179 
181 {
182  return mTableWidget || mLineEdit || mComboBox;
183 }
184 
185 void QgsValueRelationWidgetWrapper::updateValues( const QVariant &value, const QVariantList & )
186 {
187  if ( mTableWidget )
188  {
189  QStringList checkList;
190 
191  if ( layer()->fields().at( fieldIdx() ).type() == QVariant::Map ||
192  layer()->fields().at( fieldIdx() ).type() == QVariant::List )
193  {
194  checkList = value.toStringList();
195  }
196  else
197  {
199  }
200 
201  QTableWidgetItem *lastChangedItem = nullptr;
202 
203  const int nofColumns = columnCount();
204 
205  // This block is needed because item->setCheckState triggers dataChanged gets back to value()
206  // and iterate over all items again! This can be extremely slow on large items sets.
207  for ( int j = 0; j < mTableWidget->rowCount(); j++ )
208  {
209  auto signalBlockedTableWidget = whileBlocking( mTableWidget );
210  Q_UNUSED( signalBlockedTableWidget )
211 
212  for ( int i = 0; i < nofColumns; ++i )
213  {
214  QTableWidgetItem *item = mTableWidget->item( j, i );
215  if ( item )
216  {
217  item->setCheckState( checkList.contains( item->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
218  //re-set enabled state because it's lost after reloading items
219  item->setFlags( mEnabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
220  lastChangedItem = item;
221  }
222  }
223  }
224  // let's trigger the signal now, once and for all
225  if ( lastChangedItem )
226  lastChangedItem->setCheckState( checkList.contains( lastChangedItem->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
227 
228  }
229  else if ( mComboBox )
230  {
231  // findData fails to tell a 0 from a NULL
232  // See: "Value relation, value 0 = NULL" - https://github.com/qgis/QGIS/issues/27803
233  int idx = -1; // default to not found
234  for ( int i = 0; i < mComboBox->count(); i++ )
235  {
236  QVariant v( mComboBox->itemData( i ) );
237  if ( qgsVariantEqual( v, value ) )
238  {
239  idx = i;
240  break;
241  }
242  }
243  mComboBox->setCurrentIndex( idx );
244  }
245  else if ( mLineEdit )
246  {
247  mLineEdit->clear();
248  bool wasFound { false };
249  for ( const QgsValueRelationFieldFormatter::ValueRelationItem &i : qgis::as_const( mCache ) )
250  {
251  if ( i.key == value )
252  {
253  mLineEdit->setText( i.value );
254  wasFound = true;
255  break;
256  }
257  }
258  // Value could not be found
259  if ( ! wasFound )
260  {
261  mLineEdit->setText( tr( "(no selection)" ) );
262  }
263  }
264 }
265 
266 void QgsValueRelationWidgetWrapper::widgetValueChanged( const QString &attribute, const QVariant &newValue, bool attributeChanged )
267 {
268 
269  // Do nothing if the value has not changed
270  if ( attributeChanged )
271  {
272  QVariant oldValue( value( ) );
273  setFormFeatureAttribute( attribute, newValue );
274  // Update combos if the value used in the filter expression has changed
276  && QgsValueRelationFieldFormatter::expressionFormAttributes( mExpression ).contains( attribute ) )
277  {
278  populate();
279  // Restore value
280  updateValues( value( ) );
281  // If the value has changed as a result of another widget's value change,
282  // we need to emit the signal to make sure other dependent widgets are
283  // updated.
284  if ( oldValue != value() && fieldIdx() < formFeature().fields().count() )
285  {
286  QString attributeName( formFeature().fields().names().at( fieldIdx() ) );
287  setFormFeatureAttribute( attributeName, value( ) );
289  }
290  }
291  }
292 }
293 
294 
296 {
297  setFormFeature( feature );
298  whileBlocking( this )->populate();
299  whileBlocking( this )->setValue( feature.attribute( fieldIdx() ) );
300 
301  // As we block any signals, possible depending widgets will not being updated
302  // so we force emit signal once and for all
304 
305  // A bit of logic to set the default value if AllowNull is false and this is a new feature
306  // Note that this needs to be here after the cache has been created/updated by populate()
307  // and signals unblocked (we want this to propagate to the feature itself)
308  if ( formFeature().isValid()
309  && ! formFeature().attribute( fieldIdx() ).isValid()
310  && ! mCache.isEmpty()
311  && ! config( QStringLiteral( "AllowNull" ) ).toBool( ) )
312  {
313  // This is deferred because at the time the feature is set in one widget it is not
314  // set in the next, which is typically the "down" in a drill-down
315  QTimer::singleShot( 0, this, [ this ]
316  {
317  if ( ! mCache.isEmpty() )
318  {
319  updateValues( mCache.at( 0 ).key );
320  }
321  } );
322  }
323 }
324 
325 int QgsValueRelationWidgetWrapper::columnCount() const
326 {
327  return std::max( 1, config( QStringLiteral( "NofColumns" ) ).toInt() );
328 }
329 
330 
331 QVariant::Type QgsValueRelationWidgetWrapper::fkType() const
332 {
334  if ( layer )
335  {
336  QgsFields fields = layer->fields();
337  int idx { fields.lookupField( config().value( QStringLiteral( "Key" ) ).toString() ) };
338  if ( idx >= 0 )
339  {
340  return fields.at( idx ).type();
341  }
342  }
343  return QVariant::Type::Invalid;
344 }
345 
346 void QgsValueRelationWidgetWrapper::populate( )
347 {
348  // Initialize, note that signals are blocked, to avoid double signals on new features
351  {
352  if ( context().parentFormFeature().isValid() )
353  {
354  mCache = QgsValueRelationFieldFormatter::createCache( config(), formFeature(), context().parentFormFeature() );
355  }
356  else
357  {
359  }
360  }
361  else if ( mCache.empty() )
362  {
364  }
365 
366  if ( mComboBox )
367  {
368  mComboBox->clear();
369  if ( config( QStringLiteral( "AllowNull" ) ).toBool( ) )
370  {
371  whileBlocking( mComboBox )->addItem( tr( "(no selection)" ), QVariant( field().type( ) ) );
372  }
373 
374  for ( const QgsValueRelationFieldFormatter::ValueRelationItem &element : qgis::as_const( mCache ) )
375  {
376  whileBlocking( mComboBox )->addItem( element.value, element.key );
377  if ( !element.description.isEmpty() )
378  mComboBox->setItemData( mComboBox->count() - 1, element.description, Qt::ToolTipRole );
379  }
380 
381  }
382  else if ( mTableWidget )
383  {
384  const int nofColumns = columnCount();
385 
386  if ( ! mCache.empty() )
387  {
388  mTableWidget->setRowCount( ( mCache.size() + nofColumns - 1 ) / nofColumns );
389  }
390  else
391  mTableWidget->setRowCount( 1 );
392  mTableWidget->setColumnCount( nofColumns );
393 
394  whileBlocking( mTableWidget )->clear();
395  int row = 0;
396  int column = 0;
397  for ( const QgsValueRelationFieldFormatter::ValueRelationItem &element : qgis::as_const( mCache ) )
398  {
399  if ( column == nofColumns )
400  {
401  row++;
402  column = 0;
403  }
404  QTableWidgetItem *item = nullptr;
405  item = new QTableWidgetItem( element.value );
406  item->setData( Qt::UserRole, element.key );
407  whileBlocking( mTableWidget )->setItem( row, column, item );
408  column++;
409  }
410 
411  }
412  else if ( mLineEdit )
413  {
414  QStringList values;
415  values.reserve( mCache.size() );
416  for ( const QgsValueRelationFieldFormatter::ValueRelationItem &i : qgis::as_const( mCache ) )
417  {
418  values << i.value;
419  }
420  QStringListModel *m = new QStringListModel( values, mLineEdit );
421  QCompleter *completer = new QCompleter( m, mLineEdit );
422  completer->setCaseSensitivity( Qt::CaseInsensitive );
423  mLineEdit->setCompleter( completer );
424  }
425 }
426 
428 {
429  const int nofColumns = columnCount();
430 
431  if ( mTableWidget )
432  {
433  for ( int j = 0; j < mTableWidget->rowCount(); j++ )
434  {
435  for ( int i = 0; i < nofColumns; ++i )
436  {
437  whileBlocking( mTableWidget )->item( j, i )->setCheckState( Qt::PartiallyChecked );
438  }
439  }
440  }
441  else if ( mComboBox )
442  {
443  whileBlocking( mComboBox )->setCurrentIndex( -1 );
444  }
445  else if ( mLineEdit )
446  {
447  whileBlocking( mLineEdit )->clear();
448  }
449 }
450 
452 {
453  if ( mEnabled == enabled )
454  return;
455 
456  mEnabled = enabled;
457 
458  if ( mTableWidget )
459  {
460  auto signalBlockedTableWidget = whileBlocking( mTableWidget );
461  Q_UNUSED( signalBlockedTableWidget )
462 
463  for ( int j = 0; j < mTableWidget->rowCount(); j++ )
464  {
465  for ( int i = 0; i < mTableWidget->columnCount(); ++i )
466  {
467  QTableWidgetItem *item = mTableWidget->item( j, i );
468  if ( item )
469  {
470  item->setFlags( enabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
471  }
472  }
473  }
474  }
475  else
477 }
478 
479 void QgsValueRelationWidgetWrapper::parentFormValueChanged( const QString &attribute, const QVariant &value )
480 {
481 
482  // Update the parent feature in the context ( which means to replace the whole context :/ )
484  QgsFeature feature { context().parentFormFeature() };
485  feature.setAttribute( attribute, value );
486  ctx.setParentFormFeature( feature );
487  setContext( ctx );
488 
489  // Check if the change might affect the filter expression and the cache needs updates
491  && ( config( QStringLiteral( "Value" ) ).toString() == attribute ||
492  config( QStringLiteral( "Key" ) ).toString() == attribute ||
494  QgsValueRelationFieldFormatter::expressionParentFormAttributes( mExpression ).contains( attribute ) ) )
495  {
496  populate();
497  }
498 
499 }
500 
501 void QgsValueRelationWidgetWrapper::emitValueChangedInternal( const QString &value )
502 {
504  emit valueChanged( value );
506  emit valuesChanged( value );
507 }
qgsfields.h
QgsPostgresStringUtils::buildArray
static QString buildArray(const QVariantList &list)
Build a postgres array like formatted list in a string from a QVariantList.
Definition: qgspostgresstringutils.cpp:119
qgsvaluerelationfieldformatter.h
qgsattributeform.h
QgsValueRelationFieldFormatter::valueToStringList
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 ...
Definition: qgsvaluerelationfieldformatter.cpp:228
qgspostgresstringutils.h
QgsEditorWidgetWrapper::setFormFeatureAttribute
bool setFormFeatureAttribute(const QString &attributeName, const QVariant &attributeValue)
Update the feature currently being edited by changing its attribute attributeName to attributeValue.
Definition: qgseditorwidgetwrapper.cpp:130
QgsValueRelationWidgetWrapper::value
QVariant value() const override
Will be used to access the widget's value.
Definition: qgsvaluerelationwidgetwrapper.cpp:48
QgsValueRelationWidgetWrapper::setFeature
void setFeature(const QgsFeature &feature) override
Will be called when the feature changes.
Definition: qgsvaluerelationwidgetwrapper.cpp:295
qgsfeatureiterator.h
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
qgsfilterlineedit.h
QgsFilterLineEdit
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
Definition: qgsfilterlineedit.h:40
qgis.h
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
QgsValueRelationFieldFormatter::expressionParentFormVariables
static QSet< QString > expressionParentFormVariables(const QString &expression)
Returns a list of variables required by the parent form's form context expression.
Definition: qgsvaluerelationfieldformatter.cpp:300
QgsValueRelationWidgetWrapper::valid
bool valid() const override
Returns true if the widget has been properly initialized.
Definition: qgsvaluerelationwidgetwrapper.cpp:180
QgsValueRelationFieldFormatter::expressionRequiresParentFormScope
static bool expressionRequiresParentFormScope(const QString &expression)
Check if the expression requires a parent form scope (i.e.
Definition: qgsvaluerelationfieldformatter.cpp:314
QgsValueRelationFieldFormatter::expressionFormAttributes
static QSet< QString > expressionFormAttributes(const QString &expression)
Returns a list of attributes required by the form context expression.
Definition: qgsvaluerelationfieldformatter.cpp:343
QgsValueRelationWidgetWrapper::showIndeterminateState
void showIndeterminateState() override
Sets the widget to display in an indeterminate "mixed value" state.
Definition: qgsvaluerelationwidgetwrapper.cpp:427
QgsWidgetWrapper::context
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
Definition: qgswidgetwrapper.cpp:86
QgsEditorWidgetWrapper
Manages an editor widget Widget and wrapper share the same parent.
Definition: qgseditorwidgetwrapper.h:48
QgsValueRelationWidgetWrapper::widgetValueChanged
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.
Definition: qgsvaluerelationwidgetwrapper.cpp:266
QgsEditorWidgetWrapper::fieldIdx
int fieldIdx() const
Access the field index.
Definition: qgseditorwidgetwrapper.cpp:34
QgsEditorWidgetWrapper::valueChanged
Q_DECL_DEPRECATED void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3283
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:797
QgsWidgetWrapper::layer
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Definition: qgswidgetwrapper.cpp:91
whileBlocking
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:262
QgsValueRelationWidgetWrapper::initWidget
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
Definition: qgsvaluerelationwidgetwrapper.cpp:148
QgsEditorWidgetWrapper::field
QgsField field() const
Access the field.
Definition: qgseditorwidgetwrapper.cpp:39
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:264
QgsEditorWidgetWrapper::emitValueChanged
void emitValueChanged()
Will call the value() method to determine the emitted value.
Definition: qgseditorwidgetwrapper.cpp:91
QgsAttributeEditorContext::parentFormFeature
QgsFeature parentFormFeature() const
Returns the feature of the currently edited parent form in its actual state.
Definition: qgsattributeeditorcontext.h:251
qgsvaluerelationwidgetwrapper.h
QgsValueRelationFieldFormatter::resolveLayer
static QgsVectorLayer * resolveLayer(const QVariantMap &config, const QgsProject *project)
Returns the (possibly NULL) layer from the widget's config and project.
Definition: qgsvaluerelationfieldformatter.cpp:395
qgsvectorlayer.h
QgsEditorWidgetWrapper::setFormFeature
void setFormFeature(const QgsFeature &feature)
Set the feature currently being edited to feature.
Definition: qgseditorwidgetwrapper.h:353
QgsFeature::setAttribute
bool setAttribute(int field, const QVariant &attr)
Set an attribute's value by field index.
Definition: qgsfeature.cpp:213
QgsEditorWidgetWrapper::valuesChanged
void valuesChanged(const QVariant &value, const QVariantList &additionalFieldValues=QVariantList())
Emit this signal, whenever the value changed.
QgsValueRelationWidgetWrapper::parentFormValueChanged
void parentFormValueChanged(const QString &attribute, const QVariant &value) override
Definition: qgsvaluerelationwidgetwrapper.cpp:479
qgsattributes.h
QgsValueRelationWidgetWrapper::setEnabled
void setEnabled(bool enabled) override
Is used to enable or disable the edit functionality of the managed widget.
Definition: qgsvaluerelationwidgetwrapper.cpp:451
QgsWidgetWrapper::config
QVariantMap config() const
Returns the whole config.
Definition: qgswidgetwrapper.cpp:81
qgsVariantEqual
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:265
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsValueRelationFieldFormatter::createCache
QVariant createCache(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config) const override
Create a cache for a given field.
Definition: qgsvaluerelationfieldformatter.cpp:116
QgsValueRelationWidgetWrapper::createWidget
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
Definition: qgsvaluerelationwidgetwrapper.cpp:126
QgsEditorWidgetWrapper::setEnabled
void setEnabled(bool enabled) override
Is used to enable or disable the edit functionality of the managed widget.
Definition: qgseditorwidgetwrapper.cpp:60
QgsValueRelationFieldFormatter::expressionRequiresFormScope
static bool expressionRequiresFormScope(const QString &expression)
Check if the expression requires a form scope (i.e.
Definition: qgsvaluerelationfieldformatter.cpp:309
qgsvaluerelationwidgetfactory.h
QgsAttributeForm::widgetValueChanged
void widgetValueChanged(const QString &attribute, const QVariant &value, bool attributeChanged)
Notifies about changes of attributes.
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsValueRelationWidgetWrapper::QgsValueRelationWidgetWrapper
QgsValueRelationWidgetWrapper(QgsVectorLayer *layer, int fieldIdx, QWidget *editor=nullptr, QWidget *parent=nullptr)
Constructor for QgsValueRelationWidgetWrapper.
Definition: qgsvaluerelationwidgetwrapper.cpp:42
QgsAttributeForm
Definition: qgsattributeform.h:45
QgsValueRelationFieldFormatter::expressionParentFormAttributes
static QSet< QString > expressionParentFormAttributes(const QString &expression)
Returns a list of attributes required by the parent form's form context expression.
Definition: qgsvaluerelationfieldformatter.cpp:319
qgsjsonutils.h
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
QgsFields::at
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
QgsAttributeEditorContext
This class contains context information for attribute editor widgets.
Definition: qgsattributeeditorcontext.h:41
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:796
QgsWidgetWrapper::setContext
void setContext(const QgsAttributeEditorContext &context)
Set the context in which this widget is shown.
Definition: qgswidgetwrapper.cpp:66
QgsValueRelationFieldFormatter::ValueRelationItem
Definition: qgsvaluerelationfieldformatter.h:40
qgsproject.h
QgsField::type
QVariant::Type type
Definition: qgsfield.h:57
QgsEditorWidgetWrapper::formFeature
QgsFeature formFeature() const
The feature currently being edited, in its current state.
Definition: qgseditorwidgetwrapper.h:346