17#include "moc_qgsattributeform.cpp" 
   76int QgsAttributeForm::sFormCounter = 0;
 
   81  , mOwnsMessageBar( true )
 
   83  , mFormNr( sFormCounter++ )
 
   85  , mPreventFeatureRefresh( false )
 
   86  , mIsSettingMultiEditFeatures( false )
 
   87  , mUnsavedMultiEditChanges( false )
 
   88  , mEditCommandMessage( tr( 
"Attributes changed" ) )
 
  101  updateContainersVisibility();
 
  103  updateEditableState();
 
 
  109  qDeleteAll( mInterfaces );
 
 
  136  mInterfaces.append( iface );
 
 
  152    if ( mUnsavedMultiEditChanges )
 
  155      int res = QMessageBox::question( 
this, tr( 
"Multiedit Attributes" ), tr( 
"Apply changes to edited features?" ), QMessageBox::Yes | QMessageBox::No );
 
  156      if ( res == QMessageBox::Yes )
 
  161    clearMultiEditMessages();
 
  163  mUnsavedMultiEditChanges = 
false;
 
  215    w->setContext( newContext );
 
  221    w->setVisible( relationWidgetsVisible );
 
  228      mSearchButtonBox->setVisible( 
false );
 
  233      mSearchButtonBox->setVisible( 
false );
 
  238      mSearchButtonBox->setVisible( 
false );
 
  242      resetMultiEdit( 
false );
 
  244      mSearchButtonBox->setVisible( 
false );
 
  248      mSearchButtonBox->setVisible( 
true );
 
  254      mSearchButtonBox->setVisible( 
false );
 
  262      mSearchButtonBox->setVisible( 
false );
 
 
  271  const auto constMWidgets = mWidgets;
 
  286        QVariant mainValue = eww->
value();
 
  288        additionalFieldValues[index] = value;
 
  289        eww->
setValues( mainValue, additionalFieldValues );
 
 
  303  mIsSettingFeature = 
true;
 
  320      mIsSettingFeature = 
false;
 
  321      const auto constMInterfaces = mInterfaces;
 
  324        iface->featureChanged();
 
  340  mIsSettingFeature = 
false;
 
 
  343bool QgsAttributeForm::saveEdits( QString *error )
 
  346  bool changedLayer = 
false;
 
  351    bool doUpdate = 
false;
 
  373            *error = tr( 
"JSON value for %1 is invalid and has not been saved" ).arg( eww->
field().
name() );
 
  376        QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
 
  377        QVariantList srcVars = QVariantList() << eww->
value();
 
  378        QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
  382        for ( 
const QString &fieldName : additionalFields )
 
  386          dstVars << dst.at( idx );
 
  390        Q_ASSERT( dstVars.count() == srcVars.count() );
 
  392        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)" ).arg( dst.at( i ).toString(), dst.at( i ).typeName() ).arg( 
QgsVariantUtils::isNull( dst.at( i ) ) ).arg( dst.at( i ).isValid() ), 2 );
 
  455          QgsDebugMsgLevel( QStringLiteral( 
"src:'%1' (type:%2, isNull:%3, isValid:%4)" ).arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( 
QgsVariantUtils::isNull( src.at( i ) ) ).arg( src.at( i ).isValid() ), 2 );
 
  457          newValues[i] = dst.at( i );
 
  458          oldValues[i] = src.at( i );
 
  463        auto context = std::make_unique<QgsVectorLayerToolsContext>();
 
  465        context->setExpressionContext( &expressionContext );
 
  468        if ( success && n > 0 )
 
  495QgsFeature QgsAttributeForm::getUpdatedFeature()
 const 
  507    QVariantList dstVars = QVariantList() << featureAttributes.at( eww->
fieldIdx() );
 
  508    QVariantList srcVars = QVariantList() << eww->
value();
 
  509    QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
  513    for ( 
const QString &fieldName : additionalFields )
 
  517      dstVars << featureAttributes.at( idx );
 
  521    Q_ASSERT( dstVars.count() == srcVars.count() );
 
  523    for ( 
int i = 0; i < dstVars.count(); i++ )
 
  525      if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() )
 
  526        featureAttributes[fieldIndexes[i]] = srcVars[i];
 
  531  return updatedFeature;
 
  534void QgsAttributeForm::updateValuesDependencies( 
const int originIdx )
 
  536  updateValuesDependenciesDefaultValues( originIdx );
 
  537  updateValuesDependenciesVirtualFields( originIdx );
 
  540void QgsAttributeForm::updateValuesDependenciesDefaultValues( 
const int originIdx )
 
  542  if ( !mDefaultValueDependencies.contains( originIdx ) )
 
  550  QgsFeature updatedFeature = getUpdatedFeature();
 
  553  QList<QgsWidgetWrapper *> relevantWidgets = mDefaultValueDependencies.values( originIdx );
 
  570      if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
 
  582void QgsAttributeForm::updateValuesDependenciesVirtualFields( 
const int originIdx )
 
  584  if ( !mVirtualFieldsDependencies.contains( originIdx ) )
 
  591  QgsFeature updatedFeature = getUpdatedFeature();
 
  594  const QList<QgsWidgetWrapper *> relevantWidgets = mVirtualFieldsDependencies.values( originIdx );
 
  602    if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
 
  608    const QVariant value = exp.evaluate( &context );
 
  614void QgsAttributeForm::updateValuesDependenciesParent()
 
  617  QgsFeature updatedFeature = getUpdatedFeature();
 
  618  QList<int> updatedFields;
 
  621  const QSet<QgsEditorWidgetWrapper *> relevantWidgets = mParentDependencies;
 
  625    if ( updatedFields.contains( eww->
fieldIdx() ) )
 
  636void QgsAttributeForm::updateRelatedLayerFields()
 
  639  updateRelatedLayerFieldsDependencies();
 
  641  if ( mRelatedLayerFieldsDependencies.isEmpty() )
 
  648  QgsFeature updatedFeature = getUpdatedFeature();
 
  651  const QSet<QgsEditorWidgetWrapper *> relevantWidgets = mRelatedLayerFieldsDependencies;
 
  655    if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
 
  661    QVariant value = exp.evaluate( &context );
 
  666void QgsAttributeForm::resetMultiEdit( 
bool promptToSave )
 
  671  mUnsavedMultiEditChanges = 
