75int QgsAttributeForm::sFormCounter = 0;
 
   80  , mOwnsMessageBar( true )
 
   82  , mFormNr( sFormCounter++ )
 
   84  , mPreventFeatureRefresh( false )
 
   85  , mIsSettingMultiEditFeatures( false )
 
   86  , mUnsavedMultiEditChanges( false )
 
   87  , mEditCommandMessage( tr( 
"Attributes changed" ) )
 
  100  updateContainersVisibility();
 
  102  updateEditableState();
 
  109  qDeleteAll( mInterfaces );
 
  136  mInterfaces.append( iface );
 
  152    if ( mUnsavedMultiEditChanges )
 
  155      int res = QMessageBox::question( 
this, tr( 
"Multiedit Attributes" ),
 
  156                                       tr( 
"Apply changes to edited features?" ), QMessageBox::Yes | QMessageBox::No );
 
  157      if ( res == QMessageBox::Yes )
 
  162    clearMultiEditMessages();
 
  164  mUnsavedMultiEditChanges = 
false;
 
  216    w->setContext( newContext );
 
  222    w->setVisible( relationWidgetsVisible );
 
  229      mSearchButtonBox->setVisible( 
false );
 
  234      mSearchButtonBox->setVisible( 
false );
 
  239      mSearchButtonBox->setVisible( 
false );
 
  243      resetMultiEdit( 
false );
 
  245      mSearchButtonBox->setVisible( 
false );
 
  249      mSearchButtonBox->setVisible( 
true );
 
  255      mSearchButtonBox->setVisible( 
false );
 
  263      mSearchButtonBox->setVisible( 
false );
 
  272  const auto constMWidgets = mWidgets;
 
  287        QVariant mainValue = eww->
value();
 
  289        additionalFieldValues[index] = value;
 
  290        eww->
setValues( mainValue, additionalFieldValues );
 
  304  mIsSettingFeature = 
true;
 
  321      mIsSettingFeature = 
false;
 
  322      const auto constMInterfaces = mInterfaces;
 
  325        iface->featureChanged();
 
  341  mIsSettingFeature = 
false;
 
  344bool QgsAttributeForm::saveEdits( QString *error )
 
  347  bool changedLayer = 
false;
 
  352    bool doUpdate = 
false;
 
  372            *error = tr( 
"JSON value for %1 is invalid and has not been saved" ).arg( eww->
field().
name() );
 
  375        QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
 
  376        QVariantList srcVars = QVariantList() << eww->
value();
 
  377        QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
  381        for ( 
const QString &fieldName : additionalFields )
 
  385          dstVars << dst.at( idx );
 
  389        Q_ASSERT( dstVars.count() == srcVars.count() );
 
  391        for ( 
int i = 0; i < dstVars.count(); i++ )
 
  394          if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() )
 
  396            dst[fieldIndexes[i]] = srcVars[i];
 
  406    const auto constMInterfaces = mInterfaces;
 
  409      if ( !iface->acceptChanges( updatedFeature ) )
 
  419        mFeature = updatedFeature;
 
  425        bool res = mLayer->
addFeature( updatedFeature );
 
  444        for ( 
int i = 0; i < dst.count(); ++i )
 
  447               || !dst.at( i ).isValid()                 
 
  448               || !fieldIsEditable( i ) )                
 
  454          QgsDebugMsgLevel( QStringLiteral( 
"dst:'%1' (type:%2, isNull:%3, isValid:%4)" )
 
  455                            .arg( dst.at( i ).toString(), dst.at( i ).typeName() ).arg( 
QgsVariantUtils::isNull( dst.at( i ) ) ).arg( dst.at( i ).isValid() ), 2 );
 
  456          QgsDebugMsgLevel( QStringLiteral( 
"src:'%1' (type:%2, isNull:%3, isValid:%4)" )
 
  457                            .arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( 
QgsVariantUtils::isNull( src.at( i ) ) ).arg( src.at( i ).isValid() ), 2 );
 
  459          newValues[i] = dst.at( i );
 
  460          oldValues[i] = src.at( i );
 
  467        if ( success && n > 0 )
 
  494QgsFeature QgsAttributeForm::getUpdatedFeature()
 const 
  506    QVariantList dstVars = QVariantList() << featureAttributes.at( eww->
fieldIdx() );
 
  507    QVariantList srcVars = QVariantList() << eww->
value();
 
  508    QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
  512    for ( 
const QString &fieldName : additionalFields )
 
  516      dstVars << featureAttributes.at( idx );
 
  520    Q_ASSERT( dstVars.count() == srcVars.count() );
 
  522    for ( 
int i = 0; i < dstVars.count(); i++ )
 
  524      if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() )
 
  525        featureAttributes[fieldIndexes[i]] = srcVars[i];
 
  530  return updatedFeature;
 
  533void QgsAttributeForm::updateValuesDependencies( 
const int originIdx )
 
  535  updateValuesDependenciesDefaultValues( originIdx );
 
  536  updateValuesDependenciesVirtualFields( originIdx );
 
  539void QgsAttributeForm::updateValuesDependenciesDefaultValues( 
const int originIdx )
 
  541  if ( !mDefaultValueDependencies.contains( originIdx ) )
 
  549  QgsFeature updatedFeature = getUpdatedFeature();
 
  552  QList<QgsWidgetWrapper *> relevantWidgets = mDefaultValueDependencies.values( originIdx );
 
  569      if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
 
  580void QgsAttributeForm::updateValuesDependenciesVirtualFields( 
const int originIdx )
 
  582  if ( !mVirtualFieldsDependencies.contains( originIdx ) )
 
  589  QgsFeature updatedFeature = getUpdatedFeature();
 
  592  const QList<QgsWidgetWrapper *> relevantWidgets = mVirtualFieldsDependencies.values( originIdx );
 
  600    if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
 
  606    const QVariant value = exp.evaluate( &context );
 
  612void QgsAttributeForm::updateRelatedLayerFields()
 
  615  updateRelatedLayerFieldsDependencies();
 
  617  if ( mRelatedLayerFieldsDependencies.isEmpty() )
 
  624  QgsFeature updatedFeature = getUpdatedFeature();
 
  627  const QSet<QgsEditorWidgetWrapper *> relevantWidgets = mRelatedLayerFieldsDependencies;
 
  631    if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
 
  637    QVariant value = exp.evaluate( &context );
 
  642void QgsAttributeForm::resetMultiEdit( 
bool promptToSave )
 
  647  mUnsavedMultiEditChanges = 
false;
 
  651void QgsAttributeForm::multiEditMessageClicked( 
const QString &link )
 
  653  clearMultiEditMessages();
 
  654  resetMultiEdit( link == QLatin1String( 
"#apply" ) );
 
  657void QgsAttributeForm::filterTriggered()
 
  659  QString filter = createFilterExpression();
 
  665void QgsAttributeForm::searchZoomTo()
 
  667  QString filter = createFilterExpression();
 
  668  if ( filter.isEmpty() )
 
  674void QgsAttributeForm::searchFlash()
 
  676  QString filter = createFilterExpression();
 
  677  if ( filter.isEmpty() )
 
  683void QgsAttributeForm::filterAndTriggered()
 
  685  QString filter = createFilterExpression();
 
  686  if ( filter.isEmpty() )
 
  694void QgsAttributeForm::filterOrTriggered()
 
  696  QString filter = createFilterExpression();
 
  697  if ( filter.isEmpty() )
 
  705void QgsAttributeForm::pushSelectedFeaturesMessage()
 
  711                              tr( 
"%n matching feature(s) selected", 
"matching features", count ),
 
  712                              Qgis::MessageLevel::Info );
 
  717                              tr( 
"No matching features found" ),
 
  718                              Qgis::MessageLevel::Info );
 
  726                            Qgis::MessageLevel::Warning );
 
  731  QString filter = createFilterExpression();
 
  732  if ( filter.isEmpty() )
 
  736  pushSelectedFeaturesMessage();
 
  741void QgsAttributeForm::searchSetSelection()
 
  746void QgsAttributeForm::searchAddToSelection()
 
  751void QgsAttributeForm::searchRemoveFromSelection()
 
  756void QgsAttributeForm::searchIntersectSelection()
 
  761bool QgsAttributeForm::saveMultiEdits()
 
  765  const QList<int> fieldIndexes = mFormEditorWidgets.uniqueKeys();
 
  766  mFormEditorWidgets.constBegin();
 
  767  for ( 
int fieldIndex : fieldIndexes )
 
  769    const QList<QgsAttributeFormEditorWidget *> widgets = mFormEditorWidgets.values( fieldIndex );
 
  770    if ( !widgets.first()->hasChanged() )
 
  773    if ( !widgets.first()->currentValue().isValid() 
 
  774         || !fieldIsEditable( fieldIndex ) ) 
 
  781      widget->changesCommitted();
 
  783    newAttributeValues.insert( fieldIndex, widgets.first()->currentValue() );
 
  786  if ( newAttributeValues.isEmpty() )
 
  794  int res = QMessageBox::information( 
this, tr( 
"Multiedit Attributes" ),
 
  795                                      tr( 
"Edits will be applied to all selected features." ), QMessageBox::Ok | QMessageBox::Cancel );
 
  796  if ( res != QMessageBox::Ok )
 
  807  const auto constMultiEditFeatureIds = mMultiEditFeatureIds;
 
  810    QgsAttributeMap::const_iterator aIt = newAttributeValues.constBegin();
 
  811    for ( ; aIt != newAttributeValues.constEnd(); ++aIt )
 
  817  clearMultiEditMessages();
 
  822    mMultiEditMessageBarItem = 
