21 #include "qgsattributeeditorcontainer.h" 
   22 #include "qgsattributeeditorfield.h" 
   23 #include "qgsattributeeditorrelation.h" 
   24 #include "qgsattributeeditorqmlelement.h" 
   25 #include "qgsattributeeditorhtmlelement.h" 
   54 #include <QTextStream> 
   57 #include <QFormLayout> 
   58 #include <QGridLayout> 
   62 #include <QPushButton> 
   64 #include <QMessageBox> 
   65 #include <QToolButton> 
   68 int QgsAttributeForm::sFormCounter = 0;
 
   73   , mOwnsMessageBar( true )
 
   75   , mFormNr( sFormCounter++ )
 
   77   , mPreventFeatureRefresh( false )
 
   78   , mIsSettingMultiEditFeatures( false )
 
   79   , mUnsavedMultiEditChanges( false )
 
   80   , mEditCommandMessage( tr( 
"Attributes changed" ) )
 
   93   updateContainersVisibility();
 
  101   qDeleteAll( mInterfaces );
 
  128   mInterfaces.append( iface );
 
  144     if ( mUnsavedMultiEditChanges )
 
  147       int res = QMessageBox::question( 
this, tr( 
"Multiedit Attributes" ),
 
  148                                        tr( 
"Apply changes to edited features?" ), QMessageBox::Yes | QMessageBox::No );
 
  149       if ( res == QMessageBox::Yes )
 
  154     clearMultiEditMessages();
 
  156   mUnsavedMultiEditChanges = 
false;
 
  208     w->setContext( newContext );
 
  214     w->setVisible( relationWidgetsVisible );
 
  221       mSearchButtonBox->setVisible( 
false );
 
  225       synchronizeEnabledState();
 
  226       mSearchButtonBox->setVisible( 
false );
 
  230       synchronizeEnabledState();
 
  231       mSearchButtonBox->setVisible( 
false );
 
  235       resetMultiEdit( 
false );
 
  236       synchronizeEnabledState();
 
  237       mSearchButtonBox->setVisible( 
false );
 
  241       mSearchButtonBox->setVisible( 
true );
 
  246       mSearchButtonBox->setVisible( 
false );
 
  252       mSearchButtonBox->setVisible( 
false );
 
  261   const auto constMWidgets = mWidgets;
 
  276         QVariant mainValue = eww->
value();
 
  278         additionalFieldValues[index] = value;
 
  279         eww->
setValues( mainValue, additionalFieldValues );
 
  288   mIsSettingFeature = 
true;
 
  301       synchronizeEnabledState();
 
  305       mIsSettingFeature = 
false;
 
  306       const auto constMInterfaces = mInterfaces;
 
  309         iface->featureChanged();
 
  325   mIsSettingFeature = 
false;
 
  328 bool QgsAttributeForm::saveEdits( QString *error )
 
  331   bool changedLayer = 
false;
 
  336     bool doUpdate = 
false;
 
  356             *error = tr( 
"JSON value for %1 is invalid and has not been saved" ).arg( eww->
field().
name() );
 
  359         QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
 
  360         QVariantList srcVars = QVariantList() << eww->
value();
 
  361         QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
  365         for ( 
const QString &fieldName : additionalFields )
 
  369           dstVars << dst.at( idx );
 
  373         Q_ASSERT( dstVars.count() == srcVars.count() );
 
  375         for ( 
int i = 0; i < dstVars.count(); i++ )
 
  378           if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() )
 
  380             dst[fieldIndexes[i]] = srcVars[i];
 
  390     const auto constMInterfaces = mInterfaces;
 
  393       if ( !iface->acceptChanges( updatedFeature ) )
 
  403         mFeature = updatedFeature;
 
  409         bool res = mLayer->
addFeature( updatedFeature );
 
  428         for ( 
int i = 0; i < dst.count(); ++i )
 
  431                || !dst.at( i ).isValid()                 
 
  432                || !fieldIsEditable( i ) )                
 
  438           QgsDebugMsgLevel( QStringLiteral( 
"dst:'%1' (type:%2, isNull:%3, isValid:%4)" )
 
  439                             .arg( dst.at( i ).toString(), dst.at( i ).typeName() ).arg( dst.at( i ).isNull() ).arg( dst.at( i ).isValid() ), 2 );
 
  440           QgsDebugMsgLevel( QStringLiteral( 
"src:'%1' (type:%2, isNull:%3, isValid:%4)" )
 
  441                             .arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( src.at( i ).isNull() ).arg( src.at( i ).isValid() ), 2 );
 
  443           newValues[i] = dst.at( i );
 
  444           oldValues[i] = src.at( i );
 
  451         if ( success && n > 0 )
 
  478 bool QgsAttributeForm::updateDefaultValues( 
const int originIdx )
 
  482   updateDefaultValueDependencies();
 
  484   if ( !mDefaultValueDependencies.contains( originIdx ) )
 
  497         QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
 
  498         QVariantList srcVars = QVariantList() << eww->
value();
 
  499         QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
  503         for ( 
const QString &fieldName : additionalFields )
 
  507           dstVars << dst.at( idx );
 
  511         Q_ASSERT( dstVars.count() == srcVars.count() );
 
  513         for ( 
int i = 0; i < dstVars.count(); i++ )
 
  516           if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() && fieldIsEditable( fieldIndexes[i] ) )
 
  518             dst[fieldIndexes[i]] = srcVars[i];
 
  526     QList<QgsWidgetWrapper *> relevantWidgets = mDefaultValueDependencies.values( originIdx );
 
  539         if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
 
  551 void QgsAttributeForm::resetMultiEdit( 
bool promptToSave )
 
  556   mUnsavedMultiEditChanges = 
