48 #include <QTextStream> 51 #include <QFormLayout> 52 #include <QGridLayout> 56 #include <QPushButton> 58 #include <QMessageBox> 59 #include <QToolButton> 62 int QgsAttributeForm::sFormCounter = 0;
67 , mOwnsMessageBar( true )
69 , mFormNr( sFormCounter++ )
71 , mPreventFeatureRefresh( false )
72 , mIsSettingMultiEditFeatures( false )
73 , mUnsavedMultiEditChanges( false )
74 , mEditCommandMessage( tr(
"Attributes changed" ) )
87 updateContainersVisibility();
93 qDeleteAll( mInterfaces );
120 mInterfaces.append( iface );
136 if ( mUnsavedMultiEditChanges )
139 int res = QMessageBox::question(
this, tr(
"Multiedit Attributes" ),
140 tr(
"Apply changes to edited features?" ), QMessageBox::Yes | QMessageBox::No );
141 if ( res == QMessageBox::Yes )
146 clearMultiEditMessages();
148 mUnsavedMultiEditChanges =
false;
196 w->setContext( newContext );
202 w->setVisible( relationWidgetsVisible );
209 mSearchButtonBox->setVisible(
false );
213 synchronizeEnabledState();
214 mSearchButtonBox->setVisible(
false );
218 resetMultiEdit(
false );
219 synchronizeEnabledState();
220 mSearchButtonBox->setVisible(
false );
224 mSearchButtonBox->setVisible(
true );
229 mSearchButtonBox->setVisible(
false );
235 mSearchButtonBox->setVisible(
false );
244 const auto constMWidgets = mWidgets;
259 QVariant mainValue = eww->
value();
261 additionalFieldValues[index] = value;
262 eww->
setValues( mainValue, additionalFieldValues );
271 mIsSettingFeature =
true;
282 synchronizeEnabledState();
286 mIsSettingFeature =
false;
287 const auto constMInterfaces = mInterfaces;
290 iface->featureChanged();
306 mIsSettingFeature =
false;
309 bool QgsAttributeForm::saveEdits()
312 bool changedLayer =
false;
317 bool doUpdate =
false;
338 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
339 QVariantList srcVars = QVariantList() << eww->
value();
340 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
344 for (
const QString &fieldName : additionalFields )
348 dstVars << dst.at( idx );
352 Q_ASSERT( dstVars.count() == srcVars.count() );
354 for (
int i = 0; i < dstVars.count(); i++ )
357 if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() && fieldIsEditable( fieldIndexes[i] ) )
359 dst[fieldIndexes[i]] = srcVars[i];
369 const auto constMInterfaces = mInterfaces;
372 if ( !iface->acceptChanges( updatedFeature ) )
384 bool res = mLayer->
addFeature( updatedFeature );
403 for (
int i = 0; i < dst.count(); ++i )
406 || !dst.at( i ).isValid()
407 || !fieldIsEditable( i ) )
412 QgsDebugMsg( QStringLiteral(
"Updating field %1" ).arg( i ) );
413 QgsDebugMsg( QStringLiteral(
"dst:'%1' (type:%2, isNull:%3, isValid:%4)" )
414 .arg( dst.at( i ).toString(), dst.at( i ).typeName() ).arg( dst.at( i ).isNull() ).arg( dst.at( i ).isValid() ) );
415 QgsDebugMsg( QStringLiteral(
"src:'%1' (type:%2, isNull:%3, isValid:%4)" )
416 .arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( src.at( i ).isNull() ).arg( src.at( i ).isValid() ) );
418 newValues[i] = dst.at( i );
419 oldValues[i] = src.at( i );
426 if ( success && n > 0 )
453 bool QgsAttributeForm::updateDefaultValues(
const int originIdx )
457 updateDefaultValueDependencies();
459 if ( !mDefaultValueDependencies.contains( originIdx ) )
472 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
473 QVariantList srcVars = QVariantList() << eww->
value();
474 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
478 for (
const QString &fieldName : additionalFields )
482 dstVars << dst.at( idx );
486 Q_ASSERT( dstVars.count() == srcVars.count() );
488 for (
int i = 0; i < dstVars.count(); i++ )
491 if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() && fieldIsEditable( fieldIndexes[i] ) )
493 dst[fieldIndexes[i]] = srcVars[i];
501 QList<QgsWidgetWrapper *> relevantWidgets = mDefaultValueDependencies.values( originIdx );
514 if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
525 void QgsAttributeForm::resetMultiEdit(
bool promptToSave )
530 mUnsavedMultiEditChanges =
false;
534 void QgsAttributeForm::multiEditMessageClicked(
const QString &link )
536 clearMultiEditMessages();
537 resetMultiEdit( link == QLatin1String(
"#apply" ) );
540 void QgsAttributeForm::filterTriggered()
542 QString filter = createFilterExpression();
548 void QgsAttributeForm::searchZoomTo()
550 QString filter = createFilterExpression();
551 if ( filter.isEmpty() )
557 void QgsAttributeForm::searchFlash()
559 QString filter = createFilterExpression();
560 if ( filter.isEmpty() )
566 void QgsAttributeForm::filterAndTriggered()
568 QString filter = createFilterExpression();
569 if ( filter.isEmpty() )
577 void QgsAttributeForm::filterOrTriggered()
579 QString filter = createFilterExpression();
580 if ( filter.isEmpty() )
588 void QgsAttributeForm::pushSelectedFeaturesMessage()
594 tr(
"%n matching feature(s) selected",
"matching features", count ),
601 tr(
"No matching features found" ),
617 QString filter = createFilterExpression();
618 if ( filter.isEmpty() )
622 pushSelectedFeaturesMessage();
627 void QgsAttributeForm::searchSetSelection()
632 void QgsAttributeForm::searchAddToSelection()
637 void QgsAttributeForm::searchRemoveFromSelection()
642 void QgsAttributeForm::searchIntersectSelection()
647 bool QgsAttributeForm::saveMultiEdits()
651 QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
652 for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
659 || !fieldIsEditable( wIt.key() ) )
667 newAttributeValues.insert( wIt.key(), w->
currentValue() );
670 if ( newAttributeValues.isEmpty() )
678 int res = QMessageBox::information(
this, tr(
"Multiedit Attributes" ),
679 tr(
"Edits will be applied to all selected features." ), QMessageBox::Ok | QMessageBox::Cancel );
680 if ( res != QMessageBox::Ok )
691 const auto constMMultiEditFeatureIds = mMultiEditFeatureIds;
694 QgsAttributeMap::const_iterator aIt = newAttributeValues.constBegin();
695 for ( ; aIt != newAttributeValues.constEnd(); ++aIt )
701 clearMultiEditMessages();
714 if ( !mButtonBox->isVisible() )
715 mMessageBar->
pushItem( mMultiEditMessageBarItem );
726 wrapper->notifyAboutToSave();
764 success = saveEdits();
768 success = saveMultiEdits();
773 mUnsavedMultiEditChanges =
false;
781 mValuesInitialized =
false;
782 const auto constMWidgets = mWidgets;
785 ww->setFeature( mFeature );
787 mValuesInitialized =
true;
793 const auto widgets { findChildren< QgsAttributeFormEditorWidget * >() };
800 void QgsAttributeForm::clearMultiEditMessages()
802 if ( mMultiEditUnsavedMessageBarItem )
804 if ( !mButtonBox->isVisible() )
805 mMessageBar->
popWidget( mMultiEditUnsavedMessageBarItem );
806 mMultiEditUnsavedMessageBarItem =
nullptr;
808 if ( mMultiEditMessageBarItem )
810 if ( !mButtonBox->isVisible() )
811 mMessageBar->
popWidget( mMultiEditMessageBarItem );
812 mMultiEditMessageBarItem =
nullptr;
816 QString QgsAttributeForm::createFilterExpression()
const 821 QString filter = w->currentFilterExpression();
822 if ( !filter.isEmpty() )
826 if ( filters.isEmpty() )
829 QString filter = filters.join( QStringLiteral(
") AND (" ) ).prepend(
'(' ).append(
')' );
834 void QgsAttributeForm::onAttributeChanged(
const QVariant &value,
const QVariantList &additionalFieldValues )
839 bool signalEmitted =
false;
841 if ( mValuesInitialized )
857 for (
int i = 0; i < additionalFields.count(); i++ )
859 const QString fieldName = additionalFields.at( i );
860 const QVariant value = additionalFieldValues.at( i );
864 signalEmitted =
true;
866 updateJoinedFields( *eww );
872 if ( !mIsSettingMultiEditFeatures )
874 mUnsavedMultiEditChanges =
true;
876 QLabel *msgLabel =
new QLabel( tr(
"Unsaved multiedit changes: <a href=\"#apply\">apply changes</a> or <a href=\"#reset\">reset changes</a>." ), mMessageBar );
877 msgLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
878 msgLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
879 connect( msgLabel, &QLabel::linkActivated,
this, &QgsAttributeForm::multiEditMessageClicked );
880 clearMultiEditMessages();
883 if ( !mButtonBox->isVisible() )
884 mMessageBar->
pushItem( mMultiEditUnsavedMessageBarItem );
894 updateConstraints( eww );
897 mAlreadyUpdatedFields.append( eww->
fieldIdx() );
898 updateDefaultValues( eww->
fieldIdx() );
899 mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
901 if ( !signalEmitted )
910 void QgsAttributeForm::updateAllConstraints()
912 const auto constMWidgets = mWidgets;
917 updateConstraints( eww );
925 if ( currentFormFeature( ft ) )
937 updateConstraint( ft, eww );
940 const QList<QgsEditorWidgetWrapper *> deps = constraintDependencies( eww );
943 updateConstraint( ft, depsEww );
946 synchronizeEnabledState();
953 const QVector<ContainerInformation *> infos = mContainerInformationDependency.value( eww->
field().
name() );
954 for ( ContainerInformation *info : infos )
956 info->apply( &mExpressionContext );
961 void QgsAttributeForm::updateContainersVisibility()
965 const QVector<ContainerInformation *> infos = mContainerVisibilityInformation;
967 for ( ContainerInformation *info : infos )
969 info->apply( &mExpressionContext );
973 updateAllConstraints();
987 if ( mJoinedFeatures.contains( info ) )
1017 if ( dst.count() > eww->
fieldIdx() )
1019 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
1020 QVariantList srcVars = QVariantList() << eww->
value();
1021 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
1025 for (
const QString &fieldName : additionalFields )
1028 fieldIndexes << idx;
1029 dstVars << dst.at( idx );
1033 Q_ASSERT( dstVars.count() == srcVars.count() );
1035 for (
int i = 0; i < dstVars.count(); i++ )
1039 if ( ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) || dstVars[i].isNull() != srcVars[i].isNull() ) && srcVars[i].isValid() )
1041 dst[fieldIndexes[i]] = srcVars[i];
1058 void QgsAttributeForm::registerContainerInformation( QgsAttributeForm::ContainerInformation *info )
1060 mContainerVisibilityInformation.append( info );
1062 const QSet<QString> referencedColumns = info->expression.referencedColumns();
1064 for (
const QString &col : referencedColumns )
1066 mContainerInformationDependency[ col ].append( info );
1070 bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions )
1094 void QgsAttributeForm::onAttributeAdded(
int idx )
1096 mPreventFeatureRefresh =
false;
1100 attrs.insert( idx, QVariant(
layer()->fields().at( idx ).type() ) );
1108 void QgsAttributeForm::onAttributeDeleted(
int idx )
1110 mPreventFeatureRefresh =
false;
1114 attrs.remove( idx );
1122 void QgsAttributeForm::onUpdatedFields()
1124 mPreventFeatureRefresh =
false;
1136 attrs[i].convert(
layer()->fields().at( i ).type() );
1141 attrs[i] = QVariant(
layer()->fields().at( i ).type() );
1151 void QgsAttributeForm::onConstraintStatusChanged(
const QString &constraint,
1159 if ( formEditorWidget )
1165 QList<QgsEditorWidgetWrapper *> wDeps;
1177 if ( name != ewwName )
1184 for (
const QString &colName : referencedColumns )
1186 if ( name == colName )
1188 wDeps.append( eww );
1209 void QgsAttributeForm::preventFeatureRefresh()
1211 mPreventFeatureRefresh =
true;
1228 void QgsAttributeForm::synchronizeEnabledState()
1230 bool isEditable = ( mFeature.
isValid()
1246 bool enabled = isEditable && fieldIsEditable( eww->
fieldIdx() );
1247 ww->setEnabled( enabled );
1255 QStringList invalidFields, descriptions;
1256 bool validConstraint = currentFormValidConstraints( invalidFields, descriptions );
1258 isEditable = isEditable & validConstraint;
1262 QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
1264 okButton->setEnabled( isEditable );
1267 void QgsAttributeForm::init()
1269 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1272 QWidget *formWidget =
nullptr;
1274 bool buttonBoxVisible =
true;
1278 buttonBoxVisible = mButtonBox->isVisible();
1280 mButtonBox =
nullptr;
1283 if ( mSearchButtonBox )
1285 delete mSearchButtonBox;
1286 mSearchButtonBox =
nullptr;
1289 qDeleteAll( mWidgets );
1292 while ( QWidget *w = this->findChild<QWidget *>() )
1298 QVBoxLayout *vl =
new QVBoxLayout();
1300 vl->setContentsMargins( 0, 0, 0, 0 );
1302 mMessageBar->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
1303 vl->addWidget( mMessageBar );
1308 QGridLayout *layout =
new QGridLayout();
1309 QWidget *container =
new QWidget();
1310 container->setLayout( layout );
1311 vl->addWidget( container );
1313 mFormEditorWidgets.clear();
1314 mFormWidgets.clear();
1317 setContentsMargins( 0, 0, 0, 0 );
1326 if ( file && file->open( QFile::ReadOnly ) )
1330 QFileInfo fi( file->fileName() );
1331 loader.setWorkingDirectory( fi.dir() );
1332 formWidget = loader.load( file,
this );
1335 formWidget->setWindowFlags( Qt::Widget );
1336 layout->addWidget( formWidget );
1339 mButtonBox = findChild<QDialogButtonBox *>();
1342 formWidget->installEventFilter(
this );
1354 int columnCount = 1;
1363 if ( !containerDef )
1368 tabWidget =
nullptr;
1369 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
1370 layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
1373 registerContainerInformation(
new ContainerInformation( widgetInfo.widget, containerDef->
visibilityExpression().
data() ) );
1382 layout->addWidget( tabWidget, row, column, 1, 2 );
1386 QWidget *tabPage =
new QWidget( tabWidget );
1388 tabWidget->addTab( tabPage, widgDef->name() );
1392 registerContainerInformation(
new ContainerInformation( tabWidget, tabPage, containerDef->
visibilityExpression().
data() ) );
1394 QGridLayout *tabPageLayout =
new QGridLayout();
1395 tabPage->setLayout( tabPageLayout );
1397 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, tabPage, mLayer, mContext );
1398 tabPageLayout->addWidget( widgetInfo.widget );
1403 tabWidget =
nullptr;
1404 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
1405 QLabel *label =
new QLabel( widgetInfo.labelText );
1406 label->setToolTip( widgetInfo.toolTip );
1407 if ( columnCount > 1 && !widgetInfo.labelOnTop )
1409 label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
1412 label->setBuddy( widgetInfo.widget );
1414 if ( !widgetInfo.showLabel )
1416 QVBoxLayout *
c =
new QVBoxLayout();
1417 label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1418 c->addWidget( widgetInfo.widget );
1419 layout->addLayout( c, row, column, 1, 2 );
1422 else if ( widgetInfo.labelOnTop )
1424 QVBoxLayout *
c =
new QVBoxLayout();
1425 label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1426 c->addWidget( label );
1427 c->addWidget( widgetInfo.widget );
1428 layout->addLayout( c, row, column, 1, 2 );
1433 layout->addWidget( label, row, column++ );
1434 layout->addWidget( widgetInfo.widget, row, column++ );
1438 if ( column >= columnCount * 2 )
1444 formWidget = container;
1453 formWidget =
new QWidget(
this );
1454 QGridLayout *gridLayout =
new QGridLayout( formWidget );
1455 formWidget->setLayout( gridLayout );
1461 scrollArea->setWidget( formWidget );
1462 scrollArea->setWidgetResizable(
true );
1463 scrollArea->setFrameShape( QFrame::NoFrame );
1464 scrollArea->setFrameShadow( QFrame::Plain );
1465 scrollArea->setFocusProxy(
this );
1466 layout->addWidget( scrollArea );
1470 layout->addWidget( formWidget );
1477 for (
const QgsField &field : fields )
1485 QString labelText = fieldName;
1486 labelText.replace(
'&', QStringLiteral(
"&&" ) );
1490 if ( widgetSetup.
type() == QLatin1String(
"Hidden" ) )
1496 QLabel *l =
new QLabel( labelText );
1497 l->setToolTip( QStringLiteral(
"<b>%1</b><p>%2</p>" ).arg( fieldName, field.comment() ) );
1498 QSvgWidget *i =
new QSvgWidget();
1499 i->setFixedSize( 18, 18 );
1503 QWidget *w =
nullptr;
1508 mFormEditorWidgets.insert( idx, formWidget );
1509 mFormWidgets.append( formWidget );
1512 l->setBuddy( eww->
widget() );
1516 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() ) ) );
1521 w->setObjectName( field.name() );
1525 addWidgetWrapper( eww );
1526 mIconMap[eww->
widget()] = i;
1531 gridLayout->addWidget( l, row++, 0, 1, 2 );
1532 gridLayout->addWidget( w, row++, 0, 1, 2 );
1533 gridLayout->addWidget( i, row++, 0, 1, 2 );
1537 gridLayout->addWidget( l, row, 0 );
1538 gridLayout->addWidget( w, row, 1 );
1539 gridLayout->addWidget( i, row++, 2 );
1550 gridLayout->addWidget( formWidget, row++, 0, 1, 2 );
1552 mWidgets.append( rww );
1553 mFormWidgets.append( formWidget );
1558 QSpacerItem *spacerItem =
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
1559 gridLayout->addItem( spacerItem, row, 0 );
1560 gridLayout->setRowStretch( row, 1 );
1565 updateDefaultValueDependencies();
1569 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1570 mButtonBox->setObjectName( QStringLiteral(
"buttonBox" ) );
1571 layout->addWidget( mButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
1573 mButtonBox->setVisible( buttonBoxVisible );
1575 if ( !mSearchButtonBox )
1577 mSearchButtonBox =
new QWidget();
1578 QHBoxLayout *boxLayout =
new QHBoxLayout();
1579 boxLayout->setMargin( 0 );
1580 boxLayout->setContentsMargins( 0, 0, 0, 0 );
1581 mSearchButtonBox->setLayout( boxLayout );
1582 mSearchButtonBox->setObjectName( QStringLiteral(
"searchButtonBox" ) );
1584 QPushButton *clearButton =
new QPushButton( tr(
"&Reset Form" ), mSearchButtonBox );
1586 boxLayout->addWidget( clearButton );
1587 boxLayout->addStretch( 1 );
1589 QPushButton *flashButton =
new QPushButton();
1590 flashButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1591 flashButton->setText( tr(
"&Flash Features" ) );
1592 connect( flashButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchFlash );
1593 boxLayout->addWidget( flashButton );
1595 QPushButton *zoomButton =
new QPushButton();
1596 zoomButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1597 zoomButton->setText( tr(
"&Zoom to Features" ) );
1598 connect( zoomButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchZoomTo );
1599 boxLayout->addWidget( zoomButton );
1601 QToolButton *selectButton =
new QToolButton();
1602 selectButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1603 selectButton->setText( tr(
"&Select Features" ) );
1605 selectButton->setPopupMode( QToolButton::MenuButtonPopup );
1606 selectButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
1607 connect( selectButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchSetSelection );
1608 QMenu *selectMenu =
new QMenu( selectButton );
1609 QAction *selectAction =
new QAction( tr(
"Select Features" ), selectMenu );
1611 connect( selectAction, &QAction::triggered,
this, &QgsAttributeForm::searchSetSelection );
1612 selectMenu->addAction( selectAction );
1613 QAction *addSelectAction =
new QAction( tr(
"Add to Current Selection" ), selectMenu );
1615 connect( addSelectAction, &QAction::triggered,
this, &QgsAttributeForm::searchAddToSelection );
1616 selectMenu->addAction( addSelectAction );
1617 QAction *deselectAction =
new QAction( tr(
"Remove from Current Selection" ), selectMenu );
1619 connect( deselectAction, &QAction::triggered,
this, &QgsAttributeForm::searchRemoveFromSelection );
1620 selectMenu->addAction( deselectAction );
1621 QAction *filterSelectAction =
new QAction( tr(
"Filter Current Selection" ), selectMenu );
1623 connect( filterSelectAction, &QAction::triggered,
this, &QgsAttributeForm::searchIntersectSelection );
1624 selectMenu->addAction( filterSelectAction );
1625 selectButton->setMenu( selectMenu );
1626 boxLayout->addWidget( selectButton );
1630 QToolButton *filterButton =
new QToolButton();
1631 filterButton->setText( tr(
"Filter Features" ) );
1632 filterButton->setPopupMode( QToolButton::MenuButtonPopup );
1633 filterButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1634 connect( filterButton, &QToolButton::clicked,
this, &QgsAttributeForm::filterTriggered );
1635 QMenu *filterMenu =
new QMenu( filterButton );
1636 QAction *filterAndAction =
new QAction( tr(
"Filter Within (\"AND\")" ), filterMenu );
1637 connect( filterAndAction, &QAction::triggered,
this, &QgsAttributeForm::filterAndTriggered );
1638 filterMenu->addAction( filterAndAction );
1639 QAction *filterOrAction =
new QAction( tr(
"Extend Filter (\"OR\")" ), filterMenu );
1640 connect( filterOrAction, &QAction::triggered,
this, &QgsAttributeForm::filterOrTriggered );
1641 filterMenu->addAction( filterOrAction );
1642 filterButton->setMenu( filterMenu );
1643 boxLayout->addWidget( filterButton );
1647 QPushButton *closeButton =
new QPushButton( tr(
"Close" ), mSearchButtonBox );
1649 closeButton->setShortcut( Qt::Key_Escape );
1650 boxLayout->addWidget( closeButton );
1653 layout->addWidget( mSearchButtonBox );
1671 const auto constMInterfaces = mInterfaces;
1682 QApplication::restoreOverrideCursor();
1685 void QgsAttributeForm::cleanPython()
1687 if ( !mPyFormVarName.isNull() )
1689 QString expr = QStringLiteral(
"if '%1' in locals(): del %1\n" ).arg( mPyFormVarName );
1694 void QgsAttributeForm::initPython()
1711 if ( !initFilePath.isEmpty() )
1715 if ( inputFile && inputFile->open( QFile::ReadOnly ) )
1718 QTextStream inf( inputFile );
1719 initCode = inf.readAll();
1724 QgsLogger::warning( QStringLiteral(
"The external python file path %1 could not be opened!" ).arg( initFilePath ) );
1735 if ( initCode.isEmpty() )
1737 QgsLogger::warning( QStringLiteral(
"The python code provided in the dialog is empty!" ) );
1748 if ( !initCode.isEmpty() )
1754 tr(
"Python macro could not be run due to missing permissions." ),
1755 Qgis::MessageLevel::Warning,
1763 if (
QgsPythonRunner::eval( QStringLiteral(
"len(inspect.getfullargspec(%1)[0])" ).arg( initFunction ), numArgs ) )
1765 static int sFormId = 0;
1766 mPyFormVarName = QStringLiteral(
"_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
1768 QString form = QStringLiteral(
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
1769 .arg( mPyFormVarName )
1770 .arg( ( quint64 )
this );
1774 QgsDebugMsg( QStringLiteral(
"running featureForm init: %1" ).arg( mPyFormVarName ) );
1777 if ( numArgs == QLatin1String(
"3" ) )
1785 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 ) );
1788 QString expr = QString(
"%1(%2)" )
1789 .arg( mLayer->editFormInit() )
1790 .arg( mPyFormVarName );
1791 QgsAttributeFormInterface *iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface *>( expr,
"QgsAttributeFormInterface" );
1801 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 ) );
1809 WidgetInfo newWidgetInfo;
1811 switch ( widgetDef->
type() )
1821 if ( fldIdx < fields.
count() && fldIdx >= 0 )
1827 mFormEditorWidgets.insert( fldIdx, formWidget );
1828 mFormWidgets.append( formWidget );
1832 newWidgetInfo.widget = formWidget;
1833 addWidgetWrapper( eww );
1835 newWidgetInfo.widget->setObjectName( fields.
at( fldIdx ).
name() );
1836 newWidgetInfo.hint = fields.
at( fldIdx ).
comment();
1841 newWidgetInfo.labelText.replace(
'&', QStringLiteral(
"&&" ) );
1842 newWidgetInfo.toolTip = QStringLiteral(
"<b>%1</b><p>%2</p>" ).arg( mLayer->
attributeDisplayName( fldIdx ), newWidgetInfo.hint );
1843 newWidgetInfo.showLabel = widgetDef->
showLabel();
1861 mWidgets.append( rww );
1862 mFormWidgets.append( formWidget );
1864 newWidgetInfo.widget = formWidget;
1865 newWidgetInfo.labelText = QString();
1866 newWidgetInfo.labelOnTop =
true;
1878 if ( columnCount <= 0 )
1882 QWidget *myContainer =
nullptr;
1885 QGroupBox *groupBox =
new QGroupBox( parent );
1886 widgetName = QStringLiteral(
"QGroupBox" );
1888 groupBox->setTitle( container->
name() );
1889 myContainer = groupBox;
1890 newWidgetInfo.widget = myContainer;
1894 myContainer =
new QWidget();
1900 scrollArea->setWidget( myContainer );
1901 scrollArea->setWidgetResizable(
true );
1902 scrollArea->setFrameShape( QFrame::NoFrame );
1903 widgetName = QStringLiteral(
"QScrollArea QWidget" );
1905 newWidgetInfo.widget = scrollArea;
1909 newWidgetInfo.widget = myContainer;
1910 widgetName = QStringLiteral(
"QWidget" );
1916 QString style {QStringLiteral(
"background-color: %1;" ).arg( container->
backgroundColor().name() )};
1917 newWidgetInfo.widget->setStyleSheet( style );
1920 QGridLayout *gbLayout =
new QGridLayout();
1921 myContainer->setLayout( gbLayout );
1926 const QList<QgsAttributeEditorElement *> children = container->
children();
1930 WidgetInfo widgetInfo = createWidgetFromDef( childDef, myContainer, vl, context );
1937 registerContainerInformation(
new ContainerInformation( widgetInfo.widget, containerDef->
visibilityExpression().
data() ) );
1941 if ( widgetInfo.labelText.isNull() )
1943 gbLayout->addWidget( widgetInfo.widget, row, column, 1, 2 );
1948 QLabel *mypLabel =
new QLabel( widgetInfo.labelText );
1949 mypLabel->setToolTip( widgetInfo.toolTip );
1950 if ( columnCount > 1 && !widgetInfo.labelOnTop )
1952 mypLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
1955 mypLabel->setBuddy( widgetInfo.widget );
1957 if ( widgetInfo.labelOnTop )
1959 QVBoxLayout *
c =
new QVBoxLayout();
1960 mypLabel->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1961 c->layout()->addWidget( mypLabel );
1962 c->layout()->addWidget( widgetInfo.widget );
1963 gbLayout->addLayout( c, row, column, 1, 2 );
1968 gbLayout->addWidget( mypLabel, row, column++ );
1969 gbLayout->addWidget( widgetInfo.widget, row, column++ );
1973 if ( column >= columnCount * 2 )
1979 QWidget *spacer =
new QWidget();
1980 spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
1981 gbLayout->addWidget( spacer, ++row, 0 );
1982 gbLayout->setRowStretch( row, 1 );
1984 newWidgetInfo.labelText = QString();
1985 newWidgetInfo.labelOnTop =
true;
1999 mWidgets.append( qmlWrapper );
2001 newWidgetInfo.widget = qmlWrapper->
widget();
2002 newWidgetInfo.labelText = elementDef->
name();
2003 newWidgetInfo.labelOnTop =
true;
2004 newWidgetInfo.showLabel = widgetDef->
showLabel();
2018 mWidgets.append( htmlWrapper );
2020 newWidgetInfo.widget = htmlWrapper->
widget();
2021 newWidgetInfo.labelText = elementDef->
name();
2022 newWidgetInfo.labelOnTop =
true;
2023 newWidgetInfo.showLabel = widgetDef->
showLabel();
2028 QgsDebugMsg( QStringLiteral(
"Unknown attribute editor widget type encountered..." ) );
2032 newWidgetInfo.showLabel = widgetDef->
showLabel();
2034 return newWidgetInfo;
2055 mWidgets.append( eww );
2058 void QgsAttributeForm::createWrappers()
2060 QList<QWidget *> myWidgets = findChildren<QWidget *>();
2061 const QList<QgsField> fields = mLayer->
fields().
toList();
2063 const auto constMyWidgets = myWidgets;
2064 for ( QWidget *myWidget : constMyWidgets )
2067 QVariant vRel = myWidget->property(
"qgisRelation" );
2068 if ( vRel.isValid() )
2078 mWidgets.append( rww );
2083 const auto constFields = fields;
2084 for (
const QgsField &field : constFields )
2086 if ( field.name() == myWidget->objectName() )
2091 addWidgetWrapper( eww );
2098 void QgsAttributeForm::afterWidgetInit()
2100 bool isFirstEww =
true;
2102 const auto constMWidgets = mWidgets;
2111 setFocusProxy( eww->
widget() );
2126 if ( e->type() == QEvent::KeyPress )
2128 QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( e );
2129 if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
2141 QSet< int > &mixedValueFields,
2142 QHash< int, QVariant > &fieldSharedValues )
const 2144 mixedValueFields.clear();
2145 fieldSharedValues.clear();
2151 for (
int i = 0; i < mLayer->
fields().
count(); ++i )
2153 if ( mixedValueFields.contains( i ) )
2158 fieldSharedValues[i] = f.
attribute( i );
2162 if ( fieldSharedValues.value( i ) != f.
attribute( i ) )
2164 fieldSharedValues.remove( i );
2165 mixedValueFields.insert( i );
2171 if ( mixedValueFields.count() == mLayer->
fields().
count() )
2180 void QgsAttributeForm::layerSelectionChanged()
2192 resetMultiEdit(
true );
2199 mIsSettingMultiEditFeatures =
true;
2200 mMultiEditFeatureIds = fids;
2202 if ( fids.isEmpty() )
2205 QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
2206 for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
2208 wIt.value()->initialize( QVariant() );
2210 mIsSettingMultiEditFeatures =
false;
2217 QSet< int > mixedValueFields;
2218 QHash< int, QVariant > fieldSharedValues;
2219 scanForEqualAttributes( fit, mixedValueFields, fieldSharedValues );
2226 const auto constMixedValueFields = mixedValueFields;
2227 for (
int fieldIndex : qgis::as_const( mixedValueFields ) )
2231 const QStringList additionalFields = w->editorWidget()->
additionalFields();
2232 QVariantList additionalFieldValues;
2233 for (
const QString &additionalField : additionalFields )
2234 additionalFieldValues << firstFeature.
attribute( additionalField );
2235 w->initialize( firstFeature.
attribute( fieldIndex ),
true, additionalFieldValues );
2238 QHash< int, QVariant >::const_iterator sharedValueIt = fieldSharedValues.constBegin();
2239 for ( ; sharedValueIt != fieldSharedValues.constEnd(); ++sharedValueIt )
2244 const QStringList additionalFields = w->editorWidget()->
additionalFields();
2245 for (
const QString &additionalField : additionalFields )
2248 if ( constMixedValueFields.contains( index ) )
2255 QVariantList additionalFieldValues;
2258 for (
const QString &additionalField : additionalFields )
2259 additionalFieldValues << firstFeature.
attribute( additionalField );
2260 w->initialize( firstFeature.
attribute( sharedValueIt.key() ),
true, additionalFieldValues );
2264 for (
const QString &additionalField : additionalFields )
2267 Q_ASSERT( fieldSharedValues.contains( index ) );
2268 additionalFieldValues << fieldSharedValues.value( index );
2270 w->initialize( sharedValueIt.value(),
false, additionalFieldValues );
2274 mIsSettingMultiEditFeatures =
false;
2279 if ( mOwnsMessageBar )
2281 mOwnsMessageBar =
false;
2282 mMessageBar = messageBar;
2292 QStringList filters;
2295 QString filter = widget->currentFilterExpression();
2296 if ( !filter.isNull() )
2297 filters <<
'(' + filter +
')';
2300 return filters.join( QStringLiteral(
" AND " ) );
2303 int QgsAttributeForm::messageTimeout()
2306 return settings.
value( QStringLiteral(
"qgis/messageTimeout" ), 5 ).toInt();
2311 bool newVisibility = expression.evaluate( expressionContext ).toBool();
2313 if ( newVisibility != isVisible )
2317 tabWidget->setTabVisible( widget, newVisibility );
2321 widget->setVisible( newVisibility );
2324 isVisible = newVisibility;
2337 if ( infos.count() == 0 || !currentFormFeature( formFeature ) )
2340 const QString hint = tr(
"No feature joined" );
2341 const auto constInfos = infos;
2344 if ( !info->isDynamicFormEnabled() )
2349 mJoinedFeatures[info] = joinFeature;
2351 if ( info->hasSubset() )
2355 const auto constSubsetNames = subsetNames;
2356 for (
const QString &field : constSubsetNames )
2358 QString prefixedName = info->prefixedFieldName( field );
2360 QString hintText = hint;
2374 for (
const QgsField &field : joinFields )
2376 QString prefixedName = info->prefixedFieldName( field );
2378 QString hintText = hint;
2392 bool QgsAttributeForm::fieldIsEditable(
int fieldIndex )
const 2397 void QgsAttributeForm::updateDefaultValueDependencies()
2399 mDefaultValueDependencies.clear();
2408 for (
const QString &referencedColumn : referencedColumns )
2414 for (
const int id : allAttributeIds )
2416 mDefaultValueDependencies.insertMulti(
id, eww );
2421 mDefaultValueDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
2434 mIconMap[eww->
widget()]->hide();
2448 const QString file = QStringLiteral(
"/mIconJoinNotEditable.svg" );
2449 const QString tooltip = tr(
"Join settings do not allow editing" );
2450 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2454 const QString file = QStringLiteral(
"mIconJoinHasNotUpsertOnEdit.svg" );
2455 const QString tooltip = tr(
"Join settings do not allow upsert on edit" );
2456 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2460 const QString file = QStringLiteral(
"/mIconJoinedLayerNotEditable.svg" );
2461 const QString tooltip = tr(
"Joined layer is not toggled editable" );
2462 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2468 void QgsAttributeForm::reloadIcon(
const QString &file,
const QString &tooltip, QSvgWidget *sw )
2471 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.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
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.
Q_INVOKABLE 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.
Encapsulate a field in an attribute table or data source.
bool isInvalidJSON()
Returns whether the text edit widget contains Invalid JSON.
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.
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.
Q_INVOKABLE void selectByExpression(const QString &expression, QgsVectorLayer::SelectBehavior behavior=QgsVectorLayer::SetSelection)
Selects matching features using an expression.
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.