new QgsMessageBarItem( tr( 
"Attribute changes for multiple features applied." ), Qgis::MessageLevel::Success, -1 );
 
  827    mMultiEditMessageBarItem = 
new QgsMessageBarItem( tr( 
"Changes could not be applied." ), Qgis::MessageLevel::Warning, 0 );
 
  830  if ( !mButtonBox->isVisible() )
 
  831    mMessageBar->
pushItem( mMultiEditMessageBarItem );
 
  857    wrapper->notifyAboutToSave();
 
  897      success = saveEdits( error );
 
  901      success = saveMultiEdits();
 
  906  mUnsavedMultiEditChanges = 
false;
 
  915  mValuesInitialized = 
false;
 
  916  const auto constMWidgets = mWidgets;
 
  919    ww->setFeature( mFeature );
 
  923  updateFieldDependencies();
 
  933    mAlreadyUpdatedFields.append( eww->
fieldIdx() );
 
  934    updateValuesDependencies( eww->
fieldIdx() );
 
  935    mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
 
  938  mValuesInitialized = 
true;
 
  944  const auto widgets { findChildren<  QgsAttributeFormEditorWidget * >() };
 
  951void QgsAttributeForm::clearMultiEditMessages()
 
  953  if ( mMultiEditUnsavedMessageBarItem )
 
  955    if ( !mButtonBox->isVisible() )
 
  956      mMessageBar->
popWidget( mMultiEditUnsavedMessageBarItem );
 
  957    mMultiEditUnsavedMessageBarItem = 
nullptr;
 
  959  if ( mMultiEditMessageBarItem )
 
  961    if ( !mButtonBox->isVisible() )
 
  962      mMessageBar->
popWidget( mMultiEditMessageBarItem );
 
  963    mMultiEditMessageBarItem = 
nullptr;
 
  967QString QgsAttributeForm::createFilterExpression()
 const 
  972    QString filter = w->currentFilterExpression();
 
  973    if ( !filter.isEmpty() )
 
  977  if ( filters.isEmpty() )
 
  980  QString filter = filters.join( QLatin1String( 
") AND (" ) ).prepend( 
'(' ).append( 
')' );
 
  989  if ( mExtraContextScope )
 
  996void QgsAttributeForm::onAttributeChanged( 
const QVariant &value, 
const QVariantList &additionalFieldValues )
 
 1001  bool signalEmitted = 
false;
 
 1003  if ( mValuesInitialized )
 
 1022      for ( 
int i = 0; i < additionalFields.count(); i++ )
 
 1024        const QString fieldName = additionalFields.at( i );
 
 1025        const QVariant value = additionalFieldValues.at( i );
 
 1029      signalEmitted = 
true;
 
 1031      if ( mValuesInitialized )
 
 1032        updateJoinedFields( *eww );
 
 1038      if ( !mIsSettingMultiEditFeatures )
 
 1040        mUnsavedMultiEditChanges = 
true;
 
 1042        QLabel *msgLabel = 
new QLabel( tr( 
"Unsaved multiedit changes: <a href=\"#apply\">apply changes</a> or <a href=\"#reset\">reset changes</a>." ), mMessageBar );
 
 1043        msgLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
 
 1044        msgLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
 
 1045        connect( msgLabel, &QLabel::linkActivated, 
this, &QgsAttributeForm::multiEditMessageClicked );
 
 1046        clearMultiEditMessages();
 
 1048        mMultiEditUnsavedMessageBarItem = 
new QgsMessageBarItem( msgLabel, Qgis::MessageLevel::Warning );
 
 1049        if ( !mButtonBox->isVisible() )
 
 1050          mMessageBar->
pushItem( mMultiEditUnsavedMessageBarItem );
 
 1053        signalEmitted = 
true;
 
 1063  updateConstraints( eww );
 
 1066  if ( mValuesInitialized )
 
 1069    mAlreadyUpdatedFields.append( eww->
fieldIdx() );
 
 1070    updateValuesDependencies( eww->
fieldIdx() );
 
 1071    mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
 
 1076  updateEditableState();
 
 1079  const QList<QgsAttributeFormEditorWidget *> formEditorWidgets = mFormEditorWidgets.values( eww->
fieldIdx() );
 
 1082    if ( formEditorWidget->editorWidget() == eww )
 
 1087    formEditorWidget->editorWidget()->blockSignals( 
true );
 
 1088    formEditorWidget->editorWidget()->setValue( value );
 
 1089    formEditorWidget->editorWidget()->blockSignals( 
false );
 
 1092  if ( !signalEmitted )
 
 1097    bool attributeHasChanged = !mIsSettingFeature;
 
 1099      attributeHasChanged &= !mIsSettingMultiEditFeatures;
 
 1105void QgsAttributeForm::updateAllConstraints()
 
 1107  const auto constMWidgets = mWidgets;
 
 1112      updateConstraints( eww );
 
 1120  if ( currentFormValuesFeature( ft ) )
 
 1132    updateConstraint( ft, eww );
 
 1135    const QList<QgsEditorWidgetWrapper *> deps = constraintDependencies( eww );
 
 1138      updateConstraint( ft, depsEww );
 
 1146    const QVector<ContainerInformation *> infos = mContainerInformationDependency.value( eww->
field().
name() );
 
 1147    for ( ContainerInformation *info : infos )
 
 1149      info->apply( &context );
 
 1154void QgsAttributeForm::updateContainersVisibility()
 
 1158  const QVector<ContainerInformation *> infos = mContainerVisibilityCollapsedInformation;
 
 1160  for ( ContainerInformation *info : infos )
 
 1162    info->apply( &context );
 
 1170  if ( mMode != QgsAttributeEditorContext::Mode::MultiEditMode )
 
 1172    updateAllConstraints();
 
 1188      if ( mJoinedFeatures.contains( info ) )
 
 1205void QgsAttributeForm::updateLabels()
 
 1207  if ( ! mLabelDataDefinedProperties.isEmpty() )
 
 1210    if ( currentFormValuesFeature( currentFeature ) )
 
 1214      for ( 
auto it = mLabelDataDefinedProperties.constBegin() ; it != mLabelDataDefinedProperties.constEnd(); ++it )
 
 1216        QLabel *label { it.key() };
 
 1218        const QString value { it->valueAsString( context, QString(), &ok ) };
 
 1219        if ( ok && ! value.isEmpty() )
 
 1221          label->setText( value );
 
 1228void QgsAttributeForm::updateEditableState()
 
 1230  if ( ! mEditableDataDefinedProperties.isEmpty() )
 
 1233    if ( currentFormValuesFeature( currentFeature ) )
 
 1237      for ( 
auto it = mEditableDataDefinedProperties.constBegin() ; it != mEditableDataDefinedProperties.constEnd(); ++it )
 
 1239        QWidget *w { it.key() };
 
 1241        const bool isEditable { it->valueAsBool( context, 
true, &ok ) && mLayer && mLayer->
isEditable() };  
 
 1251            w->setEnabled( isEditable );
 
 1259bool QgsAttributeForm::currentFormValuesFeature( 
QgsFeature &feature )
 
 1272    if ( dst.count() > eww->
fieldIdx() )
 
 1274      QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
 
 1275      QVariantList srcVars = QVariantList() << eww->