false;
 
  560 void QgsAttributeForm::multiEditMessageClicked( 
const QString &link )
 
  562   clearMultiEditMessages();
 
  563   resetMultiEdit( link == QLatin1String( 
"#apply" ) );
 
  566 void QgsAttributeForm::filterTriggered()
 
  568   QString filter = createFilterExpression();
 
  574 void QgsAttributeForm::searchZoomTo()
 
  576   QString filter = createFilterExpression();
 
  577   if ( filter.isEmpty() )
 
  583 void QgsAttributeForm::searchFlash()
 
  585   QString filter = createFilterExpression();
 
  586   if ( filter.isEmpty() )
 
  592 void QgsAttributeForm::filterAndTriggered()
 
  594   QString filter = createFilterExpression();
 
  595   if ( filter.isEmpty() )
 
  603 void QgsAttributeForm::filterOrTriggered()
 
  605   QString filter = createFilterExpression();
 
  606   if ( filter.isEmpty() )
 
  614 void QgsAttributeForm::pushSelectedFeaturesMessage()
 
  620                               tr( 
"%n matching feature(s) selected", 
"matching features", count ),
 
  626                               tr( 
"No matching features found" ),
 
  640   QString filter = createFilterExpression();
 
  641   if ( filter.isEmpty() )
 
  645   pushSelectedFeaturesMessage();
 
  650 void QgsAttributeForm::searchSetSelection()
 
  655 void QgsAttributeForm::searchAddToSelection()
 
  660 void QgsAttributeForm::searchRemoveFromSelection()
 
  665 void QgsAttributeForm::searchIntersectSelection()
 
  670 bool QgsAttributeForm::saveMultiEdits()
 
  674   QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
 
  675   for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
 
  682          || !fieldIsEditable( wIt.key() ) ) 
 
  690     newAttributeValues.insert( wIt.key(), w->
currentValue() );
 
  693   if ( newAttributeValues.isEmpty() )
 
  701   int res = QMessageBox::information( 
this, tr( 
"Multiedit Attributes" ),
 
  702                                       tr( 
"Edits will be applied to all selected features." ), QMessageBox::Ok | QMessageBox::Cancel );
 
  703   if ( res != QMessageBox::Ok )
 
  714   const auto constMultiEditFeatureIds = mMultiEditFeatureIds;
 
  717     QgsAttributeMap::const_iterator aIt = newAttributeValues.constBegin();
 
  718     for ( ; aIt != newAttributeValues.constEnd(); ++aIt )
 
  724   clearMultiEditMessages();
 
  737   if ( !mButtonBox->isVisible() )
 
  738     mMessageBar->
pushItem( mMultiEditMessageBarItem );
 
  757     wrapper->notifyAboutToSave();
 
  797       success = saveEdits( error );
 
  801       success = saveMultiEdits();
 
  806   mUnsavedMultiEditChanges = 
false;
 
  815   mValuesInitialized = 
false;
 
  816   const auto constMWidgets = mWidgets;
 
  819     ww->setFeature( mFeature );
 
  821   mValuesInitialized = 
true;
 
  827   const auto widgets { findChildren<  QgsAttributeFormEditorWidget * >() };
 
  834 void QgsAttributeForm::clearMultiEditMessages()
 
  836   if ( mMultiEditUnsavedMessageBarItem )
 
  838     if ( !mButtonBox->isVisible() )
 
  839       mMessageBar->
popWidget( mMultiEditUnsavedMessageBarItem );
 
  840     mMultiEditUnsavedMessageBarItem = 
nullptr;
 
  842   if ( mMultiEditMessageBarItem )
 
  844     if ( !mButtonBox->isVisible() )
 
  845       mMessageBar->
popWidget( mMultiEditMessageBarItem );
 
  846     mMultiEditMessageBarItem = 
nullptr;
 
  850 QString QgsAttributeForm::createFilterExpression()
 const 
  856     if ( !filter.isEmpty() )
 
  860   if ( filters.isEmpty() )
 
  863   QString filter = filters.join( QLatin1String( 
") AND (" ) ).prepend( 
'(' ).append( 
')' );
 
  872   if ( mExtraContextScope )
 
  879 void QgsAttributeForm::onAttributeChanged( 
const QVariant &value, 
const QVariantList &additionalFieldValues )
 
  884   bool signalEmitted = 
false;
 
  886   if ( mValuesInitialized )
 
  905       for ( 
int i = 0; i < additionalFields.count(); i++ )
 
  907         const QString fieldName = additionalFields.at( i );
 
  908         const QVariant value = additionalFieldValues.at( i );
 
  912       signalEmitted = 
true;
 
  914       updateJoinedFields( *eww );
 
  920       if ( !mIsSettingMultiEditFeatures )
 
  922         mUnsavedMultiEditChanges = 
true;
 
  924         QLabel *msgLabel = 
new QLabel( tr( 
"Unsaved multiedit changes: <a href=\"#apply\">apply changes</a> or <a href=\"#reset\">reset changes</a>." ), mMessageBar );
 
  925         msgLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
 
  926         msgLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
 
  927         connect( msgLabel, &QLabel::linkActivated, 
this, &QgsAttributeForm::multiEditMessageClicked );
 
  928         clearMultiEditMessages();
 
  931         if ( !mButtonBox->isVisible() )
 
  932           mMessageBar->
pushItem( mMultiEditUnsavedMessageBarItem );
 
  944   updateConstraints( eww );
 
  947   mAlreadyUpdatedFields.append( eww->
fieldIdx() );
 
  948   updateDefaultValues( eww->
fieldIdx() );
 
  949   mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
 
  954   if ( !signalEmitted )
 
  963 void QgsAttributeForm::updateAllConstraints()
 
  965   const auto constMWidgets = mWidgets;
 
  970       updateConstraints( eww );
 
  978   if ( currentFormValuesFeature( ft ) )
 
  990     updateConstraint( ft, eww );
 
  993     const QList<QgsEditorWidgetWrapper *> deps = constraintDependencies( eww );
 
  996       updateConstraint( ft, depsEww );
 
  999     synchronizeEnabledState();
 
 1004     const QVector<ContainerInformation *> infos = mContainerInformationDependency.value( eww->
field().
name() );
 
 1005     for ( ContainerInformation *info : infos )
 
 1007       info->apply( &context );
 
 1012 void QgsAttributeForm::updateContainersVisibility()
 
 1016   const QVector<ContainerInformation *> infos = mContainerVisibilityInformation;
 
 1018   for ( ContainerInformation *info : infos )
 
 1020     info->apply( &context );
 
 1024   updateAllConstraints();
 
 1030   if ( mContext.
attributeFormMode() != QgsAttributeEditorContext::Mode::MultiEditMode )
 
 1042         if ( mJoinedFeatures.contains( info ) )
 
 1060 void QgsAttributeForm::updateLabels()
 
 1062   if ( ! mLabelDataDefinedProperties.isEmpty() )
 
 1065     if ( currentFormValuesFeature( currentFeature ) )
 
 1069       for ( 
auto it = mLabelDataDefinedProperties.constBegin() ; it != mLabelDataDefinedProperties.constEnd(); ++it )
 
 1071         QLabel *label { it.key() };
 
 1073         const QString value { it->valueAsString( context, QString(), &ok ) };
 
 1074         if ( ok && ! value.isEmpty() )
 
 1076           label->setText( value );
 
 1083 bool QgsAttributeForm::currentFormValuesFeature( 
QgsFeature &feature )
 
 1096     if ( dst.count() > eww->
fieldIdx() )
 
 1098       QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
 
 1099       QVariantList srcVars = QVariantList() << eww->