false;
 
  675void QgsAttributeForm::multiEditMessageClicked( 
const QString &link )
 
  677  clearMultiEditMessages();
 
  678  resetMultiEdit( link == QLatin1String( 
"#apply" ) );
 
  681void QgsAttributeForm::filterTriggered()
 
  683  QString filter = createFilterExpression();
 
  689void QgsAttributeForm::searchZoomTo()
 
  691  QString filter = createFilterExpression();
 
  692  if ( filter.isEmpty() )
 
  698void QgsAttributeForm::searchFlash()
 
  700  QString filter = createFilterExpression();
 
  701  if ( filter.isEmpty() )
 
  707void QgsAttributeForm::filterAndTriggered()
 
  709  QString filter = createFilterExpression();
 
  710  if ( filter.isEmpty() )
 
  718void QgsAttributeForm::filterOrTriggered()
 
  720  QString filter = createFilterExpression();
 
  721  if ( filter.isEmpty() )
 
  729void QgsAttributeForm::pushSelectedFeaturesMessage()
 
  749  QString filter = createFilterExpression();
 
  750  if ( filter.isEmpty() )
 
  754  pushSelectedFeaturesMessage();
 
  759void QgsAttributeForm::searchSetSelection()
 
  764void QgsAttributeForm::searchAddToSelection()
 
  769void QgsAttributeForm::searchRemoveFromSelection()
 
  774void QgsAttributeForm::searchIntersectSelection()
 
  779bool QgsAttributeForm::saveMultiEdits()
 
  783  const QList<int> fieldIndexes = mFormEditorWidgets.uniqueKeys();
 
  784  for ( 
int fieldIndex : fieldIndexes )
 
  786    const QList<QgsAttributeFormEditorWidget *> widgets = mFormEditorWidgets.values( fieldIndex );
 
  787    if ( !widgets.first()->hasChanged() )
 
  790    if ( !widgets.first()->currentValue().isValid() 
 
  791         || !fieldIsEditable( fieldIndex ) )        
 
  798      widget->changesCommitted();
 
  800    newAttributeValues.insert( fieldIndex, widgets.first()->currentValue() );
 
  803  if ( newAttributeValues.isEmpty() )
 
  811  int res = QMessageBox::information( 
this, tr( 
"Multiedit Attributes" ),
 
  812                                      tr( 
"Edits will be applied to all selected features." ), QMessageBox::Ok | QMessageBox::Cancel );
 
  813  if ( res != QMessageBox::Ok )
 
  824  const auto constMultiEditFeatureIds = mMultiEditFeatureIds;
 
  827    QgsAttributeMap::const_iterator aIt = newAttributeValues.constBegin();
 
  828    for ( ; aIt != newAttributeValues.constEnd(); ++aIt )
 
  834  clearMultiEditMessages();
 
  847  if ( !mButtonBox->isVisible() )
 
  848    mMessageBar->
pushItem( mMultiEditMessageBarItem );
 
  874    wrapper->notifyAboutToSave();
 
  914      success = saveEdits( error );
 
  918      success = saveMultiEdits();
 
  923  mUnsavedMultiEditChanges = 
false;
 
 
  932  mValuesInitialized = 
false;
 
  933  const auto constMWidgets = mWidgets;
 
  936    ww->setFeature( mFeature );
 
  947    mAlreadyUpdatedFields.append( eww->
fieldIdx() );
 
  948    updateValuesDependenciesVirtualFields( eww->
fieldIdx() );
 
  949    mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
 
  952  mValuesInitialized = 
true;
 
 
  958  const auto widgets { findChildren<QgsAttributeFormEditorWidget *>() };
 
 
  965void QgsAttributeForm::clearMultiEditMessages()
 
  967  if ( mMultiEditUnsavedMessageBarItem )
 
  969    if ( !mButtonBox->isVisible() )
 
  970      mMessageBar->
popWidget( mMultiEditUnsavedMessageBarItem );
 
  971    mMultiEditUnsavedMessageBarItem = 
nullptr;
 
  973  if ( mMultiEditMessageBarItem )
 
  975    if ( !mButtonBox->isVisible() )
 
  976      mMessageBar->
popWidget( mMultiEditMessageBarItem );
 
  977    mMultiEditMessageBarItem = 
nullptr;
 
  981QString QgsAttributeForm::createFilterExpression()
 const 
  986    QString filter = w->currentFilterExpression();
 
  987    if ( !filter.isEmpty() )
 
  991  if ( filters.isEmpty() )
 
  994  QString filter = filters.join( QLatin1String( 
") AND (" ) ).prepend( 
'(' ).append( 
')' );
 
 1003  if ( mExtraContextScope )
 
 1016void QgsAttributeForm::onAttributeChanged( 
const QVariant &value, 
const QVariantList &additionalFieldValues )
 
 1021  bool signalEmitted = 
false;
 
 1023  if ( mValuesInitialized )
 
 1030  const QList<QgsAttributeFormEditorWidget *> formEditorWidgets = mFormEditorWidgets.values( eww->
fieldIdx() );
 
 1033    if ( formEditorWidget->editorWidget() == eww )
 
 1037    formEditorWidget->editorWidget()->setValue( value );
 
 1054      for ( 
int i = 0; i < additionalFields.count(); i++ )
 
 1056        const QString fieldName = additionalFields.at( i );
 
 1057        const QVariant value = additionalFieldValues.at( i );
 
 1061      signalEmitted = 
true;
 
 1063      if ( mValuesInitialized )
 
 1064        updateJoinedFields( *eww );
 
 1070      if ( !mIsSettingMultiEditFeatures )
 
 1072        mUnsavedMultiEditChanges = 
true;
 
 1074        QLabel *msgLabel = 
new QLabel( tr( 
"Unsaved multiedit changes: <a href=\"#apply\">apply changes</a> or <a href=\"#reset\">reset changes</a>." ), mMessageBar );
 
 1075        msgLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
 
 1076        msgLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
 
 1077        connect( msgLabel, &QLabel::linkActivated, 
this, &QgsAttributeForm::multiEditMessageClicked );
 
 1078        clearMultiEditMessages();
 
 1081        if ( !mButtonBox->isVisible() )
 
 1082          mMessageBar->
pushItem( mMultiEditUnsavedMessageBarItem );
 
 1085        signalEmitted = 
true;
 
 1095  updateConstraints( eww );
 
 1098  if ( mValuesInitialized )
 
 1101    mAlreadyUpdatedFields.append( eww->
fieldIdx() );
 
 1102    updateValuesDependencies( eww->
fieldIdx() );
 
 1103    mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
 
 1108  updateEditableState();
 
 1110  if ( !signalEmitted )
 
 1115    bool attributeHasChanged = !mIsSettingFeature;
 
 1117      attributeHasChanged &= !mIsSettingMultiEditFeatures;
 
 1123void QgsAttributeForm::updateAllConstraints()
 
 1125  const auto constMWidgets = mWidgets;
 
 1130      updateConstraints( eww );
 
 1138  if ( currentFormValuesFeature( ft ) )
 
 1150    updateConstraint( ft, eww );
 
 1153    const QList<QgsEditorWidgetWrapper *> deps = constraintDependencies( eww );
 
 1156      updateConstraint( ft, depsEww );
 
 1164    const QVector<ContainerInformation *> infos = mContainerInformationDependency.value( eww->
field().
name() );
 
 1165    for ( ContainerInformation *info : infos )
 
 1167      info->apply( &context );
 
 1172void QgsAttributeForm::updateContainersVisibility()
 
 1176  const QVector<ContainerInformation *> infos = mContainerVisibilityCollapsedInformation;
 
 1178  for ( ContainerInformation *info : infos )
 
 1180    info->apply( &context );
 
 1190    updateAllConstraints();
 
 1205      if ( mJoinedFeatures.contains( info ) )
 
 1221void QgsAttributeForm::updateLabels()
 
 1223  if ( !mLabelDataDefinedProperties.isEmpty() )
 
 1226    if ( currentFormValuesFeature( currentFeature ) )
 
 1230      for ( 
auto it = mLabelDataDefinedProperties.constBegin(); it != mLabelDataDefinedProperties.constEnd(); ++it )
 
 1232        QLabel *label { it.key() };
 
 1234        const QString value { it->valueAsString( context, QString(), &ok ) };
 
 1235        if ( ok && !value.isEmpty() )
 
 1237          label->setText( value );
 
 1244void QgsAttributeForm::updateEditableState()
 
 1246  if ( !mEditableDataDefinedProperties.isEmpty() )
 
 1249    if ( currentFormValuesFeature( currentFeature ) )
 
 1253      for ( 
auto it = mEditableDataDefinedProperties.constBegin(); it != mEditableDataDefinedProperties.constEnd(); ++it )
 
 1255        QWidget *w { it.key() };
 
 1257        const bool isEditable { it->valueAsBool( context, 
true, &ok ) && mLayer && mLayer->
isEditable() }; 
 
 1267            w->setEnabled( isEditable );
 
 1275bool QgsAttributeForm::currentFormValuesFeature( 
QgsFeature &feature )
 
 1288    if ( dst.count() > eww->
fieldIdx() )
 
 1290      QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
 
 1291      QVariantList srcVars = QVariantList() << eww->