value();
 
 1276      QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
 1280      for ( 
const QString &fieldName : additionalFields )
 
 1283        fieldIndexes << idx;
 
 1284        dstVars << dst.at( idx );
 
 1288      Q_ASSERT( dstVars.count() == srcVars.count() );
 
 1290      for ( 
int i = 0; i < dstVars.count(); i++ )
 
 1296          dst[fieldIndexes[i]] = srcVars[i];
 
 1313void QgsAttributeForm::registerContainerInformation( QgsAttributeForm::ContainerInformation *info )
 
 1315  mContainerVisibilityCollapsedInformation.append( info );
 
 1317  const QSet<QString> referencedColumns = info->expression.referencedColumns().unite( info->collapsedExpression.referencedColumns() );
 
 1319  for ( 
const QString &col : referencedColumns )
 
 1321    mContainerInformationDependency[ col ].append( info );
 
 1325bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions )
 const 
 1349bool QgsAttributeForm::currentFormValidHardConstraints( QStringList &invalidFields, QStringList &descriptions )
 const 
 1370void QgsAttributeForm::onAttributeAdded( 
int idx )
 
 1372  mPreventFeatureRefresh = 
false;
 
 1376    attrs.insert( idx, QVariant( 
layer()->fields().at( idx ).type() ) );
 
 1384void QgsAttributeForm::onAttributeDeleted( 
int idx )
 
 1386  mPreventFeatureRefresh = 
false;
 
 1390    attrs.remove( idx );
 
 1398void QgsAttributeForm::onRelatedFeaturesChanged()
 
 1400  updateRelatedLayerFields();
 
 1403void QgsAttributeForm::onUpdatedFields()
 
 1405  mPreventFeatureRefresh = 