value();
 
 1100       QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
 
 1104       for ( 
const QString &fieldName : additionalFields )
 
 1107         fieldIndexes << idx;
 
 1108         dstVars << dst.at( idx );
 
 1112       Q_ASSERT( dstVars.count() == srcVars.count() );
 
 1114       for ( 
int i = 0; i < dstVars.count(); i++ )
 
 1118         if ( ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) || dstVars[i].isNull() != srcVars[i].isNull() ) && srcVars[i].isValid() )
 
 1120           dst[fieldIndexes[i]] = srcVars[i];
 
 1137 void QgsAttributeForm::registerContainerInformation( QgsAttributeForm::ContainerInformation *info )
 
 1139   mContainerVisibilityInformation.append( info );
 
 1141   const QSet<QString> referencedColumns = info->expression.referencedColumns();
 
 1143   for ( 
const QString &col : referencedColumns )
 
 1145     mContainerInformationDependency[ col ].append( info );
 
 1149 bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions )
 
 1173 void QgsAttributeForm::onAttributeAdded( 
int idx )
 
 1175   mPreventFeatureRefresh = 
false;
 
 1179     attrs.insert( idx, QVariant( 
layer()->fields().at( idx ).type() ) );
 
 1187 void QgsAttributeForm::onAttributeDeleted( 
int idx )
 
 1189   mPreventFeatureRefresh = 
false;
 
 1193     attrs.remove( idx );
 
 1201 void QgsAttributeForm::onUpdatedFields()
 
 1203   mPreventFeatureRefresh = 