value();
 
 1292      QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
 1296      for ( 
const QString &fieldName : additionalFields )
 
 1299        fieldIndexes << idx;
 
 1300        dstVars << dst.at( idx );
 
 1304      Q_ASSERT( dstVars.count() == srcVars.count() );
 
 1306      for ( 
int i = 0; i < dstVars.count(); i++ )
 
 1312          dst[fieldIndexes[i]] = srcVars[i];
 
 1329void QgsAttributeForm::registerContainerInformation( QgsAttributeForm::ContainerInformation *info )
 
 1331  mContainerVisibilityCollapsedInformation.append( info );
 
 1333  const QSet<QString> referencedColumns = info->expression.referencedColumns().unite( info->collapsedExpression.referencedColumns() );
 
 1335  for ( 
const QString &col : referencedColumns )
 
 1337    mContainerInformationDependency[col].append( info );
 
 1341bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions )
 const 
 1343  bool valid { 
true };
 
 1365bool QgsAttributeForm::currentFormValidHardConstraints( QStringList &invalidFields, QStringList &descriptions )
 const 
 1367  bool valid { 
true };
 
 1386void QgsAttributeForm::onAttributeAdded( 
int idx )
 
 1388  mPreventFeatureRefresh = 
false;
 
 1400void QgsAttributeForm::onAttributeDeleted( 
int idx )
 
 1402  mPreventFeatureRefresh = 
false;
 
 1406    attrs.remove( idx );
 
 1414void QgsAttributeForm::onRelatedFeaturesChanged()
 
 1416  updateRelatedLayerFields();
 
 1419void QgsAttributeForm::onUpdatedFields()
 
 1421  mPreventFeatureRefresh = 