false;
 
 1422        attrs[i] = QVariant( 
layer()->fields().at( i ).type() );
 
 1432void QgsAttributeForm::onConstraintStatusChanged( 
const QString &constraint,
 
 1438  const QList<QgsAttributeFormEditorWidget *> formEditorWidgets = mFormEditorWidgets.values( eww->
fieldIdx() );
 
 1441    formEditorWidget->setConstraintStatus( constraint, description, err, result );
 
 1446  QList<QgsEditorWidgetWrapper *> wDeps;
 
 1458      if ( name != ewwName )
 
 1465        for ( 
const QString &colName : referencedColumns )
 
 1467          if ( name == colName )
 
 1469            wDeps.append( eww );
 
 1482  return setupRelationWidgetWrapper( QString(), rel, context );
 
 1495void QgsAttributeForm::preventFeatureRefresh()
 
 1497  mPreventFeatureRefresh = 
true;
 
 1528  return mNeedsGeometry;
 
 1531void QgsAttributeForm::synchronizeState()
 
 1533  bool isEditable = ( mFeature.
isValid()
 
 1543      const QList<QgsAttributeFormEditorWidget *> formWidgets = mFormEditorWidgets.values( eww->
fieldIdx() );
 
 1546        formWidget->setConstraintResultVisible( isEditable );
 
 1550      bool enabled = isEditable && fieldIsEditable( eww->
fieldIdx() );
 
 1551      ww->setEnabled( enabled );
 
 1557      ww->setEnabled( isEditable );
 
 1565    if ( mMode == QgsAttributeEditorContext::Mode::MultiEditMode && mLayer->
selectedFeatureCount() == 0 )
 
 1568      if ( mConstraintsFailMessageBarItem )
 
 1570        mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
 
 1572      mConstraintsFailMessageBarItem = 
new QgsMessageBarItem( tr( 
"Multi edit mode requires at least one selected feature." ), Qgis::MessageLevel::Info, -1 );
 
 1573      mMessageBar->
pushItem( mConstraintsFailMessageBarItem );
 
 1577      QStringList invalidFields, descriptions;
 
 1578      mValidConstraints = currentFormValidHardConstraints( invalidFields, descriptions );
 
 1582        if ( !mValidConstraints && !mConstraintsFailMessageBarItem )
 
 1584          mConstraintsFailMessageBarItem = 
new QgsMessageBarItem( tr( 
"Changes to this form will not be saved. %n field(s) don't meet their constraints.", 
"invalid fields", invalidFields.size() ), Qgis::MessageLevel::Warning, -1 );
 
 1585          mMessageBar->
pushItem( mConstraintsFailMessageBarItem );
 
 1587        else if ( mValidConstraints && mConstraintsFailMessageBarItem )
 
 1589          mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
 
 1590          mConstraintsFailMessageBarItem = 
nullptr;
 
 1593      else if ( mConstraintsFailMessageBarItem )
 
 1595        mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
 
 1596        mConstraintsFailMessageBarItem = 
nullptr;
 
 1599      isEditable = isEditable & mValidConstraints;
 
 1604  QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
 
 1606    okButton->setEnabled( isEditable );
 
 1609void QgsAttributeForm::init()
 
 1611  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
 
 1614  QWidget *formWidget = 
nullptr;
 
 1615  mNeedsGeometry = 
false;
 
 1617  bool buttonBoxVisible = 
true;
 
 1621    buttonBoxVisible = mButtonBox->isVisible();
 
 1623    mButtonBox = 
nullptr;
 
 1626  if ( mSearchButtonBox )
 
 1628    delete mSearchButtonBox;
 
 1629    mSearchButtonBox = 
nullptr;
 
 1632  qDeleteAll( mWidgets );
 
 1635  while ( QWidget *w = this->findChild<QWidget *>() )
 
 1641  QVBoxLayout *vl = 
new QVBoxLayout();
 
 1642  vl->setContentsMargins( 0, 0, 0, 0 );
 
 1644  mMessageBar->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
 
 1645  vl->addWidget( mMessageBar );
 
 1650  QGridLayout *layout = 
new QGridLayout();
 
 1651  QWidget *container = 
new QWidget();
 
 1652  container->setLayout( layout );
 
 1653  vl->addWidget( container );
 
 1655  mFormEditorWidgets.clear();
 
 1656  mFormWidgets.clear();
 
 1659  setContentsMargins( 0, 0, 0, 0 );
 
 1668    if ( file && file->open( QFile::ReadOnly ) )
 
 1672      QFileInfo fi( file->fileName() );
 
 1673      loader.setWorkingDirectory( fi.dir() );
 
 1674      formWidget = loader.load( file, 
this );
 
 1677        formWidget->setWindowFlags( Qt::Widget );
 
 1678        layout->addWidget( formWidget );
 
 1681        mButtonBox = findChild<QDialogButtonBox *>();
 
 1684        formWidget->installEventFilter( 
this );
 
 1692  if ( !formWidget && mLayer->
editFormConfig().
layout() == Qgis::AttributeFormLayout::DragAndDrop )
 
 1696    int columnCount = 1;
 
 1697    bool hasRootFields = 
false;
 
 1698    bool addSpacer = 
true;
 
 1704      if ( widgDef->type() == Qgis::AttributeEditorType::Container )
 
 1707        if ( !containerDef )
 
 1710        switch ( containerDef->
type() )
 
 1714            tabWidget = 
nullptr;
 
 1715            WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
 
 1716            if ( widgetInfo.labelStyle.overrideColor )
 
 1718              if ( widgetInfo.labelStyle.color.isValid() )
 
 1720                widgetInfo.widget->setStyleSheet( QStringLiteral( 
"QGroupBox::title { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 1723            if ( widgetInfo.labelStyle.overrideFont )
 
 1725              widgetInfo.widget->setFont( widgetInfo.labelStyle.font );
 
 1728            layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
 
 1729            if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1731              layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1733            if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1735              layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1749            tabWidget = 
nullptr;
 
 1750            WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
 
 1751            layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
 
 1752            if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1754              layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1757            if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1759              layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1775              layout->addWidget( tabWidget, row, column, 1, 2 );
 
 1779            QWidget *tabPage = 
new QWidget( tabWidget );
 
 1781            tabWidget->addTab( tabPage, widgDef->name() );
 
 1782            tabWidget->
setTabStyle( tabWidget->tabBar()->count() - 1, widgDef->labelStyle() );
 
 1786              registerContainerInformation( 
new ContainerInformation( tabWidget, tabPage, containerDef->
visibilityExpression().
data() ) );
 
 1788            QGridLayout *tabPageLayout = 
new QGridLayout();
 
 1789            tabPage->setLayout( tabPageLayout );
 
 1791            WidgetInfo widgetInfo = createWidgetFromDef( widgDef, tabPage, mLayer, mContext );
 
 1792            tabPageLayout->addWidget( widgetInfo.widget );
 
 1797      else if ( widgDef->type() == Qgis::AttributeEditorType::Relation )
 
 1799        hasRootFields = 
true;
 
 1800        tabWidget = 
nullptr;
 
 1801        WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
 
 1804        if ( widgetInfo.showLabel )
 
 1806          if ( widgetInfo.labelStyle.overrideColor && widgetInfo.labelStyle.color.isValid() )
 
 1808            collapsibleGroupBox->
setStyleSheet( QStringLiteral( 
"QGroupBox::title { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 1811          if ( widgetInfo.labelStyle.overrideFont )
 
 1813            collapsibleGroupBox->setFont( widgetInfo.labelStyle.font );
 
 1816          collapsibleGroupBox->setTitle( widgetInfo.labelText );
 
 1819        QVBoxLayout *collapsibleGroupBoxLayout = 
new QVBoxLayout();
 
 1820        collapsibleGroupBoxLayout->addWidget( widgetInfo.widget );
 
 1821        collapsibleGroupBox->setLayout( collapsibleGroupBoxLayout );
 
 1823        QVBoxLayout *
c = 
new QVBoxLayout();
 
 1824        c->addWidget( collapsibleGroupBox );
 
 1825        layout->addLayout( 
c, row, column, 1, 2 );
 
 1827        if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1828          layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1829        if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1830          layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1839        hasRootFields = 
true;
 
 1840        tabWidget = 
nullptr;
 
 1841        WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
 
 1842        QLabel *label = 
new QLabel( widgetInfo.labelText );
 
 1844        if ( widgetInfo.labelStyle.overrideColor )
 
 1846          if ( widgetInfo.labelStyle.color.isValid() )
 
 1848            label->setStyleSheet( QStringLiteral( 
"QLabel { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 1852        if ( widgetInfo.labelStyle.overrideFont )
 
 1854          label->setFont( widgetInfo.labelStyle.font );
 
 1857        label->setToolTip( widgetInfo.toolTip );
 
 1858        if ( columnCount > 1 && !widgetInfo.labelOnTop )
 
 1860          label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
 
 1863        label->setBuddy( widgetInfo.widget );
 
 1866        if ( widgetInfo.widget
 
 1867             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Fixed
 
 1868             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Maximum
 
 1869             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Preferred )
 
 1872        if ( !widgetInfo.showLabel )
 
 1874          QVBoxLayout *
c = 
new QVBoxLayout();
 
 1875          label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 1876          c->addWidget( widgetInfo.widget );
 
 1877          layout->addLayout( 
c, row, column, 1, 2 );
 
 1879          if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1881            layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1884          if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1886            layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1891        else if ( widgetInfo.labelOnTop )
 
 1893          QVBoxLayout *
c = 
new QVBoxLayout();
 
 1894          label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 1895          c->addWidget( label );
 
 1896          c->addWidget( widgetInfo.widget );
 
 1897          layout->addLayout( 
c, row, column, 1, 2 );
 
 1899          if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1901            layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1904          if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1906            layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1913          const int widgetColumn = column + 1;
 
 1914          layout->addWidget( label, row, column++ );
 
 1915          layout->addWidget( widgetInfo.widget, row, column++ );
 
 1917          if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1919            layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1922          if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( widgetColumn ) )
 
 1924            layout->setColumnStretch( widgetColumn, widgDef->horizontalStretch() );
 
 1929        if ( widgDef->type() == Qgis::AttributeEditorType::Field )
 
 1932          const int fieldIdx = fieldElement->
idx();
 
 1933          if ( fieldIdx >= 0 && fieldIdx < mLayer->fields().count() )
 
 1935            const QString fieldName { mLayer->
fields().
at( fieldIdx ).
name() };
 
 1939              if ( property.isActive() )
 
 1941                mLabelDataDefinedProperties[ label ] = property;
 
 1947              if ( property.isActive() )
 
 1949                mEditableDataDefinedProperties[ widgetInfo.widget ] = property;
 
 1956      if ( column >= columnCount * 2 )
 
 1963    if ( hasRootFields && addSpacer )
 
 1965      QSpacerItem *spacerItem = 
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
 
 1966      layout->addItem( spacerItem, row, 0 );
 
 1967      layout->setRowStretch( row, 1 );
 
 1970    formWidget = container;
 
 1979    formWidget = 
new QWidget( 
this );
 
 1980    QGridLayout *gridLayout = 
new QGridLayout( formWidget );
 
 1981    formWidget->setLayout( gridLayout );
 
 1987      scrollArea->setWidget( formWidget );
 
 1988      scrollArea->setWidgetResizable( 
true );
 
 1989      scrollArea->setFrameShape( QFrame::NoFrame );
 
 1990      scrollArea->setFrameShadow( QFrame::Plain );
 
 1991      scrollArea->setFocusProxy( 
this );
 
 1992      layout->addWidget( scrollArea );
 
 1996      layout->addWidget( formWidget );
 
 2011      QString labelText = fieldName;
 
 2012      labelText.replace( 
'&', QLatin1String( 
"&&" ) ); 
 
 2016      if ( widgetSetup.
type() == QLatin1String( 
"Hidden" ) )
 
 2022      QLabel *label = 
new QLabel( labelText );
 
 2024      QSvgWidget *i = 
new QSvgWidget();
 
 2025      i->setFixedSize( 18, 18 );
 
 2030        if ( property.isActive() )
 
 2032          mLabelDataDefinedProperties[ label ] = property;
 
 2038      QWidget *w = 
nullptr;
 
 2043        mFormEditorWidgets.insert( idx, formWidget );
 
 2044        mFormWidgets.append( formWidget );
 
 2047        label->setBuddy( eww->
widget() );
 
 2052          if ( property.isActive() )
 
 2054            mEditableDataDefinedProperties[ formWidget ] = property;
 
 2060        w = 
new QLabel( QStringLiteral( 
"<p style=\"color: red; font-style: italic;\">%1</p>" ).arg( tr( 
"Failed to create widget with type '%1'" ).arg( widgetSetup.
type() ) ) );
 
 2069        mWidgets.append( eww );
 
 2070        mIconMap[eww->
widget()] = i;
 
 2075        gridLayout->addWidget( label, row++, 0, 1, 2 );
 
 2076        gridLayout->addWidget( w, row++, 0, 1, 2 );
 
 2077        gridLayout->addWidget( i, row++, 0, 1, 2 );
 
 2081        gridLayout->addWidget( label, row, 0 );
 
 2082        gridLayout->addWidget( w, row, 1 );
 
 2083        gridLayout->addWidget( i, row++, 2 );
 
 2097      QVBoxLayout *collapsibleGroupBoxLayout = 
new QVBoxLayout();
 
 2098      collapsibleGroupBoxLayout->addWidget( formWidget );
 
 2099      collapsibleGroupBox->setLayout( collapsibleGroupBoxLayout );
 
 2101      gridLayout->addWidget( collapsibleGroupBox, row++, 0, 1, 2 );
 
 2103      mWidgets.append( rww );
 
 2104      mFormWidgets.append( formWidget );
 
 2109      QSpacerItem *spacerItem = 
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
 
 2110      gridLayout->addItem( spacerItem, row, 0 );
 
 2111      gridLayout->setRowStretch( row, 1 );
 
 2116  updateFieldDependencies();
 
 2120    mButtonBox = 
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
 
 2121    mButtonBox->setObjectName( QStringLiteral( 
"buttonBox" ) );
 
 2122    layout->addWidget( mButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
 
 2124  mButtonBox->setVisible( buttonBoxVisible );
 
 2126  if ( !mSearchButtonBox )
 
 2128    mSearchButtonBox = 
new QWidget();
 
 2129    QHBoxLayout *boxLayout = 
new QHBoxLayout();
 
 2130    boxLayout->setContentsMargins( 0, 0, 0, 0 );
 
 2131    mSearchButtonBox->setLayout( boxLayout );
 
 2132    mSearchButtonBox->setObjectName( QStringLiteral( 
"searchButtonBox" ) );
 
 2134    QPushButton *clearButton = 
new QPushButton( tr( 
"&Reset Form" ), mSearchButtonBox );
 
 2136    boxLayout->addWidget( clearButton );
 
 2137    boxLayout->addStretch( 1 );
 
 2139    QPushButton *flashButton = 
new QPushButton();
 
 2140    flashButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2141    flashButton->setText( tr( 
"&Flash Features" ) );
 
 2142    connect( flashButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchFlash );
 
 2143    boxLayout->addWidget( flashButton );
 
 2145    QPushButton *openAttributeTableButton = 
new QPushButton();
 
 2146    openAttributeTableButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2147    openAttributeTableButton->setText( tr( 
"Show in &Table" ) );
 
 2148    openAttributeTableButton->setToolTip( tr( 
"Open the attribute table editor with the filtered features" ) );
 
 2149    connect( openAttributeTableButton, &QToolButton::clicked, 
this, [ = ]
 
 2153    boxLayout->addWidget( openAttributeTableButton );
 
 2155    QPushButton *zoomButton = 
new QPushButton();
 
 2156    zoomButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2157    zoomButton->setText( tr( 
"&Zoom to Features" ) );
 
 2158    connect( zoomButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchZoomTo );
 
 2159    boxLayout->addWidget( zoomButton );
 
 2161    QToolButton *selectButton = 
new QToolButton();
 
 2162    selectButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2163    selectButton->setText( tr( 
"&Select Features" ) );
 
 2165    selectButton->setPopupMode( QToolButton::MenuButtonPopup );
 
 2166    selectButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
 
 2167    connect( selectButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchSetSelection );
 
 2168    QMenu *selectMenu = 
new QMenu( selectButton );
 
 2169    QAction *selectAction = 
new QAction( tr( 
"Select Features" ), selectMenu );
 
 2171    connect( selectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchSetSelection );
 
 2172    selectMenu->addAction( selectAction );
 
 2173    QAction *addSelectAction = 
new QAction( tr( 
"Add to Current Selection" ), selectMenu );
 
 2175    connect( addSelectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchAddToSelection );
 
 2176    selectMenu->addAction( addSelectAction );
 
 2177    QAction *deselectAction = 
new QAction( tr( 
"Remove from Current Selection" ), selectMenu );
 
 2179    connect( deselectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchRemoveFromSelection );
 
 2180    selectMenu->addAction( deselectAction );
 
 2181    QAction *filterSelectAction = 
new QAction( tr( 
"Filter Current Selection" ), selectMenu );
 
 2183    connect( filterSelectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchIntersectSelection );
 
 2184    selectMenu->addAction( filterSelectAction );
 
 2185    selectButton->setMenu( selectMenu );
 
 2186    boxLayout->addWidget( selectButton );
 
 2190      QToolButton *filterButton = 
new QToolButton();
 
 2191      filterButton->setText( tr( 
"Filter Features" ) );
 
 2192      filterButton->setPopupMode( QToolButton::MenuButtonPopup );
 
 2193      filterButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2194      connect( filterButton, &QToolButton::clicked, 
this, &QgsAttributeForm::filterTriggered );
 
 2195      QMenu *filterMenu = 
new QMenu( filterButton );
 
 2196      QAction *filterAndAction = 
new QAction( tr( 
"Filter Within (\"AND\")" ), filterMenu );
 
 2197      connect( filterAndAction, &QAction::triggered, 
this, &QgsAttributeForm::filterAndTriggered );
 
 2198      filterMenu->addAction( filterAndAction );
 
 2199      QAction *filterOrAction = 
new QAction( tr( 
"Extend Filter (\"OR\")" ), filterMenu );
 
 2200      connect( filterOrAction, &QAction::triggered, 
this, &QgsAttributeForm::filterOrTriggered );
 
 2201      filterMenu->addAction( filterOrAction );
 
 2202      filterButton->setMenu( filterMenu );
 
 2203      boxLayout->addWidget( filterButton );
 
 2207      QPushButton *closeButton = 
new QPushButton( tr( 
"Close" ), mSearchButtonBox );
 
 2209      closeButton->setShortcut( Qt::Key_Escape );
 
 2210      boxLayout->addWidget( closeButton );
 
 2213    layout->addWidget( mSearchButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
 
 2231  const auto constMInterfaces = mInterfaces;
 
 2242  QApplication::restoreOverrideCursor();
 
 2245void QgsAttributeForm::cleanPython()
 
 2247  if ( !mPyFormVarName.isNull() )
 
 2249    QString expr = QStringLiteral( 
"if '%1' in locals(): del %1\n" ).arg( mPyFormVarName );
 
 2254void QgsAttributeForm::initPython()
 
 2270      case Qgis::AttributeFormPythonInitCodeSource::File:
 
 2271        if ( !initFilePath.isEmpty() )
 
 2275          if ( inputFile && inputFile->open( QFile::ReadOnly ) )
 
 2278            QTextStream inf( inputFile );
 
 2279#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 
 2280            inf.setCodec( 
"UTF-8" );
 
 2282            initCode = inf.readAll();
 
 2287            QgsLogger::warning( QStringLiteral( 
"The external python file path %1 could not be opened!" ).arg( initFilePath ) );
 
 2296      case Qgis::AttributeFormPythonInitCodeSource::Dialog:
 
 2298        if ( initCode.isEmpty() )
 
 2300          QgsLogger::warning( QStringLiteral( 
"The python code provided in the dialog is empty!" ) );
 
 2304      case Qgis::AttributeFormPythonInitCodeSource::Environment:
 
 2305      case Qgis::AttributeFormPythonInitCodeSource::NoSource:
 
 2311    if ( !initCode.isEmpty() )
 
 2317                                  tr( 
"Python macro could not be run due to missing permissions." ),
 
 2318                                  Qgis::MessageLevel::Warning );
 
 2325    if ( 
QgsPythonRunner::eval( QStringLiteral( 
"len(inspect.getfullargspec(%1)[0])" ).arg( initFunction ), numArgs ) )
 
 2327      static int sFormId = 0;
 
 2328      mPyFormVarName = QStringLiteral( 
"_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
 
 2330      QString form = QStringLiteral( 
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
 
 2331                     .arg( mPyFormVarName )
 
 2332                     .arg( ( quint64 ) 
this );
 
 2336      QgsDebugMsgLevel( QStringLiteral( 
"running featureForm init: %1" ).arg( mPyFormVarName ), 2 );
 
 2339      if ( numArgs == QLatin1String( 
"3" ) )
 
 2347        msgBox.setText( tr( 
"The python init function (<code>%1</code>) does not accept three arguments as expected!<br>Please check the function name in the <b>Fields</b> tab of the layer properties." ).arg( initFunction ) );
 
 2350        QString expr = QString( 
"%1(%2)" )
 
 2351                       .arg( mLayer->editFormInit() )
 
 2352                       .arg( mPyFormVarName );
 
 2353        QgsAttributeFormInterface *iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface *>( expr, 
"QgsAttributeFormInterface" );
 
 2363      msgBox.setText( tr( 
"The python init function (<code>%1</code>) could not be found!<br>Please check the function name in the <b>Fields</b> tab of the layer properties." ).arg( initFunction ) );
 
 2371  WidgetInfo newWidgetInfo;
 
 2373  newWidgetInfo.labelStyle = widgetDef->
labelStyle();
 
 2375  switch ( widgetDef->
type() )
 
 2377    case Qgis::AttributeEditorType::Action:
 
 2387      mWidgets.append( actionWrapper );
 
 2388      newWidgetInfo.widget = actionWrapper->
widget();
 
 2389      newWidgetInfo.showLabel = 
false;
 
 2394    case Qgis::AttributeEditorType::Field:
 
 2402      if ( fldIdx < fields.
count() && fldIdx >= 0 )
 
 2408        mFormEditorWidgets.insert( fldIdx, formWidget );
 
 2409        mFormWidgets.append( formWidget );
 
 2413        newWidgetInfo.widget = formWidget;
 
 2414        mWidgets.append( eww );
 
 2416        newWidgetInfo.widget->setObjectName( fields.
at( fldIdx ).
name() );
 
 2417        newWidgetInfo.hint = fields.
at( fldIdx ).
comment();
 
 2422      newWidgetInfo.labelText.replace( 
'&', QLatin1String( 
"&&" ) ); 
 
 2423      newWidgetInfo.toolTip = QStringLiteral( 
"<b>%1</b><p>%2</p>" ).arg( mLayer->
attributeDisplayName( fldIdx ), newWidgetInfo.hint );
 
 2424      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2429    case Qgis::AttributeEditorType::Relation:
 
 2445      mWidgets.append( rww );
 
 2446      mFormWidgets.append( formWidget );
 
 2448      newWidgetInfo.widget = formWidget;
 
 2449      newWidgetInfo.showLabel = relDef->
showLabel();
 
 2450      newWidgetInfo.labelText = relDef->
label();
 
 2451      if ( newWidgetInfo.labelText.isEmpty() )
 
 2453      newWidgetInfo.labelOnTop = 
true;
 
 2457    case Qgis::AttributeEditorType::Container:
 
 2465      if ( columnCount <= 0 )
 
 2469      QWidget *myContainer = 
nullptr;
 
 2470      bool removeLayoutMargin = 
false;
 
 2471      switch ( container->
type() )
 
 2476          widgetName = QStringLiteral( 
"QGroupBox" );
 
 2479            groupBox->setTitle( container->
name() );
 
 2480            if ( newWidgetInfo.labelStyle.overrideColor )
 
 2482              if ( newWidgetInfo.labelStyle.color.isValid() )
 
 2484                groupBox->
setStyleSheet( QStringLiteral( 
"QGroupBox::title { color: %1; }" ).arg( newWidgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 2487            if ( newWidgetInfo.labelStyle.overrideFont )
 
 2489              groupBox->setFont( newWidgetInfo.labelStyle.font );
 
 2492          myContainer = groupBox;
 
 2493          newWidgetInfo.widget = myContainer;
 
 2500          QWidget *rowWidget = 
new QWidget();
 
 2501          widgetName = QStringLiteral( 
"Row" );
 
 2502          myContainer = rowWidget;
 
 2503          newWidgetInfo.widget = myContainer;
 
 2504          removeLayoutMargin = 
true;
 
 2505          columnCount = container->
children().size();
 
 2511          myContainer = 
new QWidget();
 
 2515          scrollArea->setWidget( myContainer );
 
 2516          scrollArea->setWidgetResizable( 
true );
 
 2517          scrollArea->setFrameShape( QFrame::NoFrame );
 
 2518          widgetName = QStringLiteral( 
"QScrollArea QWidget" );
 
 2520          newWidgetInfo.widget = scrollArea;
 
 2527        QString style {QStringLiteral( 
"background-color: %1;" ).arg( container->
backgroundColor().name() )};
 
 2528        newWidgetInfo.widget->setStyleSheet( style );
 
 2531      QGridLayout *gbLayout = 
new QGridLayout();
 
 2532      if ( removeLayoutMargin )
 
 2533        gbLayout->setContentsMargins( 0, 0, 0, 0 );
 
 2534      myContainer->setLayout( gbLayout );
 
 2538      bool addSpacer = 
true;
 
 2540      const QList<QgsAttributeEditorElement *> children = container->
children();
 
 2544        WidgetInfo widgetInfo = createWidgetFromDef( childDef, myContainer, vl, context );
 
 2546        if ( childDef->type() == Qgis::AttributeEditorType::Container )
 
 2556        int widgetColumn = column;
 
 2558        if ( widgetInfo.labelText.isNull() || ! widgetInfo.showLabel )
 
 2560          gbLayout->addWidget( widgetInfo.widget, row, column, 1, 2 );
 
 2561          widgetColumn = column + 1;
 
 2566          QLabel *mypLabel = 
new QLabel( widgetInfo.labelText );
 
 2568          if ( widgetInfo.labelStyle.overrideColor )
 
 2570            if ( widgetInfo.labelStyle.color.isValid() )
 
 2572              mypLabel->setStyleSheet( QStringLiteral( 
"QLabel { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 2576          if ( widgetInfo.labelStyle.overrideFont )
 
 2578            mypLabel->setFont( widgetInfo.labelStyle.font );
 
 2582          if ( childDef->type() == Qgis::AttributeEditorType::Field )
 
 2586            const int fldIdx = fieldDef->
idx();
 
 2587            if ( fldIdx < fields.
count() && fldIdx >= 0 )
 
 2589              const QString fieldName { fields.
at( fldIdx ).
name() };
 
 2593                if ( property.isActive() )
 
 2595                  mLabelDataDefinedProperties[ mypLabel ] = property;
 
 2601                if ( property.isActive() )
 
 2603                  mEditableDataDefinedProperties[ widgetInfo.widget ] = property;
 
 2609          mypLabel->setToolTip( widgetInfo.toolTip );
 
 2610          if ( columnCount > 1 && !widgetInfo.labelOnTop )
 
 2612            mypLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
 
 2615          mypLabel->setBuddy( widgetInfo.widget );
 
 2617          if ( widgetInfo.labelOnTop )
 
 2619            widgetColumn = column + 1;
 
 2620            QVBoxLayout *
c = 
new QVBoxLayout();
 
 2621            mypLabel->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 2622            c->layout()->addWidget( mypLabel );
 
 2623            c->layout()->addWidget( widgetInfo.widget );
 
 2624            gbLayout->addLayout( 
c, row, column, 1, 2 );
 
 2629            widgetColumn = column + 1;
 
 2630            gbLayout->addWidget( mypLabel, row, column++ );
 
 2631            gbLayout->addWidget( widgetInfo.widget, row, column++ );
 
 2635        const int childHorizontalStretch = childDef->horizontalStretch();
 
 2636        const int existingColumnStretch = gbLayout->columnStretch( widgetColumn );
 
 2637        if ( childHorizontalStretch > 0 && childHorizontalStretch > existingColumnStretch )
 
 2639          gbLayout->setColumnStretch( widgetColumn, childHorizontalStretch );
 
 2642        if ( childDef->verticalStretch() > 0  && childDef->verticalStretch() > gbLayout->rowStretch( row ) )
 
 2644          gbLayout->setRowStretch( row, childDef->verticalStretch() );
 
 2647        if ( column >= columnCount * 2 )
 
 2653        if ( widgetInfo.widget
 
 2654             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Fixed
 
 2655             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Maximum
 
 2656             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Preferred )
 
 2660        if ( qobject_cast<QgsAttributeFormRelationEditorWidget *>( widgetInfo.widget ) )
 
 2666        QWidget *spacer = 
new QWidget();
 
 2667        spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
 
 2668        gbLayout->addWidget( spacer, ++row, 0 );
 
 2669        gbLayout->setRowStretch( row, 1 );
 
 2672      newWidgetInfo.labelText = QString();
 
 2673      newWidgetInfo.labelOnTop = 
true;
 
 2674      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2678    case Qgis::AttributeEditorType::QmlElement:
 
 2687      mWidgets.append( qmlWrapper );
 
 2689      newWidgetInfo.widget = qmlWrapper->
widget();
 
 2690      newWidgetInfo.labelText = elementDef->
name();
 
 2691      newWidgetInfo.labelOnTop = 
true;
 
 2692      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2696    case Qgis::AttributeEditorType::HtmlElement:
 
 2704      mWidgets.append( htmlWrapper );
 
 2706      newWidgetInfo.widget = htmlWrapper->
widget();
 
 2707      newWidgetInfo.labelText = elementDef->
name();
 
 2708      newWidgetInfo.labelOnTop = 
true;
 
 2709      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2714    case Qgis::AttributeEditorType::TextElement:
 
 2722      mWidgets.append( textWrapper );
 
 2724      newWidgetInfo.widget = textWrapper->
widget();
 
 2725      newWidgetInfo.labelText = elementDef->
name();
 
 2726      newWidgetInfo.labelOnTop = 
false;
 
 2727      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2732    case Qgis::AttributeEditorType::SpacerElement:
 
 2738      mWidgets.append( spacerWrapper );
 
 2740      newWidgetInfo.widget = spacerWrapper->
widget();
 
 2741      newWidgetInfo.labelOnTop = 
false;
 
 2742      newWidgetInfo.showLabel = 
false;
 
 2747      QgsDebugError( QStringLiteral( 
"Unknown attribute editor widget type encountered..." ) );
 
 2751  return newWidgetInfo;
 
 2754void QgsAttributeForm::createWrappers()
 
 2756  QList<QWidget *> myWidgets = findChildren<QWidget *>();
 
 2757  const QList<QgsField> fields = mLayer->
fields().
toList();
 
 2759  const auto constMyWidgets = myWidgets;
 
 2760  for ( QWidget *myWidget : constMyWidgets )
 
 2763    QVariant vRel = myWidget->property( 
"qgisRelation" );
 
 2764    if ( vRel.isValid() )
 
 2774        mWidgets.append( rww );
 
 2779      const auto constFields = fields;
 
 2782        if ( 
field.
name() == myWidget->objectName() )
 
 2787          mWidgets.append( eww );
 
 2794void QgsAttributeForm::afterWidgetInit()
 
 2796  bool isFirstEww = 
true;
 
 2798  const auto constMWidgets = mWidgets;
 
 2807        setFocusProxy( eww->
widget() );
 
 2817      if ( relationWidgetWrapper )
 
 2830  if ( e->type() == QEvent::KeyPress )
 
 2832    QKeyEvent *keyEvent = 
dynamic_cast<QKeyEvent *
>( e );
 
 2833    if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
 
 2845    QSet< int > &mixedValueFields,
 
 2846    QHash< int, QVariant > &fieldSharedValues )
 const 
 2848  mixedValueFields.clear();
 
 2849  fieldSharedValues.clear();
 
 2855    for ( 
int i = 0; i < mLayer->
fields().count(); ++i )
 
 2857      if ( mixedValueFields.contains( i ) )
 
 2862        fieldSharedValues[i] = f.
attribute( i );
 
 2866        if ( fieldSharedValues.value( i ) != f.
attribute( i ) )
 
 2868          fieldSharedValues.remove( i );
 
 2869          mixedValueFields.insert( i );
 
 2875    if ( mixedValueFields.count() == mLayer->
fields().
count() )
 
 2884void QgsAttributeForm::layerSelectionChanged()
 
 2897      resetMultiEdit( 
true );
 
 2904  mIsSettingMultiEditFeatures = 
true;
 
 2905  mMultiEditFeatureIds = fids;
 
 2907  if ( fids.isEmpty() )
 
 2910    QMultiMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
 
 2911    for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
 
 2913      wIt.value()->initialize( QVariant() );
 
 2915    mIsSettingMultiEditFeatures = 
false;
 
 2922  QSet< int > mixedValueFields;
 
 2923  QHash< int, QVariant > fieldSharedValues;
 
 2924  scanForEqualAttributes( fit, mixedValueFields, fieldSharedValues );
 
 2933  if ( mCurrentFormFeature.
id() != firstFeature.
id( ) )
 
 2938  const auto constMixedValueFields = mixedValueFields;
 
 2939  for ( 
int fieldIndex : std::as_const( mixedValueFields ) )
 
 2941    const QList<QgsAttributeFormEditorWidget *> formEditorWidgets = mFormEditorWidgets.values( fieldIndex );
 
 2942    if ( formEditorWidgets.isEmpty() )
 
 2945    const QStringList additionalFields = formEditorWidgets.first()->editorWidget()->additionalFields();
 
 2946    QVariantList additionalFieldValues;
 
 2947    for ( 
const QString &additionalField : additionalFields )
 
 2948      additionalFieldValues << firstFeature.
attribute( additionalField );
 
 2951      w->initialize( firstFeature.
attribute( fieldIndex ), 
true, additionalFieldValues );
 
 2953  QHash< int, QVariant >::const_iterator sharedValueIt = fieldSharedValues.constBegin();
 
 2954  for ( ; sharedValueIt != fieldSharedValues.constEnd(); ++sharedValueIt )
 
 2956    const QList<QgsAttributeFormEditorWidget *> formEditorWidgets = mFormEditorWidgets.values( sharedValueIt.key() );
 
 2957    if ( formEditorWidgets.isEmpty() )
 
 2961    const QStringList additionalFields = formEditorWidgets.first()->editorWidget()->additionalFields();
 
 2962    for ( 
const QString &additionalField : additionalFields )
 
 2965      if ( constMixedValueFields.contains( index ) )
 
 2972    QVariantList additionalFieldValues;
 
 2975      for ( 
const QString &additionalField : additionalFields )
 
 2976        additionalFieldValues << firstFeature.
attribute( additionalField );
 
 2978        w->initialize( firstFeature.
attribute( sharedValueIt.key() ), 
true, additionalFieldValues );
 
 2982      for ( 
const QString &additionalField : additionalFields )
 
 2985        Q_ASSERT( fieldSharedValues.contains( index ) );
 
 2986        additionalFieldValues << fieldSharedValues.value( index );
 
 2989        w->initialize( sharedValueIt.value(), 
false, additionalFieldValues );
 
 2993  setMultiEditFeatureIdsRelations( fids );
 
 2995  mIsSettingMultiEditFeatures = 
false;
 
 3000  if ( mOwnsMessageBar )
 
 3002  mOwnsMessageBar = 
false;
 
 3003  mMessageBar = messageBar;
 
 3013  QStringList filters;
 
 3016    QString filter = widget->currentFilterExpression();
 
 3017    if ( !filter.isNull() )
 
 3018      filters << 
'(' + filter + 
')';
 
 3021  return filters.join( QLatin1String( 
" AND " ) );
 
 3026  mExtraContextScope.reset( extraScope );
 
 3032  const bool newVisibility = expression.evaluate( expressionContext ).toBool();
 
 3034  if ( expression.isValid() && ! expression.hasEvalError() && newVisibility != isVisible )
 
 3042      widget->setVisible( newVisibility );
 
 3045    isVisible = newVisibility;
 
 3048  const bool newCollapsedState = collapsedExpression.evaluate( expressionContext ).toBool();
 
 3050  if ( collapsedExpression.isValid() && ! collapsedExpression.hasEvalError() && newCollapsedState != isCollapsed )
 
 3055      collapsibleGroupBox->
setCollapsed( newCollapsedState );
 
 3056      isCollapsed = newCollapsedState;
 
 3070  if ( infos.count() == 0 || !currentFormValuesFeature( formFeature ) )
 
 3073  const QString hint = tr( 
"No feature joined" );
 
 3074  const auto constInfos = infos;
 
 3077    if ( !info->isDynamicFormEnabled() )
 
 3082    mJoinedFeatures[info] = joinFeature;
 
 3084    if ( info->hasSubset() )
 
 3088      const auto constSubsetNames = subsetNames;
 
 3089      for ( 
const QString &
field : constSubsetNames )
 
 3091        QString prefixedName = info->prefixedFieldName( 
field );
 
 3093        QString hintText = hint;
 
 3109        QString prefixedName = info->prefixedFieldName( 
field );
 
 3111        QString hintText = hint;
 
 3125bool QgsAttributeForm::fieldIsEditable( 
int fieldIndex )
 const 
 3130void QgsAttributeForm::updateFieldDependencies()
 
 3132  mDefaultValueDependencies.clear();
 
 3133  mVirtualFieldsDependencies.clear();
 
 3134  mRelatedLayerFieldsDependencies.clear();
 
 3143    updateFieldDependenciesDefaultValue( eww );
 
 3144    updateFieldDependenciesVirtualFields( eww );
 
 3145    updateRelatedLayerFieldsDependencies( eww );
 
 3153  if ( exp.needsGeometry() )
 
 3154    mNeedsGeometry = 
true;
 
 3156  const QSet<QString> referencedColumns = exp.referencedColumns();
 
 3157  for ( 
const QString &referencedColumn : referencedColumns )
 
 3163      for ( 
const int id : allAttributeIds )
 
 3165        mDefaultValueDependencies.insertMulti( 
id, eww );
 
 3170      mDefaultValueDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
 
 3178  if ( expressionField.isEmpty() )
 
 3183  if ( exp.needsGeometry() )
 
 3184    mNeedsGeometry = 
true;
 
 3186  const QSet<QString> referencedColumns = exp.referencedColumns();
 
 3187  for ( 
const QString &referencedColumn : referencedColumns )
 
 3192      for ( 
const int id : allAttributeIds )
 
 3194        mVirtualFieldsDependencies.insertMulti( 
id, eww );
 
 3199      mVirtualFieldsDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
 
 3209    if ( expressionField.contains( QStringLiteral( 
"relation_aggregate" ) )
 
 3210         || expressionField.contains( QStringLiteral( 
"get_features" ) ) )
 
 3211      mRelatedLayerFieldsDependencies.insert( eww );
 
 3215    mRelatedLayerFieldsDependencies.clear();
 
 3220      if ( ! editorWidgetWrapper )
 
 3223      updateRelatedLayerFieldsDependencies( editorWidgetWrapper );
 
 3228void QgsAttributeForm::setMultiEditFeatureIdsRelations( 
const QgsFeatureIds &fids )
 
 3233    if ( !relationEditorWidget )
 
 3246  mIconMap[eww->
widget()]->hide();
 
 3260        const QString file = QStringLiteral( 
"/mIconJoinNotEditable.svg" );
 
 3261        const QString tooltip = tr( 
"Join settings do not allow editing" );
 
 3262        reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 3266        const QString file = QStringLiteral( 
"mIconJoinHasNotUpsertOnEdit.svg" );
 
 3267        const QString tooltip = tr( 
"Join settings do not allow upsert on edit" );
 
 3268        reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 3272        const QString file = QStringLiteral( 
"/mIconJoinedLayerNotEditable.svg" );
 
 3273        const QString tooltip = tr( 
"Joined layer is not toggled editable" );
 
 3274        reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 3280void QgsAttributeForm::reloadIcon( 
const QString &file, 
const QString &tooltip, QSvgWidget *sw )
 
 3283  sw->setToolTip( tooltip );
 
@ Row
A row of editors (horizontal layout)
 
SelectBehavior
Specifies how a selection should be applied.
 
@ SetSelection
Set selection, removing any existing selection.
 
@ AddToSelection
Add selection to current selection.
 
@ IntersectSelection
Modify current selection to include only select features which match.
 
@ RemoveFromSelection
Remove from current selection.
 
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
 
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
 
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
 
This element will load a layer action onto the form.
 
const QgsAction & action(const QgsVectorLayer *layer) const
Returns the (possibly lazy loaded) action for the given layer.
 
This is a container for attribute editors, used to group them visually in the attribute form if it is...
 
QgsOptionalExpression visibilityExpression() const
The visibility expression is used in the attribute form to show or hide this container based on an ex...
 
QgsOptionalExpression collapsedExpression() const
The collapsed expression is used in the attribute form to set the collapsed status of the group box c...
 
bool collapsed() const
For group box containers returns true if this group box is collapsed.
 
Qgis::AttributeEditorContainerType type() const
Returns the container type.
 
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
 
QColor backgroundColor() const
Returns the background color of the container.
 
int columnCount() const
Gets the number of columns in this group.
 
This class contains context information for attribute editor widgets.
 
FormMode formMode() const
Returns the form mode.
 
QString attributeFormModeString() const
Returns given attributeFormMode as string.
 
@ Embed
A form was embedded as a widget on another form.
 
bool allowCustomUi() const
Returns true if the attribute editor should permit use of custom UI forms.
 
@ SearchMode
Form values are used for searching/filtering the layer.
 
@ FixAttributeMode
Fix feature mode, for modifying the feature attributes without saving. The updated feature is availab...
 
@ IdentifyMode
Identify the feature.
 
@ SingleEditMode
Single edit mode, for editing a single feature.
 
@ AggregateSearchMode
Form is in aggregate search mode, show each widget in this mode.
 
@ MultiEditMode
Multi edit mode, for editing fields of multiple features at once.
 
void setAttributeFormMode(const Mode &attributeFormMode)
Set attributeFormMode for the edited form.
 
This is an abstract base class for any elements of a drag and drop form.
 
LabelStyle labelStyle() const
Returns the label style.
 
Qgis::AttributeEditorType type() const
The type of this element.
 
bool showLabel() const
Controls if this element should be labeled with a title (field, relation or groupname).
 
QString name() const
Returns the name of this element.
 
This element will load a field's widget onto the form.
 
int idx() const
Returns the index of the field.
 
An attribute editor widget that will represent arbitrary HTML code.
 
QString htmlCode() const
The Html code that will be represented within this widget.
 
An attribute editor widget that will represent arbitrary QML code.
 
QString qmlCode() const
The QML code that will be represented within this widget.
 
This element will load a relation editor onto the form.
 
const QgsRelation & relation() const
Gets the id of the relation which shall be embedded.
 
QVariantMap relationEditorConfiguration() const
Returns the relation editor widget configuration.
 
QVariant nmRelationId() const
Determines the relation id of the second relation involved in an N:M relation.
 
bool forceSuppressFormPopup() const
Determines the force suppress form popup status.
 
QString relationWidgetTypeId() const
Returns the current relation widget type id.
 
QString label() const
Determines the label of this element.
 
An attribute editor widget that will represent a spacer.
 
bool drawLine() const
Returns true if the spacer element will contain an horizontal line.
 
An attribute editor widget that will represent arbitrary text code.
 
QString text() const
The Text that will be represented within this widget.
 
A groupbox that collapses/expands when toggled.
 
void setStyleSheet(const QString &style)
Overridden to prepare base call and avoid crash due to specific QT versions.
 
void setCollapsed(bool collapse)
Collapse or uncollapse this groupbox.
 
A groupbox that collapses/expands when toggled and can save its collapsed and checked states.
 
Q_GADGET QString expression
 
Single scope for storing variables and functions for use within a QgsExpressionContext.
 
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
 
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
 
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
 
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
 
Class for parsing and evaluation of expressions (formerly called "search strings").
 
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
 
Wrapper for iterator of features from vector data provider or vector layer.
 
bool nextFeature(QgsFeature &f)
 
This class wraps a request for features to a vector layer (or directly its vector data provider).
 
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
 
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
 
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
 
void setValid(bool validity)
Sets the validity of the feature.
 
bool isValid() const
Returns the validity of this feature.
 
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
 
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
 
ConstraintOrigin
Origin of constraints.
 
@ ConstraintOriginNotSet
Constraint is not set.
 
@ ConstraintOriginLayer
Constraint was set by layer.
 
QString constraintExpression() const
Returns the constraint expression for the field, if set.
 
static QString fieldToolTipExtended(const QgsField &field, const QgsVectorLayer *layer)
Returns a HTML formatted tooltip string for a field, containing details like the field name,...
 
Encapsulate a field in an attribute table or data source.
 
QString displayName() const
Returns the name to use when displaying this field.
 
QgsDefaultValue defaultValueDefinition
 
QgsFieldConstraints constraints
 
Container of fields for a vector layer.
 
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
 
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
 
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
 
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
 
int count() const
Returns number of items.
 
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
 
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
 
bool exists(int i) const
Returns if a field index is valid.
 
int size() 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.
 
A geometry is the spatial representation of a feature.
 
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
 
static bool pythonMacroAllowed(void(*lambda)()=nullptr, QgsMessageBar *messageBar=nullptr)
Returns true if python macros are currently allowed to be run If the global option is to ask user,...
 
static void warning(const QString &msg)
Goes to qWarning.
 
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
 
void editingStarted()
Emitted when editing on this layer has started.
 
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
 
Represents an item shown within a QgsMessageBar widget.
 
A bar for displaying non-blocking messages to the user.
 
bool popWidget(QgsMessageBarItem *item)
Remove the specified item from the bar, and display the next most recent one in the stack.
 
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
 
void pushItem(QgsMessageBarItem *item)
Display a message item on the bar, after hiding the currently visible one and putting it in a stack.
 
QFile * localFile(const QString &filePathOrUrl)
Returns a QFile from a local file or to a temporary file previously fetched by the registry.
 
bool enabled() const
Check if this optional is enabled.
 
T data() const
Access the payload data.
 
QgsRelationManager * relationManager
 
static QgsProject * instance()
Returns the QgsProject singleton instance.
 
bool hasProperty(int key) const override
Returns true if the collection contains a property with the specified key.
 
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
 
A store for object properties.
 
static bool run(const QString &command, const QString &messageOnError=QString())
Execute a Python statement.
 
static bool eval(const QString &command, QString &result)
Eval a Python statement.
 
This class manages a set of relations between layers.
 
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
 
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
 
bool isInvalidJSON()
Returns whether the text edit widget contains Invalid JSON.
 
Wraps a label widget to display text.
 
bool needsGeometry() const
Returns true if the widget needs feature geometry.
 
void setText(const QString &text)
Sets the text code to htmlCode.
 
void reinitWidget()
Clears the content and makes new initialization.
 
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
 
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
 
QList< const QgsVectorLayerJoinInfo * > joinsWhereFieldIsId(const QgsField &field) const
Returns joins where the field of a target layer is considered as an id.
 
QgsFeature joinedFeatureOf(const QgsVectorLayerJoinInfo *info, const QgsFeature &feature) const
Returns the joined feature corresponding to the feature.
 
Defines left outer join from our vector layer to some other vector layer.
 
QStringList * joinFieldNamesSubset() const
Returns the subset of fields to be used from joined layer.
 
bool isDynamicFormEnabled() const
Returns whether the form has to be dynamically updated with joined fields when a feature is being cre...
 
bool hasUpsertOnEdit() const
Returns whether a feature created on the target layer has to impact the joined layer by creating a ne...
 
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
 
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet)
 
static bool fieldIsEditable(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature)
Tests whether a field is editable for a particular feature.
 
Represents a vector layer which manages a vector based data sets.
 
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else.
 
void beforeRemovingExpressionField(int idx)
Will be emitted, when an expression field is going to be deleted from this vector layer.
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
 
QgsFields fields() const FINAL
Returns the list of fields of this layer.
 
QString expressionField(int index) const
Returns the expression used for a given expression field.
 
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
 
Q_INVOKABLE void selectByExpression(const QString &expression, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection, QgsExpressionContext *context=nullptr)
Selects matching features using an expression.
 
void endEditCommand()
Finish edit command and add it to undo/redo stack.
 
void destroyEditCommand()
Destroy active command and reverts all changes in it.
 
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
 
bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap(), bool skipDefaultValues=false)
Changes attributes' values for a feature (but does not immediately commit the changes).
 
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
 
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
 
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
 
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
 
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
 
void beforeAddingExpressionField(const QString &fieldName)
Will be emitted, when an expression field is going to be added to this vector layer.
 
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
 
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.
 
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
 
QgsEditFormConfig editFormConfig
 
void beforeModifiedCheck() const
Emitted when the layer is checked for modifications. Use for last-minute additions.
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
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...
 
#define Q_NOWARN_DEPRECATED_POP
 
#define Q_NOWARN_DEPRECATED_PUSH
 
QMap< int, QVariant > QgsAttributeMap
 
QSet< QgsFeatureId > QgsFeatureIds
 
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)