false;
 
 1220         attrs[i] = QVariant( 
layer()->fields().at( i ).type() );
 
 1230 void QgsAttributeForm::onConstraintStatusChanged( 
const QString &constraint,
 
 1238   if ( formEditorWidget )
 
 1244   QList<QgsEditorWidgetWrapper *> wDeps;
 
 1256       if ( name != ewwName )
 
 1263         for ( 
const QString &colName : referencedColumns )
 
 1265           if ( name == colName )
 
 1267             wDeps.append( eww );
 
 1280   return setupRelationWidgetWrapper( QString(), rel, context );
 
 1286   const QVariantMap config = mLayer->
editFormConfig().widgetConfig( rel.
id() );
 
 1293 void QgsAttributeForm::preventFeatureRefresh()
 
 1295   mPreventFeatureRefresh = 
true;
 
 1324 void QgsAttributeForm::synchronizeEnabledState()
 
 1326   bool isEditable = ( mFeature.
isValid()
 
 1342       bool enabled = isEditable && fieldIsEditable( eww->
fieldIdx() );
 
 1343       ww->setEnabled( enabled );
 
 1351     QStringList invalidFields, descriptions;
 
 1352     bool validConstraint = currentFormValidConstraints( invalidFields, descriptions );
 
 1354     isEditable = isEditable & validConstraint;
 
 1358   QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
 
 1360     okButton->setEnabled( isEditable );
 
 1363 void QgsAttributeForm::init()
 
 1365   QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
 
 1368   QWidget *formWidget = 
nullptr;
 
 1370   bool buttonBoxVisible = 
true;
 
 1374     buttonBoxVisible = mButtonBox->isVisible();
 
 1376     mButtonBox = 
nullptr;
 
 1379   if ( mSearchButtonBox )
 
 1381     delete mSearchButtonBox;
 
 1382     mSearchButtonBox = 
nullptr;
 
 1385   qDeleteAll( mWidgets );
 
 1388   while ( QWidget *w = this->findChild<QWidget *>() )
 
 1394   QVBoxLayout *vl = 
new QVBoxLayout();
 
 1395   vl->setContentsMargins( 0, 0, 0, 0 );
 
 1397   mMessageBar->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
 
 1398   vl->addWidget( mMessageBar );
 
 1403   QGridLayout *layout = 
new QGridLayout();
 
 1404   QWidget *container = 
new QWidget();
 
 1405   container->setLayout( layout );
 
 1406   vl->addWidget( container );
 
 1408   mFormEditorWidgets.clear();
 
 1409   mFormWidgets.clear();
 
 1412   setContentsMargins( 0, 0, 0, 0 );
 
 1421     if ( file && file->open( QFile::ReadOnly ) )
 
 1425       QFileInfo fi( file->fileName() );
 
 1426       loader.setWorkingDirectory( fi.dir() );
 
 1427       formWidget = loader.load( file, 
this );
 
 1430         formWidget->setWindowFlags( Qt::Widget );
 
 1431         layout->addWidget( formWidget );
 
 1434         mButtonBox = findChild<QDialogButtonBox *>();
 
 1437         formWidget->installEventFilter( 
this );
 
 1445   if ( !formWidget && mLayer->
editFormConfig().layout() == QgsEditFormConfig::TabLayout )
 
 1449     int columnCount = 1;
 
 1451     const QList<QgsAttributeEditorElement *> tabs = mLayer->
editFormConfig().tabs();
 
 1453     for ( QgsAttributeEditorElement *widgDef : tabs )
 
 1455       if ( widgDef->type() == QgsAttributeEditorElement::AeTypeContainer )
 
 1457         QgsAttributeEditorContainer *containerDef = 
dynamic_cast<QgsAttributeEditorContainer *
>( widgDef );
 
 1458         if ( !containerDef )
 
 1461         if ( containerDef->isGroupBox() )
 
 1463           tabWidget = 
nullptr;
 
 1464           WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
 
 1465           layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
 
 1466           if ( containerDef->visibilityExpression().enabled() )
 
 1468             registerContainerInformation( 
new ContainerInformation( widgetInfo.widget, containerDef->visibilityExpression().data() ) );
 
 1477             layout->addWidget( tabWidget, row, column, 1, 2 );
 
 1481           QWidget *tabPage = 
new QWidget( tabWidget );
 
 1483           tabWidget->addTab( tabPage, widgDef->name() );
 
 1485           if ( containerDef->visibilityExpression().enabled() )
 
 1487             registerContainerInformation( 
new ContainerInformation( tabWidget, tabPage, containerDef->visibilityExpression().data() ) );
 
 1489           QGridLayout *tabPageLayout = 
new QGridLayout();
 
 1490           tabPage->setLayout( tabPageLayout );
 
 1492           WidgetInfo widgetInfo = createWidgetFromDef( widgDef, tabPage, mLayer, mContext );
 
 1493           tabPageLayout->addWidget( widgetInfo.widget );
 
 1498         tabWidget = 
nullptr;
 
 1499         WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
 
 1500         QLabel *label = 
new QLabel( widgetInfo.labelText );
 
 1501         label->setToolTip( widgetInfo.toolTip );
 
 1502         if ( columnCount > 1 && !widgetInfo.labelOnTop )
 
 1504           label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
 
 1507         label->setBuddy( widgetInfo.widget );
 
 1509         if ( !widgetInfo.showLabel )
 
 1511           QVBoxLayout *
c = 
new QVBoxLayout();
 
 1512           label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 1513           c->addWidget( widgetInfo.widget );
 
 1514           layout->addLayout( 
c, row, column, 1, 2 );
 
 1517         else if ( widgetInfo.labelOnTop )
 
 1519           QVBoxLayout *
c = 
new QVBoxLayout();
 
 1520           label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 1521           c->addWidget( label );
 
 1522           c->addWidget( widgetInfo.widget );
 
 1523           layout->addLayout( 
c, row, column, 1, 2 );
 
 1528           layout->addWidget( label, row, column++ );
 
 1529           layout->addWidget( widgetInfo.widget, row, column++ );
 
 1533         if ( widgDef->type() == QgsAttributeEditorElement::AttributeEditorType::AeTypeField )
 
 1535           const QgsAttributeEditorField *fieldElement { 
static_cast<QgsAttributeEditorField *
>( widgDef ) };
 
 1536           const int fieldIdx = fieldElement->idx();
 
 1537           if ( fieldIdx >= 0 && fieldIdx < mLayer->fields().count() )
 
 1539             const QString fieldName { mLayer->
fields().
at( fieldIdx ).
name() };
 
 1540             if ( mLayer->
editFormConfig().dataDefinedFieldProperties( fieldName ).hasProperty( QgsEditFormConfig::DataDefinedProperty::Alias ) )
 
 1542               const QgsProperty property { mLayer->
editFormConfig().dataDefinedFieldProperties( fieldName ).property( QgsEditFormConfig::DataDefinedProperty::Alias ) };
 
 1543               if ( property.isActive() && ! 
property.expressionString().isEmpty() )
 
 1545                 mLabelDataDefinedProperties[ label ] = property;
 
 1552       if ( column >= columnCount * 2 )
 
 1558     formWidget = container;
 
 1567     formWidget = 
new QWidget( 
this );
 
 1568     QGridLayout *gridLayout = 
new QGridLayout( formWidget );
 
 1569     formWidget->setLayout( gridLayout );
 
 1575       scrollArea->setWidget( formWidget );
 
 1576       scrollArea->setWidgetResizable( 
true );
 
 1577       scrollArea->setFrameShape( QFrame::NoFrame );
 
 1578       scrollArea->setFrameShadow( QFrame::Plain );
 
 1579       scrollArea->setFocusProxy( 
this );
 
 1580       layout->addWidget( scrollArea );
 
 1584       layout->addWidget( formWidget );
 
 1599       QString labelText = fieldName;
 
 1600       labelText.replace( 
'&', QLatin1String( 
"&&" ) ); 
 
 1604       if ( widgetSetup.
type() == QLatin1String( 
"Hidden" ) )
 
 1610       QLabel *label = 
new QLabel( labelText );
 
 1612       QSvgWidget *i = 
new QSvgWidget();
 
 1613       i->setFixedSize( 18, 18 );
 
 1615       if ( mLayer->
editFormConfig().dataDefinedFieldProperties( fieldName ).hasProperty( QgsEditFormConfig::DataDefinedProperty::Alias ) )
 
 1617         const QgsProperty property { mLayer->
editFormConfig().dataDefinedFieldProperties( fieldName ).property( QgsEditFormConfig::DataDefinedProperty::Alias ) };
 
 1618         if ( property.isActive() && ! property.expressionString().isEmpty() )
 
 1620           mLabelDataDefinedProperties[ label ] = property;
 
 1626       QWidget *w = 
nullptr;
 
 1631         mFormEditorWidgets.insert( idx, formWidget );
 
 1632         mFormWidgets.append( formWidget );
 
 1635         label->setBuddy( eww->
widget() );
 
 1639         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() ) ) );
 
 1648         addWidgetWrapper( eww );
 
 1649         mIconMap[eww->
widget()] = i;
 
 1654         gridLayout->addWidget( label, row++, 0, 1, 2 );
 
 1655         gridLayout->addWidget( w, row++, 0, 1, 2 );
 
 1656         gridLayout->addWidget( i, row++, 0, 1, 2 );
 
 1660         gridLayout->addWidget( label, row, 0 );
 
 1661         gridLayout->addWidget( w, row, 1 );
 
 1662         gridLayout->addWidget( i, row++, 2 );
 
 1674       gridLayout->addWidget( formWidget, row++, 0, 1, 2 );
 
 1676       mWidgets.append( rww );
 
 1677       mFormWidgets.append( formWidget );
 
 1682       QSpacerItem *spacerItem = 
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
 
 1683       gridLayout->addItem( spacerItem, row, 0 );
 
 1684       gridLayout->setRowStretch( row, 1 );
 
 1689   updateDefaultValueDependencies();
 
 1693     mButtonBox = 
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
 
 1694     mButtonBox->setObjectName( QStringLiteral( 
"buttonBox" ) );
 
 1695     layout->addWidget( mButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
 
 1697   mButtonBox->setVisible( buttonBoxVisible );
 
 1699   if ( !mSearchButtonBox )
 
 1701     mSearchButtonBox = 
new QWidget();
 
 1702     QHBoxLayout *boxLayout = 
new QHBoxLayout();
 
 1703     boxLayout->setContentsMargins( 0, 0, 0, 0 );
 
 1704     mSearchButtonBox->setLayout( boxLayout );
 
 1705     mSearchButtonBox->setObjectName( QStringLiteral( 
"searchButtonBox" ) );
 
 1707     QPushButton *clearButton = 
new QPushButton( tr( 
"&Reset Form" ), mSearchButtonBox );
 
 1709     boxLayout->addWidget( clearButton );
 
 1710     boxLayout->addStretch( 1 );
 
 1712     QPushButton *flashButton = 
new QPushButton();
 
 1713     flashButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 1714     flashButton->setText( tr( 
"&Flash Features" ) );
 
 1715     connect( flashButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchFlash );
 
 1716     boxLayout->addWidget( flashButton );
 
 1718     QPushButton *zoomButton = 
new QPushButton();
 
 1719     zoomButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 1720     zoomButton->setText( tr( 
"&Zoom to Features" ) );
 
 1721     connect( zoomButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchZoomTo );
 
 1722     boxLayout->addWidget( zoomButton );
 
 1724     QToolButton *selectButton = 
new QToolButton();
 
 1725     selectButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 1726     selectButton->setText( tr( 
"&Select Features" ) );
 
 1728     selectButton->setPopupMode( QToolButton::MenuButtonPopup );
 
 1729     selectButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
 
 1730     connect( selectButton, &QToolButton::clicked, 
this, &QgsAttributeForm::searchSetSelection );
 
 1731     QMenu *selectMenu = 
new QMenu( selectButton );
 
 1732     QAction *selectAction = 
new QAction( tr( 
"Select Features" ), selectMenu );
 
 1734     connect( selectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchSetSelection );
 
 1735     selectMenu->addAction( selectAction );
 
 1736     QAction *addSelectAction = 
new QAction( tr( 
"Add to Current Selection" ), selectMenu );
 
 1738     connect( addSelectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchAddToSelection );
 
 1739     selectMenu->addAction( addSelectAction );
 
 1740     QAction *deselectAction = 
new QAction( tr( 
"Remove from Current Selection" ), selectMenu );
 
 1742     connect( deselectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchRemoveFromSelection );
 
 1743     selectMenu->addAction( deselectAction );
 
 1744     QAction *filterSelectAction = 
new QAction( tr( 
"Filter Current Selection" ), selectMenu );
 
 1746     connect( filterSelectAction, &QAction::triggered, 
this, &QgsAttributeForm::searchIntersectSelection );
 
 1747     selectMenu->addAction( filterSelectAction );
 
 1748     selectButton->setMenu( selectMenu );
 
 1749     boxLayout->addWidget( selectButton );
 
 1753       QToolButton *filterButton = 
new QToolButton();
 
 1754       filterButton->setText( tr( 
"Filter Features" ) );
 
 1755       filterButton->setPopupMode( QToolButton::MenuButtonPopup );
 
 1756       filterButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
 
 1757       connect( filterButton, &QToolButton::clicked, 
this, &QgsAttributeForm::filterTriggered );
 
 1758       QMenu *filterMenu = 
new QMenu( filterButton );
 
 1759       QAction *filterAndAction = 
new QAction( tr( 
"Filter Within (\"AND\")" ), filterMenu );
 
 1760       connect( filterAndAction, &QAction::triggered, 
this, &QgsAttributeForm::filterAndTriggered );
 
 1761       filterMenu->addAction( filterAndAction );
 
 1762       QAction *filterOrAction = 
new QAction( tr( 
"Extend Filter (\"OR\")" ), filterMenu );
 
 1763       connect( filterOrAction, &QAction::triggered, 
this, &QgsAttributeForm::filterOrTriggered );
 
 1764       filterMenu->addAction( filterOrAction );
 
 1765       filterButton->setMenu( filterMenu );
 
 1766       boxLayout->addWidget( filterButton );
 
 1770       QPushButton *closeButton = 
new QPushButton( tr( 
"Close" ), mSearchButtonBox );
 
 1772       closeButton->setShortcut( Qt::Key_Escape );
 
 1773       boxLayout->addWidget( closeButton );
 
 1776     layout->addWidget( mSearchButtonBox );
 
 1794   const auto constMInterfaces = mInterfaces;
 
 1805   QApplication::restoreOverrideCursor();
 
 1808 void QgsAttributeForm::cleanPython()
 
 1810   if ( !mPyFormVarName.isNull() )
 
 1812     QString expr = QStringLiteral( 
"if '%1' in locals(): del %1\n" ).arg( mPyFormVarName );
 
 1817 void QgsAttributeForm::initPython()
 
 1824        && mLayer->
editFormConfig().initCodeSource() != QgsEditFormConfig::CodeSourceNone )
 
 1833       case QgsEditFormConfig::CodeSourceFile:
 
 1834         if ( !initFilePath.isEmpty() )
 
 1838           if ( inputFile && inputFile->open( QFile::ReadOnly ) )
 
 1841             QTextStream inf( inputFile );
 
 1842             initCode = inf.readAll();
 
 1847             QgsLogger::warning( QStringLiteral( 
"The external python file path %1 could not be opened!" ).arg( initFilePath ) );
 
 1856       case QgsEditFormConfig::CodeSourceDialog:
 
 1858         if ( initCode.isEmpty() )
 
 1860           QgsLogger::warning( QStringLiteral( 
"The python code provided in the dialog is empty!" ) );
 
 1864       case QgsEditFormConfig::CodeSourceEnvironment:
 
 1865       case QgsEditFormConfig::CodeSourceNone:
 
 1871     if ( !initCode.isEmpty() )
 
 1877                                   tr( 
"Python macro could not be run due to missing permissions." ),
 
 1878                                   Qgis::MessageLevel::Warning );
 
 1885     if ( 
QgsPythonRunner::eval( QStringLiteral( 
"len(inspect.getfullargspec(%1)[0])" ).arg( initFunction ), numArgs ) )
 
 1887       static int sFormId = 0;
 
 1888       mPyFormVarName = QStringLiteral( 
"_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
 
 1890       QString form = QStringLiteral( 
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
 
 1891                      .arg( mPyFormVarName )
 
 1892                      .arg( ( quint64 ) 
this );
 
 1896       QgsDebugMsg( QStringLiteral( 
"running featureForm init: %1" ).arg( mPyFormVarName ) );
 
 1899       if ( numArgs == QLatin1String( 
"3" ) )
 
 1907         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 ) );
 
 1910         QString expr = QString( 
"%1(%2)" )
 
 1911                        .arg( mLayer->editFormInit() )
 
 1912                        .arg( mPyFormVarName );
 
 1913         QgsAttributeFormInterface *iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface *>( expr, 
"QgsAttributeFormInterface" );
 
 1923       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 ) );
 
 1931   WidgetInfo newWidgetInfo;
 
 1933   switch ( widgetDef->type() )
 
 1935     case QgsAttributeEditorElement::AeTypeField:
 
 1937       const QgsAttributeEditorField *fieldDef = 