false;
 
 1453  const QList<QgsAttributeFormEditorWidget *> formEditorWidgets = mFormEditorWidgets.values( eww->
fieldIdx() );
 
 1457    formEditorWidget->setConstraintStatus( constraint, description, err, result );
 
 1458    if ( formEditorWidget->editorWidget() != eww )
 
 1460      formEditorWidget->editorWidget()->updateConstraint( result, err );
 
 1467  QList<QgsEditorWidgetWrapper *> wDeps;
 
 1479      if ( name != ewwName )
 
 1486        for ( 
const QString &colName : referencedColumns )
 
 1488          if ( name.compare( colName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
 
 1490            wDeps.append( eww );
 
 1503  return setupRelationWidgetWrapper( QString(), rel, context );
 
 1516void QgsAttributeForm::preventFeatureRefresh()
 
 1518  mPreventFeatureRefresh = 
true;
 
 1544  updateValuesDependenciesParent();
 
 
 1558  return mNeedsGeometry;
 
 
 1561void QgsAttributeForm::synchronizeState()
 
 1563  bool isEditable = ( mFeature.
isValid()
 
 1573      const QList<QgsAttributeFormEditorWidget *> formWidgets = mFormEditorWidgets.values( eww->
fieldIdx() );
 
 1576        formWidget->setConstraintResultVisible( isEditable );
 
 1580      bool enabled = isEditable && fieldIsEditable( eww->
fieldIdx() );
 
 1581      ww->setEnabled( enabled );
 
 1587      ww->setEnabled( isEditable );
 
 1597      if ( mConstraintsFailMessageBarItem )
 
 1599        mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
 
 1602      mMessageBar->
pushItem( mConstraintsFailMessageBarItem );
 
 1606      QStringList invalidFields, descriptions;
 
 1607      mValidConstraints = currentFormValidHardConstraints( invalidFields, descriptions );
 
 1611        if ( !mValidConstraints && !mConstraintsFailMessageBarItem )
 
 1613          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 );
 
 1614          mMessageBar->
pushItem( mConstraintsFailMessageBarItem );
 
 1616        else if ( mValidConstraints && mConstraintsFailMessageBarItem )
 
 1618          mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
 
 1619          mConstraintsFailMessageBarItem = 
nullptr;
 
 1622      else if ( mConstraintsFailMessageBarItem )
 
 1624        mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
 
 1625        mConstraintsFailMessageBarItem = 
nullptr;
 
 1628      isEditable = isEditable & mValidConstraints;
 
 1633  QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
 
 1635    okButton->setEnabled( isEditable );
 
 1638void QgsAttributeForm::init()
 
 1640  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
 
 1643  QWidget *formWidget = 
nullptr;
 
 1644  mNeedsGeometry = 
false;
 
 1646  bool buttonBoxVisible = 
true;
 
 1650    buttonBoxVisible = mButtonBox->isVisible();
 
 1652    mButtonBox = 
nullptr;
 
 1655  if ( mSearchButtonBox )
 
 1657    delete mSearchButtonBox;
 
 1658    mSearchButtonBox = 
nullptr;
 
 1661  qDeleteAll( mWidgets );
 
 1664  while ( QWidget *w = this->findChild<QWidget *>() )
 
 1670  QVBoxLayout *vl = 
new QVBoxLayout();
 
 1671  vl->setContentsMargins( 0, 0, 0, 0 );
 
 1673  mMessageBar->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
 
 1674  vl->addWidget( mMessageBar );
 
 1679  QGridLayout *layout = 
new QGridLayout();
 
 1680  QWidget *container = 
new QWidget();
 
 1681  container->setLayout( layout );
 
 1682  vl->addWidget( container );
 
 1684  mFormEditorWidgets.clear();
 
 1685  mFormWidgets.clear();
 
 1688  setContentsMargins( 0, 0, 0, 0 );
 
 1696    if ( file && file->open( QFile::ReadOnly ) )
 
 1700      QFileInfo fi( file->fileName() );
 
 1701      loader.setWorkingDirectory( fi.dir() );
 
 1702      formWidget = loader.load( file, 
this );
 
 1705        formWidget->setWindowFlags( Qt::Widget );
 
 1706        layout->addWidget( formWidget );
 
 1709        mButtonBox = findChild<QDialogButtonBox *>();
 
 1712        formWidget->installEventFilter( 
this );
 
 1724    int columnCount = 1;
 
 1725    bool hasRootFields = 
false;
 
 1726    bool addSpacer = 
true;
 
 1735        if ( !containerDef )
 
 1738        switch ( containerDef->
type() )
 
 1742            tabWidget = 
nullptr;
 
 1743            WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
 
 1744            if ( widgetInfo.labelStyle.overrideColor )
 
 1746              if ( widgetInfo.labelStyle.color.isValid() )
 
 1748                widgetInfo.widget->setStyleSheet( QStringLiteral( 
"QGroupBox::title { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 1751            if ( widgetInfo.labelStyle.overrideFont )
 
 1753              widgetInfo.widget->setFont( widgetInfo.labelStyle.font );
 
 1756            layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
 
 1757            if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1759              layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1761            if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1763              layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1777            tabWidget = 
nullptr;
 
 1778            WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
 
 1779            layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
 
 1780            if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1782              layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1785            if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1787              layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1803              layout->addWidget( tabWidget, row, column, 1, 2 );
 
 1807            QWidget *tabPage = 
new QWidget( tabWidget );
 
 1809            tabWidget->addTab( tabPage, widgDef->name() );
 
 1810            tabWidget->
setTabStyle( tabWidget->tabBar()->count() - 1, widgDef->labelStyle() );
 
 1814              registerContainerInformation( 
new ContainerInformation( tabWidget, tabPage, containerDef->
visibilityExpression().
data() ) );
 
 1816            QGridLayout *tabPageLayout = 
new QGridLayout();
 
 1817            tabPage->setLayout( tabPageLayout );
 
 1819            WidgetInfo widgetInfo = createWidgetFromDef( widgDef, tabPage, mLayer, mContext );
 
 1820            tabPageLayout->addWidget( widgetInfo.widget );
 
 1827        hasRootFields = 
true;
 
 1828        tabWidget = 
nullptr;
 
 1829        WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
 
 1832        if ( widgetInfo.showLabel )
 
 1834          if ( widgetInfo.labelStyle.overrideColor && widgetInfo.labelStyle.color.isValid() )
 
 1836            collapsibleGroupBox->
setStyleSheet( QStringLiteral( 
"QGroupBox::title { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 1839          if ( widgetInfo.labelStyle.overrideFont )
 
 1841            collapsibleGroupBox->setFont( widgetInfo.labelStyle.font );
 
 1844          collapsibleGroupBox->setTitle( widgetInfo.labelText );
 
 1847        QVBoxLayout *collapsibleGroupBoxLayout = 
new QVBoxLayout();
 
 1848        collapsibleGroupBoxLayout->addWidget( widgetInfo.widget );
 
 1849        collapsibleGroupBox->setLayout( collapsibleGroupBoxLayout );
 
 1851        QVBoxLayout *
c = 
new QVBoxLayout();
 
 1852        c->addWidget( collapsibleGroupBox );
 
 1853        layout->addLayout( 
c, row, column, 1, 2 );
 
 1855        if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1856          layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1857        if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1858          layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1867        hasRootFields = 
true;
 
 1868        tabWidget = 
nullptr;
 
 1869        WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
 
 1870        QLabel *label = 
new QLabel( widgetInfo.labelText );
 
 1872        if ( widgetInfo.labelStyle.overrideColor )
 
 1874          if ( widgetInfo.labelStyle.color.isValid() )
 
 1876            label->setStyleSheet( QStringLiteral( 
"QLabel { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 1880        if ( widgetInfo.labelStyle.overrideFont )
 
 1882          label->setFont( widgetInfo.labelStyle.font );
 
 1885        label->setToolTip( widgetInfo.toolTip );
 
 1886        if ( columnCount > 1 && !widgetInfo.labelOnTop )
 
 1888          label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
 
 1891        label->setBuddy( widgetInfo.widget );
 
 1894        if ( widgetInfo.widget
 
 1895             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Fixed
 
 1896             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Maximum
 
 1897             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Preferred )
 
 1900        if ( !widgetInfo.showLabel )
 
 1902          QVBoxLayout *
c = 
new QVBoxLayout();
 
 1903          label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 1904          c->addWidget( widgetInfo.widget );
 
 1905          layout->addLayout( 
c, row, column, 1, 2 );
 
 1907          if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1909            layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1912          if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1914            layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1919        else if ( widgetInfo.labelOnTop )
 
 1921          QVBoxLayout *
c = 
new QVBoxLayout();
 
 1922          label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 1923          c->addWidget( label );
 
 1924          c->addWidget( widgetInfo.widget );
 
 1925          layout->addLayout( 
c, row, column, 1, 2 );
 
 1927          if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1929            layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1932          if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( column + 1 ) )
 
 1934            layout->setColumnStretch( column + 1, widgDef->horizontalStretch() );
 
 1941          const int widgetColumn = column + 1;
 
 1942          layout->addWidget( label, row, column++ );
 
 1943          layout->addWidget( widgetInfo.widget, row, column++ );
 
 1945          if ( widgDef->verticalStretch() > 0 && widgDef->verticalStretch() > layout->rowStretch( row ) )
 
 1947            layout->setRowStretch( row, widgDef->verticalStretch() );
 
 1950          if ( widgDef->horizontalStretch() > 0 && widgDef->horizontalStretch() > layout->columnStretch( widgetColumn ) )
 
 1952            layout->setColumnStretch( widgetColumn, widgDef->horizontalStretch() );
 
 1960          const int fieldIdx = fieldElement->
idx();
 
 1961          if ( fieldIdx >= 0 && fieldIdx < mLayer->fields().count() )
 
 1963            const QString fieldName { mLayer->
fields().
at( fieldIdx ).
name() };
 
 1967              if ( property.isActive() )
 
 1969                mLabelDataDefinedProperties[label] = property;
 
 1975              if ( property.isActive() )
 
 1977                mEditableDataDefinedProperties[widgetInfo.widget] = property;
 
 1984      if ( column >= columnCount * 2 )
 
 1991    if ( hasRootFields && addSpacer )
 
 1993      QSpacerItem *spacerItem = 
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
 
 1994      layout->addItem( spacerItem, row, 0 );
 
 1995      layout->setRowStretch( row, 1 );
 
 1998    formWidget = container;
 
 2007    formWidget = 
new QWidget( 
this );
 
 2008    QGridLayout *gridLayout = 
new QGridLayout( formWidget );
 
 2009    formWidget->setLayout( gridLayout );
 
 2015      scrollArea->setWidget( formWidget );
 
 2016      scrollArea->setWidgetResizable( 
true );
 
 2017      scrollArea->setFrameShape( QFrame::NoFrame );
 
 2018      scrollArea->setFrameShadow( QFrame::Plain );
 
 2019      scrollArea->setFocusProxy( 
this );
 
 2020      layout->addWidget( scrollArea );
 
 2024      layout->addWidget( formWidget );
 
 2031    for ( 
const QgsField &field : fields )
 
 2039      QString labelText = fieldName;
 
 2040      labelText.replace( 
'&', QLatin1String( 
"&&" ) ); 
 
 2044      if ( widgetSetup.
type() == QLatin1String( 
"Hidden" ) )
 
 2050      QLabel *label = 
new QLabel( labelText );
 
 2052      QSvgWidget *i = 
new QSvgWidget();
 
 2053      i->setFixedSize( 18, 18 );
 
 2058        if ( property.isActive() )
 
 2060          mLabelDataDefinedProperties[label] = property;
 
 2066      QWidget *w = 
nullptr;
 
 2071        mFormEditorWidgets.insert( idx, formWidget );
 
 2072        mFormWidgets.append( formWidget );
 
 2075        label->setBuddy( eww->
widget() );
 
 2080          if ( property.isActive() )
 
 2082            mEditableDataDefinedProperties[formWidget] = property;
 
 2088        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() ) ) );
 
 2093        w->setObjectName( field.name() );
 
 2097        mWidgets.append( eww );
 
 2098        mIconMap[eww->
widget()] = i;
 
 2103        gridLayout->addWidget( label, row++, 0, 1, 2 );
 
 2104        gridLayout->addWidget( w, row++, 0, 1, 2 );
 
 2105        gridLayout->addWidget( i, row++, 0, 1, 2 );
 
 2109        gridLayout->addWidget( label, row, 0 );
 
 2110        gridLayout->addWidget( w, row, 1 );
 
 2111        gridLayout->addWidget( i, row++, 2 );
 
 2124      QVBoxLayout *collapsibleGroupBoxLayout = 
new QVBoxLayout();
 
 2125      collapsibleGroupBoxLayout->addWidget( formWidget );
 
 2126      collapsibleGroupBox->setLayout( collapsibleGroupBoxLayout );
 
 2128      gridLayout->addWidget( collapsibleGroupBox, row++, 0, 1, 2 );
 
 2130      mWidgets.append( rww );
 
 2131      mFormWidgets.append( formWidget );
 
 2136      QSpacerItem *spacerItem = 
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
 
 2137      gridLayout->addItem( spacerItem, row, 0 );
 
 2138      gridLayout->setRowStretch( row, 1 );
 
 2144  updateFieldDependencies();
 
 2148    mButtonBox = 
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
 
 2149    mButtonBox->setObjectName( QStringLiteral( 
"buttonBox" ) );
 
 2150    layout->addWidget( mButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
 
 2152  mButtonBox->setVisible( buttonBoxVisible );
 
 2154  if ( !mSearchButtonBox )
 
 2156    mSearchButtonBox = 
new QWidget();
 
 2157    QHBoxLayout *boxLayout = 
new QHBoxLayout();
 
 2158    boxLayout->setContentsMargins( 0, 0, 0, 0 );
 
 2159    mSearchButtonBox->setLayout( boxLayout );
 
 2160    mSearchButtonBox->setObjectName( QStringLiteral( 
"searchButtonBox" ) );
 
 2162    QPushButton *clearButton = 
new QPushButton( tr( 
"&Reset Form" ), mSearchButtonBox );
 
 2164    boxLayout->addWidget( clearButton );
 
 2165    boxLayout->addStretch( 1 );
 
 2167    QPushButton *flashButton = 
new QPushButton();
 
 2168    flashButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2169    flashButton->setText( tr( 
"&Flash Features" ) );
 
 2170    connect( flashButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchFlash );
 
 2171    boxLayout->addWidget( flashButton );
 
 2173    QPushButton *openAttributeTableButton = 
new QPushButton();
 
 2174    openAttributeTableButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2175    openAttributeTableButton->setText( tr( 
"Show in &Table" ) );
 
 2176    openAttributeTableButton->setToolTip( tr( 
"Open the attribute table editor with the filtered features" ) );
 
 2177    connect( openAttributeTableButton, &QToolButton::clicked, 
this, [
this] {
 
 2180    boxLayout->addWidget( openAttributeTableButton );
 
 2182    QPushButton *zoomButton = 
new QPushButton();
 
 2183    zoomButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2184    zoomButton->setText( tr( 
"&Zoom to Features" ) );
 
 2185    connect( zoomButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchZoomTo );
 
 2186    boxLayout->addWidget( zoomButton );
 
 2188    QToolButton *selectButton = 
new QToolButton();
 
 2189    selectButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2190    selectButton->setText( tr( 
"&Select Features" ) );
 
 2192    selectButton->setPopupMode( QToolButton::MenuButtonPopup );
 
 2193    selectButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
 
 2194    connect( selectButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchSetSelection );
 
 2195    QMenu *selectMenu = 
new QMenu( selectButton );
 
 2196    QAction *selectAction = 
new QAction( tr( 
"Select Features" ), selectMenu );
 
 2198    connect( selectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchSetSelection );
 
 2199    selectMenu->addAction( selectAction );
 
 2200    QAction *addSelectAction = 
new QAction( tr( 
"Add to Current Selection" ), selectMenu );
 
 2202    connect( addSelectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchAddToSelection );
 
 2203    selectMenu->addAction( addSelectAction );
 
 2204    QAction *deselectAction = 
new QAction( tr( 
"Remove from Current Selection" ), selectMenu );
 
 2206    connect( deselectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchRemoveFromSelection );
 
 2207    selectMenu->addAction( deselectAction );
 
 2208    QAction *filterSelectAction = 
new QAction( tr( 
"Filter Current Selection" ), selectMenu );
 
 2210    connect( filterSelectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchIntersectSelection );
 
 2211    selectMenu->addAction( filterSelectAction );
 
 2212    selectButton->setMenu( selectMenu );
 
 2213    boxLayout->addWidget( selectButton );
 
 2217      QToolButton *filterButton = 
new QToolButton();
 
 2218      filterButton->setText( tr( 
"Filter Features" ) );
 
 2219      filterButton->setPopupMode( QToolButton::MenuButtonPopup );
 
 2220      filterButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 2221      connect( filterButton, &QToolButton::clicked, 
this, &QgsAttributeForm::filterTriggered );
 
 2222      QMenu *filterMenu = 
new QMenu( filterButton );
 
 2223      QAction *filterAndAction = 
new QAction( tr( 
"Filter Within (\"AND\")" ), filterMenu );
 
 2224      connect( filterAndAction, &QAction::triggered, 
this, &QgsAttributeForm::filterAndTriggered );
 
 2225      filterMenu->addAction( filterAndAction );
 
 2226      QAction *filterOrAction = 
new QAction( tr( 
"Extend Filter (\"OR\")" ), filterMenu );
 
 2227      connect( filterOrAction, &QAction::triggered, 
this, &QgsAttributeForm::filterOrTriggered );
 
 2228      filterMenu->addAction( filterOrAction );
 
 2229      filterButton->setMenu( filterMenu );
 
 2230      boxLayout->addWidget( filterButton );
 
 2234      QPushButton *closeButton = 
new QPushButton( tr( 
"Close" ), mSearchButtonBox );
 
 2236      closeButton->setShortcut( Qt::Key_Escape );
 
 2237      boxLayout->addWidget( closeButton );
 
 2240    layout->addWidget( mSearchButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
 
 2258  const auto constMInterfaces = mInterfaces;
 
 2269  QApplication::restoreOverrideCursor();
 
 2272void QgsAttributeForm::cleanPython()
 
 2274  if ( !mPyFormVarName.isNull() )
 
 2276    QString expr = QStringLiteral( 
"if '%1' in locals(): del %1\n" ).arg( mPyFormVarName );
 
 2281void QgsAttributeForm::initPython()
 
 2297        if ( !initFilePath.isEmpty() )
 
 2301          if ( inputFile && inputFile->open( QFile::ReadOnly ) )
 
 2304            QTextStream inf( inputFile );
 
 2305#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) 
 2306            inf.setCodec( 
"UTF-8" );
 
 2308            initCode = inf.readAll();
 
 2313            QgsLogger::warning( QStringLiteral( 
"The external python file path %1 could not be opened!" ).arg( initFilePath ) );
 
 2324        if ( initCode.isEmpty() )
 
 2326          QgsLogger::warning( QStringLiteral( 
"The python code provided in the dialog is empty!" ) );
 
 2337    if ( !initCode.isEmpty() )
 
 2349    if ( 
QgsPythonRunner::eval( QStringLiteral( 
"len(inspect.getfullargspec(%1)[0])" ).arg( initFunction ), numArgs ) )
 
 2351      static int sFormId = 0;
 
 2352      mPyFormVarName = QStringLiteral( 
"_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
 
 2354      QString form = QStringLiteral( 
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
 
 2355                       .arg( mPyFormVarName )
 
 2356                       .arg( ( quint64 ) 
this );
 
 2360      QgsDebugMsgLevel( QStringLiteral( 
"running featureForm init: %1" ).arg( mPyFormVarName ), 2 );
 
 2363      if ( numArgs == QLatin1String( 
"3" ) )
 
 2371        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 ) );
 
 2374        QString expr = QString( 
"%1(%2)" )
 
 2375                       .arg( mLayer->editFormInit() )
 
 2376                       .arg( mPyFormVarName );
 
 2377        QgsAttributeFormInterface *iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface *>( expr, 
"QgsAttributeFormInterface" );
 
 2387      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 ) );
 
 2395  WidgetInfo newWidgetInfo;
 
 2397  newWidgetInfo.labelStyle = widgetDef->
labelStyle();
 
 2399  switch ( widgetDef->
type() )
 
 2411      mWidgets.append( actionWrapper );
 
 2412      newWidgetInfo.widget = actionWrapper->
widget();
 
 2413      newWidgetInfo.showLabel = 
false;
 
 2426      if ( fldIdx < fields.
count() && fldIdx >= 0 )
 
 2432        mFormEditorWidgets.insert( fldIdx, formWidget );
 
 2433        mFormWidgets.append( formWidget );
 
 2437        newWidgetInfo.widget = formWidget;
 
 2438        mWidgets.append( eww );
 
 2440        newWidgetInfo.widget->setObjectName( fields.
at( fldIdx ).
name() );
 
 2441        newWidgetInfo.hint = fields.
at( fldIdx ).
comment();
 
 2446      newWidgetInfo.labelText.replace( 
'&', QLatin1String( 
"&&" ) ); 
 
 2447      newWidgetInfo.toolTip = QStringLiteral( 
"<b>%1</b><p>%2</p>" ).arg( mLayer->
attributeDisplayName( fldIdx ), newWidgetInfo.hint );
 
 2448      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2469      mWidgets.append( rww );
 
 2470      mFormWidgets.append( formWidget );
 
 2472      newWidgetInfo.widget = formWidget;
 
 2473      newWidgetInfo.showLabel = relDef->
showLabel();
 
 2474      newWidgetInfo.labelText = relDef->
label();
 
 2475      if ( newWidgetInfo.labelText.isEmpty() )
 
 2477      newWidgetInfo.labelOnTop = 
true;
 
 2489      if ( columnCount <= 0 )
 
 2493      QWidget *myContainer = 
nullptr;
 
 2494      bool removeLayoutMargin = 
false;
 
 2495      switch ( container->
type() )
 
 2500          widgetName = QStringLiteral( 
"QGroupBox" );
 
 2503            groupBox->setTitle( container->
name() );
 
 2504            if ( newWidgetInfo.labelStyle.overrideColor )
 
 2506              if ( newWidgetInfo.labelStyle.color.isValid() )
 
 2508                groupBox->
setStyleSheet( QStringLiteral( 
"QGroupBox::title { color: %1; }" ).arg( newWidgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 2511            if ( newWidgetInfo.labelStyle.overrideFont )
 
 2513              groupBox->setFont( newWidgetInfo.labelStyle.font );
 
 2516          myContainer = groupBox;
 
 2517          newWidgetInfo.widget = myContainer;
 
 2524          QWidget *rowWidget = 
new QWidget();
 
 2525          widgetName = QStringLiteral( 
"Row" );
 
 2526          myContainer = rowWidget;
 
 2527          newWidgetInfo.widget = myContainer;
 
 2528          removeLayoutMargin = 
true;
 
 2529          columnCount = container->
children().size();
 
 2535          myContainer = 
new QWidget();
 
 2539          scrollArea->setWidget( myContainer );
 
 2540          scrollArea->setWidgetResizable( 
true );
 
 2541          scrollArea->setFrameShape( QFrame::NoFrame );
 
 2542          widgetName = QStringLiteral( 
"QScrollArea QWidget" );
 
 2544          newWidgetInfo.widget = scrollArea;
 
 2551        QString style { QStringLiteral( 
"background-color: %1;" ).arg( container->
backgroundColor().name() ) };
 
 2552        newWidgetInfo.widget->setStyleSheet( style );
 
 2555      QGridLayout *gbLayout = 
new QGridLayout();
 
 2556      if ( removeLayoutMargin )
 
 2557        gbLayout->setContentsMargins( 0, 0, 0, 0 );
 
 2558      myContainer->setLayout( gbLayout );
 
 2562      bool addSpacer = 
true;
 
 2564      const QList<QgsAttributeEditorElement *> children = container->
children();
 
 2568        WidgetInfo widgetInfo = createWidgetFromDef( childDef, myContainer, vl, context );
 
 2580        int widgetColumn = column;
 
 2582        if ( widgetInfo.labelText.isNull() || !widgetInfo.showLabel )
 
 2584          gbLayout->addWidget( widgetInfo.widget, row, column, 1, 2 );
 
 2585          widgetColumn = column + 1;
 
 2590          QLabel *mypLabel = 
new QLabel( widgetInfo.labelText );
 
 2592          if ( widgetInfo.labelStyle.overrideColor )
 
 2594            if ( widgetInfo.labelStyle.color.isValid() )
 
 2596              mypLabel->setStyleSheet( QStringLiteral( 
"QLabel { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
 
 2600          if ( widgetInfo.labelStyle.overrideFont )
 
 2602            mypLabel->setFont( widgetInfo.labelStyle.font );
 
 2610            const int fldIdx = fieldDef->
idx();
 
 2611            if ( fldIdx < fields.
count() && fldIdx >= 0 )
 
 2613              const QString fieldName { fields.
at( fldIdx ).
name() };
 
 2617                if ( property.isActive() )
 
 2619                  mLabelDataDefinedProperties[mypLabel] = property;
 
 2625                if ( property.isActive() )
 
 2627                  mEditableDataDefinedProperties[widgetInfo.widget] = property;
 
 2633          mypLabel->setToolTip( widgetInfo.toolTip );
 
 2634          if ( columnCount > 1 && !widgetInfo.labelOnTop )
 
 2636            mypLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
 
 2639          mypLabel->setBuddy( widgetInfo.widget );
 
 2641          if ( widgetInfo.labelOnTop )
 
 2643            widgetColumn = column + 1;
 
 2644            QVBoxLayout *
c = 
new QVBoxLayout();
 
 2645            mypLabel->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 2646            c->layout()->addWidget( mypLabel );
 
 2647            c->layout()->addWidget( widgetInfo.widget );
 
 2648            gbLayout->addLayout( 
c, row, column, 1, 2 );
 
 2653            widgetColumn = column + 1;
 
 2654            gbLayout->addWidget( mypLabel, row, column++ );
 
 2655            gbLayout->addWidget( widgetInfo.widget, row, column++ );
 
 2659        const int childHorizontalStretch = childDef->horizontalStretch();
 
 2660        const int existingColumnStretch = gbLayout->columnStretch( widgetColumn );
 
 2661        if ( childHorizontalStretch > 0 && childHorizontalStretch > existingColumnStretch )
 
 2663          gbLayout->setColumnStretch( widgetColumn, childHorizontalStretch );
 
 2666        if ( childDef->verticalStretch() > 0 && childDef->verticalStretch() > gbLayout->rowStretch( row ) )
 
 2668          gbLayout->setRowStretch( row, childDef->verticalStretch() );
 
 2671        if ( column >= columnCount * 2 )
 
 2677        if ( widgetInfo.widget
 
 2678             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Fixed
 
 2679             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Maximum
 
 2680             && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Preferred )
 
 2684        if ( qobject_cast<QgsAttributeFormRelationEditorWidget *>( widgetInfo.widget ) )
 
 2690        QWidget *spacer = 
new QWidget();
 
 2691        spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
 
 2692        gbLayout->addWidget( spacer, ++row, 0 );
 
 2693        gbLayout->setRowStretch( row, 1 );
 
 2696      newWidgetInfo.labelText = QString();
 
 2697      newWidgetInfo.labelOnTop = 
true;
 
 2698      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2711      mWidgets.append( qmlWrapper );
 
 2713      newWidgetInfo.widget = qmlWrapper->
widget();
 
 2714      newWidgetInfo.labelText = elementDef->
name();
 
 2715      newWidgetInfo.labelOnTop = 
true;
 
 2716      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2728      mWidgets.append( htmlWrapper );
 
 2730      newWidgetInfo.widget = htmlWrapper->
widget();
 
 2731      newWidgetInfo.labelText = elementDef->
name();
 
 2732      newWidgetInfo.labelOnTop = 
true;
 
 2733      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2746      mWidgets.append( textWrapper );
 
 2748      newWidgetInfo.widget = textWrapper->
widget();
 
 2749      newWidgetInfo.labelText = elementDef->
name();
 
 2750      newWidgetInfo.labelOnTop = 
false;
 
 2751      newWidgetInfo.showLabel = widgetDef->
showLabel();
 
 2762      mWidgets.append( spacerWrapper );
 
 2764      newWidgetInfo.widget = spacerWrapper->
widget();
 
 2765      newWidgetInfo.labelOnTop = 
false;
 
 2766      newWidgetInfo.showLabel = 
false;
 
 2771      QgsDebugError( QStringLiteral( 
"Unknown attribute editor widget type encountered..." ) );
 
 2775  return newWidgetInfo;
 
 2778void QgsAttributeForm::createWrappers()
 
 2780  QList<QWidget *> myWidgets = findChildren<QWidget *>();
 
 2781  const QList<QgsField> fields = mLayer->
fields().
toList();
 
 2783  const auto constMyWidgets = myWidgets;
 
 2784  for ( QWidget *myWidget : constMyWidgets )
 
 2787    QVariant vRel = myWidget->property( 
"qgisRelation" );
 
 2788    if ( vRel.isValid() )
 
 2798        mWidgets.append( rww );
 
 2803      const auto constFields = fields;
 
 2804      for ( 
const QgsField &field : constFields )
 
 2806        if ( field.name() == myWidget->objectName() )
 
 2811          mWidgets.append( eww );
 
 2818void QgsAttributeForm::afterWidgetInit()
 
 2820  bool isFirstEww = 
true;
 
 2822  const auto constMWidgets = mWidgets;
 
 2831        setFocusProxy( eww->
widget() );
 
 2841      if ( relationWidgetWrapper )
 
 2854  if ( e->type() == QEvent::KeyPress )
 
 2856    QKeyEvent *keyEvent = 
dynamic_cast<QKeyEvent *
>( e );
 
 2857    if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
 
 
 2868void QgsAttributeForm::scanForEqualAttributes( 
QgsFeatureIterator &fit, QSet<int> &mixedValueFields, QHash<int, QVariant> &fieldSharedValues )
 const 
 2870  mixedValueFields.clear();
 
 2871  fieldSharedValues.clear();
 
 2877    for ( 
int i = 0; i < mLayer->
fields().count(); ++i )
 
 2879      if ( mixedValueFields.contains( i ) )
 
 2884        fieldSharedValues[i] = f.
attribute( i );
 
 2888        if ( fieldSharedValues.value( i ) != f.
attribute( i ) )
 
 2890          fieldSharedValues.remove( i );
 
 2891          mixedValueFields.insert( i );
 
 2897    if ( mixedValueFields.count() == mLayer->
fields().
count() )
 
 2906void QgsAttributeForm::layerSelectionChanged()
 
 2919      resetMultiEdit( 
true );
 
 2926  mIsSettingMultiEditFeatures = 
true;
 
 2927  mMultiEditFeatureIds = fids;
 
 2929  if ( fids.isEmpty() )
 
 2932    QMultiMap<int, QgsAttributeFormEditorWidget *>::const_iterator wIt = mFormEditorWidgets.constBegin();
 
 2933    for ( ; wIt != mFormEditorWidgets.constEnd(); ++wIt )
 
 2935      wIt.value()->initialize( QVariant() );
 
 2937    mIsSettingMultiEditFeatures = 
false;
 
 2944  QSet<int> mixedValueFields;
 
 2945  QHash<int, QVariant> fieldSharedValues;
 
 2946  scanForEqualAttributes( fit, mixedValueFields, fieldSharedValues );
 
 2955  if ( mCurrentFormFeature.
id() != firstFeature.
id() )
 
 2960  const auto constMixedValueFields = mixedValueFields;
 
 2961  for ( 
int fieldIndex : std::as_const( mixedValueFields ) )
 
 2963    const QList<QgsAttributeFormEditorWidget *> formEditorWidgets = mFormEditorWidgets.values( fieldIndex );
 
 2964    if ( formEditorWidgets.isEmpty() )
 
 2967    const QStringList additionalFields = formEditorWidgets.first()->editorWidget()->additionalFields();
 
 2968    QVariantList additionalFieldValues;
 
 2969    for ( 
const QString &additionalField : additionalFields )
 
 2970      additionalFieldValues << firstFeature.
attribute( additionalField );
 
 2973      w->initialize( firstFeature.
attribute( fieldIndex ), 
true, additionalFieldValues );
 
 2975  QHash<int, QVariant>::const_iterator sharedValueIt = fieldSharedValues.constBegin();
 
 2976  for ( ; sharedValueIt != fieldSharedValues.constEnd(); ++sharedValueIt )
 
 2978    const QList<QgsAttributeFormEditorWidget *> formEditorWidgets = mFormEditorWidgets.values( sharedValueIt.key() );
 
 2979    if ( formEditorWidgets.isEmpty() )
 
 2983    const QStringList additionalFields = formEditorWidgets.first()->editorWidget()->additionalFields();
 
 2984    for ( 
const QString &additionalField : additionalFields )
 
 2987      if ( constMixedValueFields.contains( index ) )
 
 2994    QVariantList additionalFieldValues;
 
 2997      for ( 
const QString &additionalField : additionalFields )
 
 2998        additionalFieldValues << firstFeature.
attribute( additionalField );
 
 3000        w->initialize( firstFeature.
attribute( sharedValueIt.key() ), 
true, additionalFieldValues );
 
 3004      for ( 
const QString &additionalField : additionalFields )
 
 3007        Q_ASSERT( fieldSharedValues.contains( index ) );
 
 3008        additionalFieldValues << fieldSharedValues.value( index );
 
 3011        w->initialize( sharedValueIt.value(), 
false, additionalFieldValues );
 
 3015  setMultiEditFeatureIdsRelations( fids );
 
 3017  mIsSettingMultiEditFeatures = 
false;
 
 
 3022  if ( mOwnsMessageBar )
 
 3024  mOwnsMessageBar = 
false;
 
 3025  mMessageBar = messageBar;
 
 
 3035  QStringList filters;
 
 3038    QString filter = widget->currentFilterExpression();
 
 3039    if ( !filter.isNull() )
 
 3040      filters << 
'(' + filter + 
')';
 
 3043  return filters.join( QLatin1String( 
" AND " ) );
 
 
 3048  mExtraContextScope.reset( extraScope );
 
 
 3053  const bool newVisibility = expression.evaluate( expressionContext ).toBool();
 
 3055  if ( expression.isValid() && !expression.hasEvalError() && newVisibility != isVisible )
 
 3063      widget->setVisible( newVisibility );
 
 3066    isVisible = newVisibility;
 
 3069  const bool newCollapsedState = collapsedExpression.evaluate( expressionContext ).toBool();
 
 3071  if ( collapsedExpression.isValid() && !collapsedExpression.hasEvalError() && newCollapsedState != isCollapsed )
 
 3075      collapsibleGroupBox->
setCollapsed( newCollapsedState );
 
 3076      isCollapsed = newCollapsedState;
 
 3090  if ( infos.count() == 0 || !currentFormValuesFeature( formFeature ) )
 
 3093  const QString hint = tr( 
"No feature joined" );
 
 3094  const auto constInfos = infos;
 
 3097    if ( !info->isDynamicFormEnabled() )
 
 3102    mJoinedFeatures[info] = joinFeature;
 
 3104    if ( info->hasSubset() )
 
 3108      const auto constSubsetNames = subsetNames;
 
 3109      for ( 
const QString &field : constSubsetNames )
 
 3111        QString prefixedName = info->prefixedFieldName( field );
 
 3113        QString hintText = hint;
 
 3127      for ( 
const QgsField &field : joinFields )
 
 3129        QString prefixedName = info->prefixedFieldName( field );
 
 3131        QString hintText = hint;
 
 3145bool QgsAttributeForm::fieldIsEditable( 
int fieldIndex )
 const 
 3150void QgsAttributeForm::updateFieldDependencies()
 
 3152  mDefaultValueDependencies.clear();
 
 3153  mVirtualFieldsDependencies.clear();
 
 3154  mRelatedLayerFieldsDependencies.clear();
 
 3155  mParentDependencies.clear();
 
 3164    updateFieldDependenciesParent( eww );
 
 3165    updateFieldDependenciesDefaultValue( eww );
 
 3166    updateFieldDependenciesVirtualFields( eww );
 
 3167    updateRelatedLayerFieldsDependencies( eww );
 
 3175  if ( exp.needsGeometry() )
 
 3176    mNeedsGeometry = 
true;
 
 3183    for ( 
const int id : allAttributeIds )
 
 3185      mDefaultValueDependencies.insertMulti( 
id, eww );
 
 3191    const QSet<QString> referencedColumns = exp.referencedColumns();
 
 3192    for ( 
const QString &referencedColumn : referencedColumns )
 
 3194      mDefaultValueDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
 
 3202  if ( expressionField.isEmpty() )
 
 3207  if ( exp.needsGeometry() )
 
 3208    mNeedsGeometry = 
true;
 
 3215    for ( 
const int id : allAttributeIds )
 
 3217      mVirtualFieldsDependencies.insertMulti( 
id, eww );
 
 3223    const QSet<QString> referencedColumns = exp.referencedColumns();
 
 3224    for ( 
const QString &referencedColumn : referencedColumns )
 
 3226      mVirtualFieldsDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
 
 3236    if ( expressionField.contains( QStringLiteral( 
"relation_aggregate" ) )
 
 3237         || expressionField.contains( QStringLiteral( 
"get_features" ) ) )
 
 3238      mRelatedLayerFieldsDependencies.insert( eww );
 
 3242    mRelatedLayerFieldsDependencies.clear();
 
 3247      if ( !editorWidgetWrapper )
 
 3250      updateRelatedLayerFieldsDependencies( editorWidgetWrapper );
 
 3260    const QSet<QString> referencedVariablesAndFunctions = expression.referencedVariables() + expression.referencedFunctions();
 
 3261    for ( 
const QString &referenced : referencedVariablesAndFunctions )
 
 3263      if ( referenced.startsWith( QLatin1String( 
"current_parent" ) ) )
 
 3265        mParentDependencies.insert( eww );
 
 3272void QgsAttributeForm::setMultiEditFeatureIdsRelations( 
const QgsFeatureIds &fids )
 
 3277    if ( !relationEditorWidget )
 
 3290  mIconMap[eww->
widget()]->hide();
 
 3304        const QString file = QStringLiteral( 
"/mIconJoinNotEditable.svg" );
 
 3305        const QString tooltip = tr( 
"Join settings do not allow editing" );
 
 3306        reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 3310        const QString file = QStringLiteral( 
"mIconJoinHasNotUpsertOnEdit.svg" );
 
 3311        const QString tooltip = tr( 
"Join settings do not allow upsert on edit" );
 
 3312        reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 3316        const QString file = QStringLiteral( 
"/mIconJoinedLayerNotEditable.svg" );
 
 3317        const QString tooltip = tr( 
"Joined layer is not toggled editable" );
 
 3318        reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 3324void QgsAttributeForm::reloadIcon( 
const QString &file, 
const QString &tooltip, QSvgWidget *sw )
 
 3327  sw->setToolTip( tooltip );
 
@ Row
A row of editors (horizontal layout)
 
@ File
Load the Python code from an external file.
 
@ Environment
Use the Python code available in the Python environment.
 
@ NoSource
Do not use Python code at all.
 
@ Dialog
Use the Python code provided in the dialog.
 
@ DragAndDrop
"Drag and drop" layout. Needs to be configured.
 
@ UiFile
Load a .ui file for the layout. Needs to be configured.
 
@ Warning
Warning message.
 
@ Info
Information message.
 
@ Success
Used for reporting a successful operation.
 
@ Join
Field originates from a joined layer.
 
@ Action
A layer action element.
 
@ QmlElement
A QML element.
 
@ HtmlElement
A HTML element.
 
@ TextElement
A text element.
 
@ SpacerElement
A spacer element.
 
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.
 
A container for attribute editors, used to group them visually in the attribute form if it is set to ...
 
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.
 
Contains context information for attribute editor widgets.
 
FormMode formMode() const
Returns the form mode.
 
QString attributeFormModeString() const
Returns given attributeFormMode as string.
 
QgsFeature parentFormFeature() const
Returns the feature of the currently edited parent form in its actual state.
 
@ Embed
A form was embedded as a widget on another form.
 
void setParentFormFeature(const QgsFeature &feature)
Sets the feature of the currently edited parent 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.
 
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.
 
Single scope for storing variables and functions for use within a QgsExpressionContext.
 
static QgsExpressionContextScope * parentFormScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current parent attribute form/tab...
 
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.
 
Handles 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)
Fetch next feature and stores in f, returns true on success.
 
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...
 
Q_INVOKABLE 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.
 
Q_INVOKABLE 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.
 
Q_INVOKABLE int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
 
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
 
Qgis::FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
 
Q_INVOKABLE 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).
 
Q_INVOKABLE 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 pythonEmbeddedInProjectAllowed(void(*lambda)()=nullptr, QgsMessageBar *messageBar=nullptr, Qgis::PythonEmbeddedType embeddedType=Qgis::PythonEmbeddedType::Macro)
Returns true if python embedded in a project is currently allowed to be loaded.
 
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 final
Returns true if the collection contains a property with the specified key.
 
QgsProperty property(int key) const final
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.
 
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.
 
Represents a relationship between two vector layers.
 
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, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
 
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
 
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 dataset.
 
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.
 
Q_INVOKABLE bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false, QgsVectorLayerToolsContext *context=nullptr)
Changes an attribute value for a feature (but does not immediately commit the changes).
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
 
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 isEditable() const FINAL
Returns true if the provider is in editing mode.
 
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
 
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.
 
Q_INVOKABLE bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap(), bool skipDefaultValues=false, QgsVectorLayerToolsContext *context=nullptr)
Changes attributes' values for a feature (but does not immediately commit the changes).
 
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)