47 #include <QTextStream> 50 #include <QFormLayout> 51 #include <QGridLayout> 55 #include <QPushButton> 57 #include <QMessageBox> 58 #include <QToolButton> 61 int QgsAttributeForm::sFormCounter = 0;
66 , mOwnsMessageBar( true )
68 , mFormNr( sFormCounter++ )
70 , mPreventFeatureRefresh( false )
71 , mIsSettingMultiEditFeatures( false )
72 , mUnsavedMultiEditChanges( false )
73 , mEditCommandMessage( tr(
"Attributes changed" ) )
86 updateContainersVisibility();
92 qDeleteAll( mInterfaces );
119 mInterfaces.append( iface );
135 if ( mUnsavedMultiEditChanges )
138 int res = QMessageBox::question(
this, tr(
"Multiedit Attributes" ),
139 tr(
"Apply changes to edited features?" ), QMessageBox::Yes | QMessageBox::No );
140 if ( res == QMessageBox::Yes )
145 clearMultiEditMessages();
147 mUnsavedMultiEditChanges =
false;
195 w->setContext( newContext );
201 w->setVisible( relationWidgetsVisible );
208 mSearchButtonBox->setVisible(
false );
212 synchronizeEnabledState();
213 mSearchButtonBox->setVisible(
false );
217 resetMultiEdit(
false );
218 synchronizeEnabledState();
219 mSearchButtonBox->setVisible(
false );
223 mSearchButtonBox->setVisible(
true );
228 mSearchButtonBox->setVisible(
false );
234 mSearchButtonBox->setVisible(
false );
243 const auto constMWidgets = mWidgets;
247 if ( eww && eww->
field().
name() == field )
256 QVariant mainValue = eww->
value();
258 additionalFieldValues[index] = value;
259 eww->
setValues( mainValue, additionalFieldValues );
267 mIsSettingFeature =
true;
278 synchronizeEnabledState();
282 mIsSettingFeature =
false;
283 const auto constMInterfaces = mInterfaces;
286 iface->featureChanged();
302 mIsSettingFeature =
false;
305 bool QgsAttributeForm::saveEdits()
308 bool changedLayer =
false;
314 bool doUpdate =
false;
329 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
330 QVariantList srcVars = QVariantList() << eww->
value();
331 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
335 for (
const QString &fieldName : additionalFields )
339 dstVars << dst.at( idx );
343 Q_ASSERT( dstVars.count() == srcVars.count() );
345 for (
int i = 0; i < dstVars.count(); i++ )
348 if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() && fieldIsEditable( fieldIndexes[i] ) )
350 dst[fieldIndexes[i]] = srcVars[i];
360 const auto constMInterfaces = mInterfaces;
363 if ( !iface->acceptChanges( updatedFeature ) )
375 bool res = mLayer->
addFeature( updatedFeature );
394 for (
int i = 0; i < dst.count(); ++i )
397 || !dst.at( i ).isValid()
398 || !fieldIsEditable( i ) )
403 QgsDebugMsg( QStringLiteral(
"Updating field %1" ).arg( i ) );
404 QgsDebugMsg( QStringLiteral(
"dst:'%1' (type:%2, isNull:%3, isValid:%4)" )
405 .arg( dst.at( i ).toString(), dst.at( i ).typeName() ).arg( dst.at( i ).isNull() ).arg( dst.at( i ).isValid() ) );
406 QgsDebugMsg( QStringLiteral(
"src:'%1' (type:%2, isNull:%3, isValid:%4)" )
407 .arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( src.at( i ).isNull() ).arg( src.at( i ).isValid() ) );
409 newValues[i] = dst.at( i );
410 oldValues[i] = src.at( i );
417 if ( success && n > 0 )
444 bool QgsAttributeForm::updateDefaultValues(
const int originIdx )
446 if ( !mDefaultValueDependencies.contains( originIdx ) )
459 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
460 QVariantList srcVars = QVariantList() << eww->
value();
461 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
465 for (
const QString &fieldName : additionalFields )
469 dstVars << dst.at( idx );
473 Q_ASSERT( dstVars.count() == srcVars.count() );
475 for (
int i = 0; i < dstVars.count(); i++ )
478 if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() && fieldIsEditable( fieldIndexes[i] ) )
480 dst[fieldIndexes[i]] = srcVars[i];
488 QList<QgsWidgetWrapper *> relevantWidgets = mDefaultValueDependencies.values( originIdx );
501 if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
512 void QgsAttributeForm::resetMultiEdit(
bool promptToSave )
517 mUnsavedMultiEditChanges =
false;
521 void QgsAttributeForm::multiEditMessageClicked(
const QString &link )
523 clearMultiEditMessages();
524 resetMultiEdit( link == QLatin1String(
"#apply" ) );
527 void QgsAttributeForm::filterTriggered()
529 QString filter = createFilterExpression();
535 void QgsAttributeForm::searchZoomTo()
537 QString filter = createFilterExpression();
538 if ( filter.isEmpty() )
544 void QgsAttributeForm::searchFlash()
546 QString filter = createFilterExpression();
547 if ( filter.isEmpty() )
553 void QgsAttributeForm::filterAndTriggered()
555 QString filter = createFilterExpression();
556 if ( filter.isEmpty() )
564 void QgsAttributeForm::filterOrTriggered()
566 QString filter = createFilterExpression();
567 if ( filter.isEmpty() )
575 void QgsAttributeForm::pushSelectedFeaturesMessage()
581 tr(
"%n matching feature(s) selected",
"matching features", count ),
588 tr(
"No matching features found" ),
596 QString filter = createFilterExpression();
597 if ( filter.isEmpty() )
601 pushSelectedFeaturesMessage();
606 void QgsAttributeForm::searchSetSelection()
611 void QgsAttributeForm::searchAddToSelection()
616 void QgsAttributeForm::searchRemoveFromSelection()
621 void QgsAttributeForm::searchIntersectSelection()
626 bool QgsAttributeForm::saveMultiEdits()
630 QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
631 for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
638 || !fieldIsEditable( wIt.key() ) )
646 newAttributeValues.insert( wIt.key(), w->
currentValue() );
649 if ( newAttributeValues.isEmpty() )
657 int res = QMessageBox::information(
this, tr(
"Multiedit Attributes" ),
658 tr(
"Edits will be applied to all selected features." ), QMessageBox::Ok | QMessageBox::Cancel );
659 if ( res != QMessageBox::Ok )
670 const auto constMMultiEditFeatureIds = mMultiEditFeatureIds;
673 QgsAttributeMap::const_iterator aIt = newAttributeValues.constBegin();
674 for ( ; aIt != newAttributeValues.constEnd(); ++aIt )
680 clearMultiEditMessages();
693 if ( !mButtonBox->isVisible() )
694 mMessageBar->
pushItem( mMultiEditMessageBarItem );
705 wrapper->notifyAboutToSave();
743 success = saveEdits();
747 success = saveMultiEdits();
752 mUnsavedMultiEditChanges =
false;
760 mValuesInitialized =
false;
761 const auto constMWidgets = mWidgets;
764 ww->setFeature( mFeature );
766 mValuesInitialized =
true;
772 const auto widgets { findChildren< QgsAttributeFormEditorWidget * >() };
779 void QgsAttributeForm::clearMultiEditMessages()
781 if ( mMultiEditUnsavedMessageBarItem )
783 if ( !mButtonBox->isVisible() )
784 mMessageBar->
popWidget( mMultiEditUnsavedMessageBarItem );
785 mMultiEditUnsavedMessageBarItem =
nullptr;
787 if ( mMultiEditMessageBarItem )
789 if ( !mButtonBox->isVisible() )
790 mMessageBar->
popWidget( mMultiEditMessageBarItem );
791 mMultiEditMessageBarItem =
nullptr;
795 QString QgsAttributeForm::createFilterExpression()
const 800 QString filter = w->currentFilterExpression();
801 if ( !filter.isEmpty() )
805 if ( filters.isEmpty() )
808 QString filter = filters.join( QStringLiteral(
") AND (" ) ).prepend(
'(' ).append(
')' );
813 void QgsAttributeForm::onAttributeChanged(
const QVariant &value,
const QVariantList &additionalFieldValues )
818 bool signalEmitted =
false;
820 if ( mValuesInitialized )
836 for (
int i = 0; i < additionalFields.count(); i++ )
838 const QString fieldName = additionalFields.at( i );
839 const QVariant value = additionalFieldValues.at( i );
843 signalEmitted =
true;
845 updateJoinedFields( *eww );
851 if ( !mIsSettingMultiEditFeatures )
853 mUnsavedMultiEditChanges =
true;
855 QLabel *msgLabel =
new QLabel( tr(
"Unsaved multiedit changes: <a href=\"#apply\">apply changes</a> or <a href=\"#reset\">reset changes</a>." ), mMessageBar );
856 msgLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
857 msgLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
858 connect( msgLabel, &QLabel::linkActivated,
this, &QgsAttributeForm::multiEditMessageClicked );
859 clearMultiEditMessages();
862 if ( !mButtonBox->isVisible() )
863 mMessageBar->
pushItem( mMultiEditUnsavedMessageBarItem );
873 updateConstraints( eww );
876 mAlreadyUpdatedFields.append( eww->
fieldIdx() );
877 updateDefaultValues( eww->
fieldIdx() );
878 mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
880 if ( !signalEmitted )
889 void QgsAttributeForm::updateAllConstraints()
891 const auto constMWidgets = mWidgets;
896 updateConstraints( eww );
904 if ( currentFormFeature( ft ) )
916 updateConstraint( ft, eww );
919 const QList<QgsEditorWidgetWrapper *> deps = constraintDependencies( eww );
922 updateConstraint( ft, depsEww );
925 synchronizeEnabledState();
932 const QVector<ContainerInformation *> infos = mContainerInformationDependency.value( eww->
field().
name() );
933 for ( ContainerInformation *info : infos )
935 info->apply( &mExpressionContext );
940 void QgsAttributeForm::updateContainersVisibility()
944 const QVector<ContainerInformation *> infos = mContainerVisibilityInformation;
946 for ( ContainerInformation *info : infos )
948 info->apply( &mExpressionContext );
952 updateAllConstraints();
966 if ( mJoinedFeatures.contains( info ) )
996 if ( dst.count() > eww->
fieldIdx() )
998 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
999 QVariantList srcVars = QVariantList() << eww->
value();
1000 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
1004 for (
const QString &fieldName : additionalFields )
1007 fieldIndexes << idx;
1008 dstVars << dst.at( idx );
1012 Q_ASSERT( dstVars.count() == srcVars.count() );
1014 for (
int i = 0; i < dstVars.count(); i++ )
1018 if ( ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) || dstVars[i].isNull() != srcVars[i].isNull() ) && srcVars[i].isValid() )
1020 dst[fieldIndexes[i]] = srcVars[i];
1037 void QgsAttributeForm::registerContainerInformation( QgsAttributeForm::ContainerInformation *info )
1039 mContainerVisibilityInformation.append( info );
1041 const QSet<QString> referencedColumns = info->expression.referencedColumns();
1043 for (
const QString &col : referencedColumns )
1045 mContainerInformationDependency[ col ].append( info );
1049 bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions )
1073 void QgsAttributeForm::onAttributeAdded(
int idx )
1075 mPreventFeatureRefresh =
false;
1079 attrs.insert( idx, QVariant(
layer()->fields().at( idx ).type() ) );
1087 void QgsAttributeForm::onAttributeDeleted(
int idx )
1089 mPreventFeatureRefresh =
false;
1093 attrs.remove( idx );
1101 void QgsAttributeForm::onUpdatedFields()
1103 mPreventFeatureRefresh =
false;
1115 attrs[i].convert(
layer()->fields().at( i ).type() );
1120 attrs[i] = QVariant(
layer()->fields().at( i ).type() );
1130 void QgsAttributeForm::onConstraintStatusChanged(
const QString &constraint,
1138 if ( formEditorWidget )
1144 QList<QgsEditorWidgetWrapper *> wDeps;
1156 if ( name != ewwName )
1163 for (
const QString &colName : referencedColumns )
1165 if ( name == colName )
1167 wDeps.append( eww );
1188 void QgsAttributeForm::preventFeatureRefresh()
1190 mPreventFeatureRefresh =
true;
1207 void QgsAttributeForm::synchronizeEnabledState()
1209 bool isEditable = ( mFeature.
isValid()
1225 bool enabled = isEditable && fieldIsEditable( eww->
fieldIdx() );
1226 ww->setEnabled( enabled );
1234 QStringList invalidFields, descriptions;
1235 bool validConstraint = currentFormValidConstraints( invalidFields, descriptions );
1237 isEditable = isEditable & validConstraint;
1241 QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
1243 okButton->setEnabled( isEditable );
1246 void QgsAttributeForm::init()
1248 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1251 QWidget *formWidget =
nullptr;
1253 bool buttonBoxVisible =
true;
1257 buttonBoxVisible = mButtonBox->isVisible();
1259 mButtonBox =
nullptr;
1262 if ( mSearchButtonBox )
1264 delete mSearchButtonBox;
1265 mSearchButtonBox =
nullptr;
1268 qDeleteAll( mWidgets );
1271 while ( QWidget *w = this->findChild<QWidget *>() )
1277 QVBoxLayout *vl =
new QVBoxLayout();
1279 vl->setContentsMargins( 0, 0, 0, 0 );
1281 mMessageBar->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
1282 vl->addWidget( mMessageBar );
1287 QGridLayout *layout =
new QGridLayout();
1288 QWidget *container =
new QWidget();
1289 container->setLayout( layout );
1290 vl->addWidget( container );
1292 mFormEditorWidgets.clear();
1293 mFormWidgets.clear();
1296 setContentsMargins( 0, 0, 0, 0 );
1305 if ( file && file->open( QFile::ReadOnly ) )
1309 QFileInfo fi( file->fileName() );
1310 loader.setWorkingDirectory( fi.dir() );
1311 formWidget = loader.load( file,
this );
1314 formWidget->setWindowFlags( Qt::Widget );
1315 layout->addWidget( formWidget );
1318 mButtonBox = findChild<QDialogButtonBox *>();
1321 formWidget->installEventFilter(
this );
1333 int columnCount = 1;
1342 if ( !containerDef )
1347 tabWidget =
nullptr;
1348 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
1349 layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
1352 registerContainerInformation(
new ContainerInformation( widgetInfo.widget, containerDef->
visibilityExpression().
data() ) );
1361 layout->addWidget( tabWidget, row, column, 1, 2 );
1365 QWidget *tabPage =
new QWidget( tabWidget );
1367 tabWidget->addTab( tabPage, widgDef->name() );
1371 registerContainerInformation(
new ContainerInformation( tabWidget, tabPage, containerDef->
visibilityExpression().
data() ) );
1373 QGridLayout *tabPageLayout =
new QGridLayout();
1374 tabPage->setLayout( tabPageLayout );
1376 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, tabPage, mLayer, mContext );
1377 tabPageLayout->addWidget( widgetInfo.widget );
1382 tabWidget =
nullptr;
1383 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
1384 QLabel *label =
new QLabel( widgetInfo.labelText );
1385 label->setToolTip( widgetInfo.toolTip );
1386 if ( columnCount > 1 && !widgetInfo.labelOnTop )
1388 label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
1391 label->setBuddy( widgetInfo.widget );
1393 if ( !widgetInfo.showLabel )
1395 QVBoxLayout *
c =
new QVBoxLayout();
1396 label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1397 c->addWidget( widgetInfo.widget );
1398 layout->addLayout( c, row, column, 1, 2 );
1401 else if ( widgetInfo.labelOnTop )
1403 QVBoxLayout *
c =
new QVBoxLayout();
1404 label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1405 c->addWidget( label );
1406 c->addWidget( widgetInfo.widget );
1407 layout->addLayout( c, row, column, 1, 2 );
1412 layout->addWidget( label, row, column++ );
1413 layout->addWidget( widgetInfo.widget, row, column++ );
1417 if ( column >= columnCount * 2 )
1423 formWidget = container;
1432 formWidget =
new QWidget(
this );
1433 QGridLayout *gridLayout =
new QGridLayout( formWidget );
1434 formWidget->setLayout( gridLayout );
1440 scrollArea->setWidget( formWidget );
1441 scrollArea->setWidgetResizable(
true );
1442 scrollArea->setFrameShape( QFrame::NoFrame );
1443 scrollArea->setFrameShadow( QFrame::Plain );
1444 scrollArea->setFocusProxy(
this );
1445 layout->addWidget( scrollArea );
1449 layout->addWidget( formWidget );
1456 for (
const QgsField &field : fields )
1464 QString labelText = fieldName;
1465 labelText.replace(
'&', QStringLiteral(
"&&" ) );
1469 if ( widgetSetup.
type() == QLatin1String(
"Hidden" ) )
1475 QLabel *l =
new QLabel( labelText );
1476 l->setToolTip( QStringLiteral(
"<b>%1</b><p>%2</p>" ).arg( fieldName, field.comment() ) );
1477 QSvgWidget *i =
new QSvgWidget();
1478 i->setFixedSize( 18, 18 );
1482 QWidget *w =
nullptr;
1487 mFormEditorWidgets.insert( idx, formWidget );
1488 mFormWidgets.append( formWidget );
1491 l->setBuddy( eww->
widget() );
1495 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() ) ) );
1500 w->setObjectName( field.name() );
1504 addWidgetWrapper( eww );
1505 mIconMap[eww->
widget()] = i;
1510 gridLayout->addWidget( l, row++, 0, 1, 2 );
1511 gridLayout->addWidget( w, row++, 0, 1, 2 );
1512 gridLayout->addWidget( i, row++, 0, 1, 2 );
1516 gridLayout->addWidget( l, row, 0 );
1517 gridLayout->addWidget( w, row, 1 );
1518 gridLayout->addWidget( i, row++, 2 );
1529 gridLayout->addWidget( formWidget, row++, 0, 1, 2 );
1531 mWidgets.append( rww );
1532 mFormWidgets.append( formWidget );
1537 QSpacerItem *spacerItem =
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
1538 gridLayout->addItem( spacerItem, row, 0 );
1539 gridLayout->setRowStretch( row, 1 );
1552 for (
const QString &referencedColumn : referencedColumns )
1558 for (
const int id : allAttributeIds )
1560 mDefaultValueDependencies.insertMulti(
id, eww );
1565 mDefaultValueDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
1573 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1574 mButtonBox->setObjectName( QStringLiteral(
"buttonBox" ) );
1575 layout->addWidget( mButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
1577 mButtonBox->setVisible( buttonBoxVisible );
1579 if ( !mSearchButtonBox )
1581 mSearchButtonBox =
new QWidget();
1582 QHBoxLayout *boxLayout =
new QHBoxLayout();
1583 boxLayout->setMargin( 0 );
1584 boxLayout->setContentsMargins( 0, 0, 0, 0 );
1585 mSearchButtonBox->setLayout( boxLayout );
1586 mSearchButtonBox->setObjectName( QStringLiteral(
"searchButtonBox" ) );
1588 QPushButton *clearButton =
new QPushButton( tr(
"&Reset Form" ), mSearchButtonBox );
1590 boxLayout->addWidget( clearButton );
1591 boxLayout->addStretch( 1 );
1593 QPushButton *flashButton =
new QPushButton();
1594 flashButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1595 flashButton->setText( tr(
"&Flash Features" ) );
1596 connect( flashButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchFlash );
1597 boxLayout->addWidget( flashButton );
1599 QPushButton *zoomButton =
new QPushButton();
1600 zoomButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1601 zoomButton->setText( tr(
"&Zoom to Features" ) );
1602 connect( zoomButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchZoomTo );
1603 boxLayout->addWidget( zoomButton );
1605 QToolButton *selectButton =
new QToolButton();
1606 selectButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1607 selectButton->setText( tr(
"&Select Features" ) );
1609 selectButton->setPopupMode( QToolButton::MenuButtonPopup );
1610 selectButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
1611 connect( selectButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchSetSelection );
1612 QMenu *selectMenu =
new QMenu( selectButton );
1613 QAction *selectAction =
new QAction( tr(
"Select Features" ), selectMenu );
1615 connect( selectAction, &QAction::triggered,
this, &QgsAttributeForm::searchSetSelection );
1616 selectMenu->addAction( selectAction );
1617 QAction *addSelectAction =
new QAction( tr(
"Add to Current Selection" ), selectMenu );
1619 connect( addSelectAction, &QAction::triggered,
this, &QgsAttributeForm::searchAddToSelection );
1620 selectMenu->addAction( addSelectAction );
1621 QAction *deselectAction =
new QAction( tr(
"Remove from Current Selection" ), selectMenu );
1623 connect( deselectAction, &QAction::triggered,
this, &QgsAttributeForm::searchRemoveFromSelection );
1624 selectMenu->addAction( deselectAction );
1625 QAction *filterSelectAction =
new QAction( tr(
"Filter Current Selection" ), selectMenu );
1627 connect( filterSelectAction, &QAction::triggered,
this, &QgsAttributeForm::searchIntersectSelection );
1628 selectMenu->addAction( filterSelectAction );
1629 selectButton->setMenu( selectMenu );
1630 boxLayout->addWidget( selectButton );
1634 QToolButton *filterButton =
new QToolButton();
1635 filterButton->setText( tr(
"Filter Features" ) );
1636 filterButton->setPopupMode( QToolButton::MenuButtonPopup );
1637 filterButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1638 connect( filterButton, &QToolButton::clicked,
this, &QgsAttributeForm::filterTriggered );
1639 QMenu *filterMenu =
new QMenu( filterButton );
1640 QAction *filterAndAction =
new QAction( tr(
"Filter Within (\"AND\")" ), filterMenu );
1641 connect( filterAndAction, &QAction::triggered,
this, &QgsAttributeForm::filterAndTriggered );
1642 filterMenu->addAction( filterAndAction );
1643 QAction *filterOrAction =
new QAction( tr(
"Extend Filter (\"OR\")" ), filterMenu );
1644 connect( filterOrAction, &QAction::triggered,
this, &QgsAttributeForm::filterOrTriggered );
1645 filterMenu->addAction( filterOrAction );
1646 filterButton->setMenu( filterMenu );
1647 boxLayout->addWidget( filterButton );
1651 QPushButton *closeButton =
new QPushButton( tr(
"Close" ), mSearchButtonBox );
1653 closeButton->setShortcut( Qt::Key_Escape );
1654 boxLayout->addWidget( closeButton );
1657 layout->addWidget( mSearchButtonBox );
1675 const auto constMInterfaces = mInterfaces;
1686 QApplication::restoreOverrideCursor();
1689 void QgsAttributeForm::cleanPython()
1691 if ( !mPyFormVarName.isNull() )
1693 QString expr = QStringLiteral(
"if '%1' in locals(): del %1\n" ).arg( mPyFormVarName );
1698 void QgsAttributeForm::initPython()
1715 if ( !initFilePath.isEmpty() )
1719 if ( inputFile && inputFile->open( QFile::ReadOnly ) )
1722 QTextStream inf( inputFile );
1723 initCode = inf.readAll();
1728 QgsLogger::warning( QStringLiteral(
"The external python file path %1 could not be opened!" ).arg( initFilePath ) );
1739 if ( initCode.isEmpty() )
1741 QgsLogger::warning( QStringLiteral(
"The python code provided in the dialog is empty!" ) );
1752 if ( !initCode.isEmpty() )
1758 tr(
"Python macro could not be run due to missing permissions." ),
1759 Qgis::MessageLevel::Warning,
1767 if (
QgsPythonRunner::eval( QStringLiteral(
"len(inspect.getargspec(%1)[0])" ).arg( initFunction ), numArgs ) )
1769 static int sFormId = 0;
1770 mPyFormVarName = QStringLiteral(
"_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
1772 QString form = QStringLiteral(
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
1773 .arg( mPyFormVarName )
1774 .arg( ( quint64 )
this );
1778 QgsDebugMsg( QStringLiteral(
"running featureForm init: %1" ).arg( mPyFormVarName ) );
1781 if ( numArgs == QLatin1String(
"3" ) )
1789 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 ) );
1792 QString expr = QString(
"%1(%2)" )
1793 .arg( mLayer->editFormInit() )
1794 .arg( mPyFormVarName );
1795 QgsAttributeFormInterface *iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface *>( expr,
"QgsAttributeFormInterface" );
1805 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 ) );
1813 WidgetInfo newWidgetInfo;
1815 switch ( widgetDef->
type() )
1825 if ( fldIdx < fields.
count() && fldIdx >= 0 )
1831 mFormEditorWidgets.insert( fldIdx, formWidget );
1832 mFormWidgets.append( formWidget );
1836 newWidgetInfo.widget = formWidget;
1837 addWidgetWrapper( eww );
1839 newWidgetInfo.widget->setObjectName( fields.
at( fldIdx ).
name() );
1840 newWidgetInfo.hint = fields.
at( fldIdx ).
comment();
1845 newWidgetInfo.labelText.replace(
'&', QStringLiteral(
"&&" ) );
1846 newWidgetInfo.toolTip = QStringLiteral(
"<b>%1</b><p>%2</p>" ).arg( mLayer->
attributeDisplayName( fldIdx ), newWidgetInfo.hint );
1847 newWidgetInfo.showLabel = widgetDef->
showLabel();
1865 mWidgets.append( rww );
1866 mFormWidgets.append( formWidget );
1868 newWidgetInfo.widget = formWidget;
1869 newWidgetInfo.labelText = QString();
1870 newWidgetInfo.labelOnTop =
true;
1882 if ( columnCount <= 0 )
1886 QWidget *myContainer =
nullptr;
1889 QGroupBox *groupBox =
new QGroupBox( parent );
1890 widgetName = QStringLiteral(
"QGroupBox" );
1892 groupBox->setTitle( container->
name() );
1893 myContainer = groupBox;
1894 newWidgetInfo.widget = myContainer;
1898 myContainer =
new QWidget();
1904 scrollArea->setWidget( myContainer );
1905 scrollArea->setWidgetResizable(
true );
1906 scrollArea->setFrameShape( QFrame::NoFrame );
1907 widgetName = QStringLiteral(
"QScrollArea QWidget" );
1909 newWidgetInfo.widget = scrollArea;
1913 newWidgetInfo.widget = myContainer;
1914 widgetName = QStringLiteral(
"QWidget" );
1920 QString style {QStringLiteral(
"background-color: %1;" ).arg( container->
backgroundColor().name() )};
1921 newWidgetInfo.widget->setStyleSheet( style );
1924 QGridLayout *gbLayout =
new QGridLayout();
1925 myContainer->setLayout( gbLayout );
1930 const QList<QgsAttributeEditorElement *> children = container->
children();
1934 WidgetInfo widgetInfo = createWidgetFromDef( childDef, myContainer, vl, context );
1941 registerContainerInformation(
new ContainerInformation( widgetInfo.widget, containerDef->
visibilityExpression().
data() ) );
1945 if ( widgetInfo.labelText.isNull() )
1947 gbLayout->addWidget( widgetInfo.widget, row, column, 1, 2 );
1952 QLabel *mypLabel =
new QLabel( widgetInfo.labelText );
1953 mypLabel->setToolTip( widgetInfo.toolTip );
1954 if ( columnCount > 1 && !widgetInfo.labelOnTop )
1956 mypLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
1959 mypLabel->setBuddy( widgetInfo.widget );
1961 if ( widgetInfo.labelOnTop )
1963 QVBoxLayout *
c =
new QVBoxLayout();
1964 mypLabel->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1965 c->layout()->addWidget( mypLabel );
1966 c->layout()->addWidget( widgetInfo.widget );
1967 gbLayout->addLayout( c, row, column, 1, 2 );
1972 gbLayout->addWidget( mypLabel, row, column++ );
1973 gbLayout->addWidget( widgetInfo.widget, row, column++ );
1977 if ( column >= columnCount * 2 )
1983 QWidget *spacer =
new QWidget();
1984 spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
1985 gbLayout->addWidget( spacer, ++row, 0 );
1986 gbLayout->setRowStretch( row, 1 );
1988 newWidgetInfo.labelText = QString();
1989 newWidgetInfo.labelOnTop =
true;
2003 mWidgets.append( qmlWrapper );
2005 newWidgetInfo.widget = qmlWrapper->
widget();
2006 newWidgetInfo.labelText = elementDef->
name();
2007 newWidgetInfo.labelOnTop =
true;
2008 newWidgetInfo.showLabel = widgetDef->
showLabel();
2022 mWidgets.append( htmlWrapper );
2024 newWidgetInfo.widget = htmlWrapper->
widget();
2025 newWidgetInfo.labelText = elementDef->
name();
2026 newWidgetInfo.labelOnTop =
true;
2027 newWidgetInfo.showLabel = widgetDef->
showLabel();
2032 QgsDebugMsg( QStringLiteral(
"Unknown attribute editor widget type encountered..." ) );
2036 newWidgetInfo.showLabel = widgetDef->
showLabel();
2038 return newWidgetInfo;
2059 mWidgets.append( eww );
2062 void QgsAttributeForm::createWrappers()
2064 QList<QWidget *> myWidgets = findChildren<QWidget *>();
2065 const QList<QgsField> fields = mLayer->
fields().
toList();
2067 const auto constMyWidgets = myWidgets;
2068 for ( QWidget *myWidget : constMyWidgets )
2071 QVariant vRel = myWidget->property(
"qgisRelation" );
2072 if ( vRel.isValid() )
2082 mWidgets.append( rww );
2087 const auto constFields = fields;
2088 for (
const QgsField &field : constFields )
2090 if ( field.name() == myWidget->objectName() )
2095 addWidgetWrapper( eww );
2102 void QgsAttributeForm::afterWidgetInit()
2104 bool isFirstEww =
true;
2106 const auto constMWidgets = mWidgets;
2115 setFocusProxy( eww->
widget() );
2130 if ( e->type() == QEvent::KeyPress )
2132 QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( e );
2133 if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
2145 QSet< int > &mixedValueFields,
2146 QHash< int, QVariant > &fieldSharedValues )
const 2148 mixedValueFields.clear();
2149 fieldSharedValues.clear();
2155 for (
int i = 0; i < mLayer->
fields().
count(); ++i )
2157 if ( mixedValueFields.contains( i ) )
2162 fieldSharedValues[i] = f.
attribute( i );
2166 if ( fieldSharedValues.value( i ) != f.
attribute( i ) )
2168 fieldSharedValues.remove( i );
2169 mixedValueFields.insert( i );
2175 if ( mixedValueFields.count() == mLayer->
fields().
count() )
2184 void QgsAttributeForm::layerSelectionChanged()
2196 resetMultiEdit(
true );
2203 mIsSettingMultiEditFeatures =
true;
2204 mMultiEditFeatureIds = fids;
2206 if ( fids.isEmpty() )
2209 QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
2210 for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
2212 wIt.value()->initialize( QVariant() );
2214 mIsSettingMultiEditFeatures =
false;
2221 QSet< int > mixedValueFields;
2222 QHash< int, QVariant > fieldSharedValues;
2223 scanForEqualAttributes( fit, mixedValueFields, fieldSharedValues );
2230 const auto constMixedValueFields = mixedValueFields;
2231 for (
int fieldIndex : qgis::as_const( mixedValueFields ) )
2235 const QStringList additionalFields = w->editorWidget()->
additionalFields();
2236 QVariantList additionalFieldValues;
2237 for (
const QString &additionalField : additionalFields )
2238 additionalFieldValues << firstFeature.
attribute( additionalField );
2239 w->initialize( firstFeature.
attribute( fieldIndex ),
true, additionalFieldValues );
2242 QHash< int, QVariant >::const_iterator sharedValueIt = fieldSharedValues.constBegin();
2243 for ( ; sharedValueIt != fieldSharedValues.constEnd(); ++sharedValueIt )
2248 const QStringList additionalFields = w->editorWidget()->
additionalFields();
2249 for (
const QString &additionalField : additionalFields )
2252 if ( constMixedValueFields.contains( index ) )
2259 QVariantList additionalFieldValues;
2262 for (
const QString &additionalField : additionalFields )
2263 additionalFieldValues << firstFeature.
attribute( additionalField );
2264 w->initialize( firstFeature.
attribute( sharedValueIt.key() ),
true, additionalFieldValues );
2268 for (
const QString &additionalField : additionalFields )
2271 Q_ASSERT( fieldSharedValues.contains( index ) );
2272 additionalFieldValues << fieldSharedValues.value( index );
2274 w->initialize( sharedValueIt.value(),
false, additionalFieldValues );
2278 mIsSettingMultiEditFeatures =
false;
2283 if ( mOwnsMessageBar )
2285 mOwnsMessageBar =
false;
2286 mMessageBar = messageBar;
2296 QStringList filters;
2299 QString filter = widget->currentFilterExpression();
2300 if ( !filter.isNull() )
2301 filters <<
'(' + filter +
')';
2304 return filters.join( QStringLiteral(
" AND " ) );
2307 int QgsAttributeForm::messageTimeout()
2310 return settings.
value( QStringLiteral(
"qgis/messageTimeout" ), 5 ).toInt();
2315 bool newVisibility = expression.evaluate( expressionContext ).toBool();
2317 if ( newVisibility != isVisible )
2321 tabWidget->setTabVisible( widget, newVisibility );
2325 widget->setVisible( newVisibility );
2328 isVisible = newVisibility;
2341 if ( infos.count() == 0 || !currentFormFeature( formFeature ) )
2344 const QString hint = tr(
"No feature joined" );
2345 const auto constInfos = infos;
2348 if ( !info->isDynamicFormEnabled() )
2353 mJoinedFeatures[info] = joinFeature;
2355 if ( info->hasSubset() )
2359 const auto constSubsetNames = subsetNames;
2360 for (
const QString &field : constSubsetNames )
2362 QString prefixedName = info->prefixedFieldName( field );
2364 QString hintText = hint;
2378 for (
const QgsField &field : joinFields )
2380 QString prefixedName = info->prefixedFieldName( field );
2382 QString hintText = hint;
2396 bool QgsAttributeForm::fieldIsEditable(
int fieldIndex )
const 2407 mIconMap[eww->
widget()]->hide();
2421 const QString file = QStringLiteral(
"/mIconJoinNotEditable.svg" );
2422 const QString tooltip = tr(
"Join settings do not allow editing" );
2423 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2427 const QString file = QStringLiteral(
"mIconJoinHasNotUpsertOnEdit.svg" );
2428 const QString tooltip = tr(
"Join settings do not allow upsert on edit" );
2429 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2433 const QString file = QStringLiteral(
"/mIconJoinedLayerNotEditable.svg" );
2434 const QString tooltip = tr(
"Joined layer is not toggled editable" );
2435 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2441 void QgsAttributeForm::reloadIcon(
const QString &file,
const QString &tooltip, QSvgWidget *sw )
2444 sw->setToolTip( tooltip );
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
bool isValid() const
Returns the validity of this feature.
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
Constraint was set by layer.
An attribute editor widget that will represent arbitrary QML code.
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
QSet< QgsFeatureId > QgsFeatureIds
void setAttributeFormMode(const Mode &attributeFormMode)
Set attributeFormMode for the edited form.
int size() const
Returns number of items.
This is an abstract base class for any elements of a drag and drop form.
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field's origin (value from an enumeration)
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
bool enabled() const
Check if this optional is enabled.
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
This class is a composition of two QSettings instances:
Form is in aggregate search mode, show each widget in this mode.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool exists(int i) const
Returns if a field index is valid.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
This class contains context information for attribute editor widgets.
ConstraintOrigin
Origin of constraints.
static void warning(const QString &msg)
Goes to qWarning.
const QgsRelation & relation() const
Gets the id of the relation which shall be embedded.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
Remove from current selection.
#define Q_NOWARN_DEPRECATED_PUSH
A bar for displaying non-blocking messages to the user.
Container of fields for a vector layer.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void beforeRemovingExpressionField(int idx)
Will be emitted, when an expression field is going to be deleted from this vector layer...
This element will load a field's widget onto the form.
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...
This element will load a relation editor onto the form.
Multi edit mode, for editing fields of multiple features at once.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
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 feat...
int count() const
Returns number of items.
An attribute editor widget that will represent arbitrary HTML code.
AttributeEditorType type() const
The type of this element.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
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 isEditable() const FINAL
Returns true if the provider is in editing mode.
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
bool showUnlinkButton() const
Determines if the "unlink feature" button should be shown.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted...
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet) ...
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
bool popWidget(QgsMessageBarItem *item)
Remove the passed widget from the bar (if previously added), then display the next one in the stack i...
QString displayName() const
Returns the name to use when displaying this field.
void beforeModifiedCheck() const
Emitted when the layer is checked for modifications. Use for last-minute additions.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Defines left outer join from our vector layer to some other vector layer.
QMap< int, QVariant > QgsAttributeMap
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
bool showLabel() const
Controls if this element should be labeled with a title (field, relation or groupname).
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void destroyEditCommand()
Destroy active command and reverts all changes in it.
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
QgsOptionalExpression visibilityExpression() const
The visibility expression is used in the attribute form to show or hide this container based on an ex...
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
QString qmlCode() const
The QML code that will be represented within this widget.
QList< const QgsVectorLayerJoinInfo * > joinsWhereFieldIsId(const QgsField &field) const
Returns joins where the field of a target layer is considered as an id.
QList< QgsRelation > referencedRelations(QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Encapsulate a field in an attribute table or data source.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::Info, int duration=5)
convenience method for pushing a message to the bar
QgsRelationManager relationManager
QgsEditFormConfig editFormConfig
Add selection to current selection.
void editingStarted()
Emitted when editing on this layer has started.
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
void endEditCommand()
Finish edit command and add it to undo/redo stack.
static bool eval(const QString &command, QString &result)
Eval a Python statement.
QString htmlCode() const
The QML code that will be represented within this widget.
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
Set selection, removing any existing selection.
FormMode formMode() const
Returns the form mode.
QFile * localFile(const QString &filePathOrUrl)
Returns a QFile from a local file or to a temporary file previously fetched by the registry...
#define Q_NOWARN_DEPRECATED_POP
void setValid(bool validity)
Sets the validity of the feature.
Modify current selection to include only select features which match.
SelectBehavior
Selection behavior.
void selectByExpression(const QString &expression, SelectBehavior behavior=SetSelection)
Selects matching features using an expression.
QColor backgroundColor() const
backgroundColor
void beforeAddingExpressionField(const QString &fieldName)
Will be emitted, when an expression field is going to be added to this vector layer.
void pushItem(QgsMessageBarItem *item)
Display a message item on the bar after hiding the currently visible one and putting it in a stack...
bool allowCustomUi() const
Returns true if the attribute editor should permit use of custom UI forms.
static bool run(const QString &command, const QString &messageOnError=QString())
Execute a Python statement.
This class manages a set of relations between layers.
int columnCount() const
Gets the number of columns in this group.
Single edit mode, for editing a single feature.
static QgsProject * instance()
Returns the QgsProject singleton instance.
T data() const
Access the payload data.
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
This is a container for attribute editors, used to group them visually in the attribute form if it is...
QgsFeature joinedFeatureOf(const QgsVectorLayerJoinInfo *info, const QgsFeature &feature) const
Returns the joined feature corresponding to the feature.
QString attributeFormModeString() const
Returns given attributeFormMode as string.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
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 isEditable() const
Returns whether joined fields may be edited through the form of the target layer. ...
virtual bool isGroupBox() const
Returns if this container is going to be rendered as a group box.
bool showLinkButton() const
Determines if the "link feature" button should be shown.
bool hasUpsertOnEdit() const
Returns whether a feature created on the target layer has to impact the joined layer by creating a ne...
bool nextFeature(QgsFeature &f)
Form values are used for searching/filtering the layer.
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...
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).
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
QString name() const
Returns the name of this element.
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
bool isDynamicFormEnabled() const
Returns whether the form has to be dynamically updated with joined fields when a feature is being cre...
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1)
static bool fieldIsEditable(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature)
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else...
QgsDefaultValue defaultValueDefinition
QStringList * joinFieldNamesSubset() const
Returns the subset of fields to be used from joined layer.
A form was embedded as a widget on another form.
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.