dynamic_cast<const QgsAttributeEditorField *
>( widgetDef );
 
 1942       int fldIdx = fields.
lookupField( fieldDef->name() );
 
 1943       if ( fldIdx < fields.
count() && fldIdx >= 0 )
 
 1949         mFormEditorWidgets.insert( fldIdx, formWidget );
 
 1950         mFormWidgets.append( formWidget );
 
 1954         newWidgetInfo.widget = formWidget;
 
 1955         addWidgetWrapper( eww );
 
 1957         newWidgetInfo.widget->setObjectName( fields.
at( fldIdx ).
name() );
 
 1958         newWidgetInfo.hint = fields.
at( fldIdx ).
comment();
 
 1961       newWidgetInfo.labelOnTop = mLayer->
editFormConfig().labelOnTop( fldIdx );
 
 1963       newWidgetInfo.labelText.replace( 
'&', QLatin1String( 
"&&" ) ); 
 
 1964       newWidgetInfo.toolTip = QStringLiteral( 
"<b>%1</b><p>%2</p>" ).arg( mLayer->
attributeDisplayName( fldIdx ), newWidgetInfo.hint );
 
 1965       newWidgetInfo.showLabel = widgetDef->showLabel();
 
 1970     case QgsAttributeEditorElement::AeTypeRelation:
 
 1972       const QgsAttributeEditorRelation *relDef = 
static_cast<const QgsAttributeEditorRelation *
>( widgetDef );
 
 1974       QgsRelationWidgetWrapper *rww = setupRelationWidgetWrapper( relDef->relationWidgetTypeId(), relDef->relation(), context );
 
 1988       mWidgets.append( rww );
 
 1989       mFormWidgets.append( formWidget );
 
 1991       newWidgetInfo.widget = formWidget;
 
 1992       newWidgetInfo.showLabel = relDef->showLabel();
 
 1993       newWidgetInfo.labelText = QString();
 
 1994       newWidgetInfo.labelOnTop = 
true;
 
 1998     case QgsAttributeEditorElement::AeTypeContainer:
 
 2000       const QgsAttributeEditorContainer *container = 
dynamic_cast<const QgsAttributeEditorContainer *
>( widgetDef );
 
 2004       int columnCount = container->columnCount();
 
 2006       if ( columnCount <= 0 )
 
 2010       QWidget *myContainer = 
nullptr;
 
 2011       if ( container->isGroupBox() )
 
 2013         QGroupBox *groupBox = 
new QGroupBox( parent );
 
 2014         widgetName = QStringLiteral( 
"QGroupBox" );
 
 2015         if ( container->showLabel() )
 
 2016           groupBox->setTitle( container->name() );
 
 2017         myContainer = groupBox;
 
 2018         newWidgetInfo.widget = myContainer;
 
 2022         myContainer = 
new QWidget();
 
 2028           scrollArea->setWidget( myContainer );
 
 2029           scrollArea->setWidgetResizable( 
true );
 
 2030           scrollArea->setFrameShape( QFrame::NoFrame );
 
 2031           widgetName = QStringLiteral( 
"QScrollArea QWidget" );
 
 2033           newWidgetInfo.widget = scrollArea;
 
 2037           newWidgetInfo.widget = myContainer;
 
 2038           widgetName = QStringLiteral( 
"QWidget" );
 
 2042       if ( container->backgroundColor().isValid() )
 
 2044         QString style {QStringLiteral( 
"background-color: %1;" ).arg( container->backgroundColor().name() )};
 
 2045         newWidgetInfo.widget->setStyleSheet( style );
 
 2048       QGridLayout *gbLayout = 
new QGridLayout();
 
 2049       myContainer->setLayout( gbLayout );
 
 2054       const QList<QgsAttributeEditorElement *> children = container->children();
 
 2056       for ( QgsAttributeEditorElement *childDef : children )
 
 2058         WidgetInfo widgetInfo = createWidgetFromDef( childDef, myContainer, vl, context );
 
 2060         if ( childDef->type() == QgsAttributeEditorElement::AeTypeContainer )
 
 2062           QgsAttributeEditorContainer *containerDef = 
static_cast<QgsAttributeEditorContainer *
>( childDef );
 
 2063           if ( containerDef->visibilityExpression().enabled() )
 
 2065             registerContainerInformation( 
new ContainerInformation( widgetInfo.widget, containerDef->visibilityExpression().data() ) );
 
 2069         if ( widgetInfo.labelText.isNull() )
 
 2071           gbLayout->addWidget( widgetInfo.widget, row, column, 1, 2 );
 
 2076           QLabel *mypLabel = 
new QLabel( widgetInfo.labelText );
 
 2079           if ( childDef->type() == QgsAttributeEditorElement::AeTypeField )
 
 2081             const QgsAttributeEditorField *fieldDef { 
static_cast<QgsAttributeEditorField *
>( childDef ) };
 
 2083             const int fldIdx = fieldDef->idx();
 
 2084             if ( fldIdx < fields.
count() && fldIdx >= 0 )
 
 2086               const QString fieldName { fields.
at( fldIdx ).
name() };
 
 2087               if ( mLayer->
editFormConfig().dataDefinedFieldProperties( fieldName ).hasProperty( QgsEditFormConfig::DataDefinedProperty::Alias ) )
 
 2089                 const QgsProperty property { mLayer->
editFormConfig().dataDefinedFieldProperties( fieldName ).property( QgsEditFormConfig::DataDefinedProperty::Alias ) };
 
 2090                 if ( property.isActive() && ! 
property.expressionString().isEmpty() )
 
 2092                   mLabelDataDefinedProperties[ mypLabel ] = property;
 
 2098           mypLabel->setToolTip( widgetInfo.toolTip );
 
 2099           if ( columnCount > 1 && !widgetInfo.labelOnTop )
 
 2101             mypLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
 
 2104           mypLabel->setBuddy( widgetInfo.widget );
 
 2106           if ( widgetInfo.labelOnTop )
 
 2108             QVBoxLayout *
c = 
new QVBoxLayout();
 
 2109             mypLabel->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
 
 2110             c->layout()->addWidget( mypLabel );
 
 2111             c->layout()->addWidget( widgetInfo.widget );
 
 2112             gbLayout->addLayout( 
c, row, column, 1, 2 );
 
 2117             gbLayout->addWidget( mypLabel, row, column++ );
 
 2118             gbLayout->addWidget( widgetInfo.widget, row, column++ );
 
 2122         if ( column >= columnCount * 2 )
 
 2128       QWidget *spacer = 
new QWidget();
 
 2129       spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
 
 2130       gbLayout->addWidget( spacer, ++row, 0 );
 
 2131       gbLayout->setRowStretch( row, 1 );
 
 2133       newWidgetInfo.labelText = QString();
 
 2134       newWidgetInfo.labelOnTop = 
true;
 
 2138     case QgsAttributeEditorElement::AeTypeQmlElement:
 
 2140       const QgsAttributeEditorQmlElement *elementDef = 
static_cast<const QgsAttributeEditorQmlElement *
>( widgetDef );
 
 2143       qmlWrapper->
setQmlCode( elementDef->qmlCode() );
 
 2147       mWidgets.append( qmlWrapper );
 
 2149       newWidgetInfo.widget = qmlWrapper->
widget();
 
 2150       newWidgetInfo.labelText = elementDef->name();
 
 2151       newWidgetInfo.labelOnTop = 
true;
 
 2152       newWidgetInfo.showLabel = widgetDef->showLabel();
 
 2156     case QgsAttributeEditorElement::AeTypeHtmlElement:
 
 2158       const QgsAttributeEditorHtmlElement *elementDef = 
static_cast<const QgsAttributeEditorHtmlElement *
>( widgetDef );
 
 2162       htmlWrapper->
setHtmlCode( elementDef->htmlCode() );
 
 2164       mWidgets.append( htmlWrapper );
 
 2166       newWidgetInfo.widget = htmlWrapper->
widget();
 
 2167       newWidgetInfo.labelText = elementDef->name();
 
 2168       newWidgetInfo.labelOnTop = 
true;
 
 2169       newWidgetInfo.showLabel = widgetDef->showLabel();
 
 2174       QgsDebugMsg( QStringLiteral( 
"Unknown attribute editor widget type encountered..." ) );
 
 2178   newWidgetInfo.showLabel = widgetDef->showLabel();
 
 2180   return newWidgetInfo;
 
 2201   mWidgets.append( eww );
 
 2204 void QgsAttributeForm::createWrappers()
 
 2206   QList<QWidget *> myWidgets = findChildren<QWidget *>();
 
 2207   const QList<QgsField> fields = mLayer->
fields().
toList();
 
 2209   const auto constMyWidgets = myWidgets;
 
 2210   for ( QWidget *myWidget : constMyWidgets )
 
 2213     QVariant vRel = myWidget->property( 
"qgisRelation" );
 
 2214     if ( vRel.isValid() )
 
 2224         mWidgets.append( rww );
 
 2229       const auto constFields = fields;
 
 2232         if ( 
field.
name() == myWidget->objectName() )
 
 2237           addWidgetWrapper( eww );
 
 2244 void QgsAttributeForm::afterWidgetInit()
 
 2246   bool isFirstEww = 
true;
 
 2248   const auto constMWidgets = mWidgets;
 
 2257         setFocusProxy( eww->
widget() );
 
 2272   if ( e->type() == QEvent::KeyPress )
 
 2274     QKeyEvent *keyEvent = 
dynamic_cast<QKeyEvent *
>( e );
 
 2275     if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
 
 2287     QSet< int > &mixedValueFields,
 
 2288     QHash< int, QVariant > &fieldSharedValues )
 const 
 2290   mixedValueFields.clear();
 
 2291   fieldSharedValues.clear();
 
 2297     for ( 
int i = 0; i < mLayer->
fields().count(); ++i )
 
 2299       if ( mixedValueFields.contains( i ) )
 
 2304         fieldSharedValues[i] = f.
attribute( i );
 
 2308         if ( fieldSharedValues.value( i ) != f.
attribute( i ) )
 
 2310           fieldSharedValues.remove( i );
 
 2311           mixedValueFields.insert( i );
 
 2317     if ( mixedValueFields.count() == mLayer->
fields().
count() )
 
 2326 void QgsAttributeForm::layerSelectionChanged()
 
 2339       resetMultiEdit( 
true );
 
 2346   mIsSettingMultiEditFeatures = 
true;
 
 2347   mMultiEditFeatureIds = fids;
 
 2349   if ( fids.isEmpty() )
 
 2352     QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
 
 2353     for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
 
 2355       wIt.value()->initialize( QVariant() );
 
 2357     mIsSettingMultiEditFeatures = 
false;
 
 2364   QSet< int > mixedValueFields;
 
 2365   QHash< int, QVariant > fieldSharedValues;
 
 2366   scanForEqualAttributes( fit, mixedValueFields, fieldSharedValues );
 
 2373   const auto constMixedValueFields = mixedValueFields;
 
 2374   for ( 
int fieldIndex : qgis::as_const( mixedValueFields ) )
 
 2378       const QStringList additionalFields = w->editorWidget()->additionalFields();
 
 2379       QVariantList additionalFieldValues;
 
 2380       for ( 
const QString &additionalField : additionalFields )
 
 2381         additionalFieldValues << firstFeature.
attribute( additionalField );
 
 2382       w->initialize( firstFeature.
attribute( fieldIndex ), 
true, additionalFieldValues );
 
 2385   QHash< int, QVariant >::const_iterator sharedValueIt = fieldSharedValues.constBegin();
 
 2386   for ( ; sharedValueIt != fieldSharedValues.constEnd(); ++sharedValueIt )
 
 2391       const QStringList additionalFields = w->editorWidget()->additionalFields();
 
 2392       for ( 
const QString &additionalField : additionalFields )
 
 2395         if ( constMixedValueFields.contains( index ) )
 
 2402       QVariantList additionalFieldValues;
 
 2405         for ( 
const QString &additionalField : additionalFields )
 
 2406           additionalFieldValues << firstFeature.
attribute( additionalField );
 
 2407         w->initialize( firstFeature.
attribute( sharedValueIt.key() ), 
true, additionalFieldValues );
 
 2411         for ( 
const QString &additionalField : additionalFields )
 
 2414           Q_ASSERT( fieldSharedValues.contains( index ) );
 
 2415           additionalFieldValues << fieldSharedValues.value( index );
 
 2417         w->initialize( sharedValueIt.value(), 
false, additionalFieldValues );
 
 2421   mIsSettingMultiEditFeatures = 
false;
 
 2426   if ( mOwnsMessageBar )
 
 2428   mOwnsMessageBar = 
false;
 
 2429   mMessageBar = messageBar;
 
 2439   QStringList filters;
 
 2442     QString filter = widget->currentFilterExpression();
 
 2443     if ( !filter.isNull() )
 
 2444       filters << 
'(' + filter + 
')';
 
 2447   return filters.join( QLatin1String( 
" AND " ) );
 
 2452   mExtraContextScope.reset( extraScope );
 
 2457   bool newVisibility = expression.evaluate( expressionContext ).toBool();
 
 2459   if ( newVisibility != isVisible )
 
 2467       widget->setVisible( newVisibility );
 
 2470     isVisible = newVisibility;
 
 2483   if ( infos.count() == 0 || !currentFormValuesFeature( formFeature ) )
 
 2486   const QString hint = tr( 
"No feature joined" );
 
 2487   const auto constInfos = infos;
 
 2490     if ( !info->isDynamicFormEnabled() )
 
 2495     mJoinedFeatures[info] = joinFeature;
 
 2497     if ( info->hasSubset() )
 
 2501       const auto constSubsetNames = subsetNames;
 
 2502       for ( 
const QString &
field : constSubsetNames )
 
 2504         QString prefixedName = info->prefixedFieldName( 
field );
 
 2506         QString hintText = hint;
 
 2522         QString prefixedName = info->prefixedFieldName( 
field );
 
 2524         QString hintText = hint;
 
 2538 bool QgsAttributeForm::fieldIsEditable( 
int fieldIndex )
 const 
 2543 void QgsAttributeForm::updateDefaultValueDependencies()
 
 2545   mDefaultValueDependencies.clear();
 
 2553       const QSet<QString> referencedColumns = exp.referencedColumns();
 
 2554       for ( 
const QString &referencedColumn : referencedColumns )
 
 2560           for ( 
const int id : allAttributeIds )
 
 2562             mDefaultValueDependencies.insertMulti( 
id, eww );
 
 2567           mDefaultValueDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
 
 2580   mIconMap[eww->
widget()]->hide();
 
 2594         const QString file = QStringLiteral( 
"/mIconJoinNotEditable.svg" );
 
 2595         const QString tooltip = tr( 
"Join settings do not allow editing" );
 
 2596         reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 2600         const QString file = QStringLiteral( 
"mIconJoinHasNotUpsertOnEdit.svg" );
 
 2601         const QString tooltip = tr( 
"Join settings do not allow upsert on edit" );
 
 2602         reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 2606         const QString file = QStringLiteral( 
"/mIconJoinedLayerNotEditable.svg" );
 
 2607         const QString tooltip = tr( 
"Joined layer is not toggled editable" );
 
 2608         reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
 
 2614 void QgsAttributeForm::reloadIcon( 
const QString &file, 
const QString &tooltip, QSvgWidget *sw )
 
 2617   sw->setToolTip( tooltip );
 
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
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.
Mode attributeFormMode() const
Returns current attributeFormMode.
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 id, geometry and a list of field/values...
bool setAttribute(int field, const QVariant &attr)
Set 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)
Assign 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 from attribute name.
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
Gets field's origin (value from an enumeration)
QgsField field(int fieldIdx) const
Gets 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
Gets 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.
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 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.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
bool popWidget(QgsMessageBarItem *item)
Remove the specified item from the bar, and display the next most recent one in the stack.
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.
QgsRelationManager * relationManager
static QgsProject * instance()
Returns the QgsProject singleton instance.
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.
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.
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)
QStringList * joinFieldNamesSubset() const
Returns the subset of fields to be used from joined layer.
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.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
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.
void editingStarted()
Emitted when editing on this layer has started.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
void endEditCommand()
Finish edit command and add it to undo/redo stack.
void destroyEditCommand()
Destroy active command and reverts all changes in it.
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Q_INVOKABLE void selectByExpression(const QString &expression, QgsVectorLayer::SelectBehavior behavior=QgsVectorLayer::SetSelection)
Selects matching features using an expression.
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.
SelectBehavior
Selection behavior.
@ RemoveFromSelection
Remove from current selection.
@ IntersectSelection
Modify current selection to include only select features which match.
@ AddToSelection
Add selection to current selection.
@ SetSelection
Set selection, removing any existing selection.
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)