57 #include <QTextStream>
60 #include <QFormLayout>
61 #include <QGridLayout>
65 #include <QPushButton>
67 #include <QMessageBox>
68 #include <QToolButton>
72 int QgsAttributeForm::sFormCounter = 0;
77 , mOwnsMessageBar( true )
79 , mFormNr( sFormCounter++ )
81 , mPreventFeatureRefresh( false )
82 , mIsSettingMultiEditFeatures( false )
83 , mUnsavedMultiEditChanges( false )
84 , mEditCommandMessage( tr(
"Attributes changed" ) )
97 updateContainersVisibility();
105 qDeleteAll( mInterfaces );
132 mInterfaces.append( iface );
148 if ( mUnsavedMultiEditChanges )
151 int res = QMessageBox::question(
this, tr(
"Multiedit Attributes" ),
152 tr(
"Apply changes to edited features?" ), QMessageBox::Yes | QMessageBox::No );
153 if ( res == QMessageBox::Yes )
158 clearMultiEditMessages();
160 mUnsavedMultiEditChanges =
false;
212 w->setContext( newContext );
218 w->setVisible( relationWidgetsVisible );
225 mSearchButtonBox->setVisible(
false );
230 mSearchButtonBox->setVisible(
false );
235 mSearchButtonBox->setVisible(
false );
239 resetMultiEdit(
false );
241 mSearchButtonBox->setVisible(
false );
245 mSearchButtonBox->setVisible(
true );
251 mSearchButtonBox->setVisible(
false );
259 mSearchButtonBox->setVisible(
false );
268 const auto constMWidgets = mWidgets;
283 QVariant mainValue = eww->
value();
285 additionalFieldValues[index] = value;
286 eww->
setValues( mainValue, additionalFieldValues );
295 mIsSettingFeature =
true;
312 mIsSettingFeature =
false;
313 const auto constMInterfaces = mInterfaces;
316 iface->featureChanged();
332 mIsSettingFeature =
false;
335 bool QgsAttributeForm::saveEdits( QString *error )
338 bool changedLayer =
false;
343 bool doUpdate =
false;
363 *error = tr(
"JSON value for %1 is invalid and has not been saved" ).arg( eww->
field().
name() );
366 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
367 QVariantList srcVars = QVariantList() << eww->
value();
368 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
372 for (
const QString &fieldName : additionalFields )
376 dstVars << dst.at( idx );
380 Q_ASSERT( dstVars.count() == srcVars.count() );
382 for (
int i = 0; i < dstVars.count(); i++ )
385 if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() )
387 dst[fieldIndexes[i]] = srcVars[i];
397 const auto constMInterfaces = mInterfaces;
400 if ( !iface->acceptChanges( updatedFeature ) )
410 mFeature = updatedFeature;
416 bool res = mLayer->
addFeature( updatedFeature );
435 for (
int i = 0; i < dst.count(); ++i )
438 || !dst.at( i ).isValid()
439 || !fieldIsEditable( i ) )
445 QgsDebugMsgLevel( QStringLiteral(
"dst:'%1' (type:%2, isNull:%3, isValid:%4)" )
446 .arg( dst.at( i ).toString(), dst.at( i ).typeName() ).arg( dst.at( i ).isNull() ).arg( dst.at( i ).isValid() ), 2 );
447 QgsDebugMsgLevel( QStringLiteral(
"src:'%1' (type:%2, isNull:%3, isValid:%4)" )
448 .arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( src.at( i ).isNull() ).arg( src.at( i ).isValid() ), 2 );
450 newValues[i] = dst.at( i );
451 oldValues[i] = src.at( i );
458 if ( success && n > 0 )
485 QgsFeature QgsAttributeForm::getUpdatedFeature()
const
497 QVariantList dstVars = QVariantList() << featureAttributes.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 << featureAttributes.at( idx );
511 Q_ASSERT( dstVars.count() == srcVars.count() );
513 for (
int i = 0; i < dstVars.count(); i++ )
515 if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() )
516 featureAttributes[fieldIndexes[i]] = srcVars[i];
521 return updatedFeature;
524 void QgsAttributeForm::updateValuesDependencies(
const int originIdx )
526 updateFieldDependencies();
528 updateValuesDependenciesDefaultValues( originIdx );
529 updateValuesDependenciesVirtualFields( originIdx );
532 void QgsAttributeForm::updateValuesDependenciesDefaultValues(
const int originIdx )
534 if ( !mDefaultValueDependencies.contains( originIdx ) )
542 QgsFeature updatedFeature = getUpdatedFeature();
545 QList<QgsWidgetWrapper *> relevantWidgets = mDefaultValueDependencies.values( originIdx );
558 if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
569 void QgsAttributeForm::updateValuesDependenciesVirtualFields(
const int originIdx )
571 if ( !mVirtualFieldsDependencies.contains( originIdx ) )
578 QgsFeature updatedFeature = getUpdatedFeature();
581 const QList<QgsWidgetWrapper *> relevantWidgets = mVirtualFieldsDependencies.values( originIdx );
589 if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
595 const QVariant value = exp.evaluate( &context );
601 void QgsAttributeForm::updateRelatedLayerFields()
604 updateRelatedLayerFieldsDependencies();
606 if ( mRelatedLayerFieldsDependencies.isEmpty() )
613 QgsFeature updatedFeature = getUpdatedFeature();
616 const QSet<QgsEditorWidgetWrapper *> relevantWidgets = mRelatedLayerFieldsDependencies;
620 if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
626 QVariant value = exp.evaluate( &context );
631 void QgsAttributeForm::resetMultiEdit(
bool promptToSave )
636 mUnsavedMultiEditChanges =
false;
640 void QgsAttributeForm::multiEditMessageClicked(
const QString &link )
642 clearMultiEditMessages();
643 resetMultiEdit( link == QLatin1String(
"#apply" ) );
646 void QgsAttributeForm::filterTriggered()
648 QString filter = createFilterExpression();
654 void QgsAttributeForm::searchZoomTo()
656 QString filter = createFilterExpression();
657 if ( filter.isEmpty() )
663 void QgsAttributeForm::searchFlash()
665 QString filter = createFilterExpression();
666 if ( filter.isEmpty() )
672 void QgsAttributeForm::filterAndTriggered()
674 QString filter = createFilterExpression();
675 if ( filter.isEmpty() )
683 void QgsAttributeForm::filterOrTriggered()
685 QString filter = createFilterExpression();
686 if ( filter.isEmpty() )
694 void QgsAttributeForm::pushSelectedFeaturesMessage()
700 tr(
"%n matching feature(s) selected",
"matching features", count ),
701 Qgis::MessageLevel::Info );
706 tr(
"No matching features found" ),
707 Qgis::MessageLevel::Info );
715 Qgis::MessageLevel::Warning );
720 QString filter = createFilterExpression();
721 if ( filter.isEmpty() )
725 pushSelectedFeaturesMessage();
730 void QgsAttributeForm::searchSetSelection()
735 void QgsAttributeForm::searchAddToSelection()
740 void QgsAttributeForm::searchRemoveFromSelection()
745 void QgsAttributeForm::searchIntersectSelection()
750 bool QgsAttributeForm::saveMultiEdits()
754 QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
755 for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
762 || !fieldIsEditable( wIt.key() ) )
770 newAttributeValues.insert( wIt.key(), w->
currentValue() );
773 if ( newAttributeValues.isEmpty() )
781 int res = QMessageBox::information(
this, tr(
"Multiedit Attributes" ),
782 tr(
"Edits will be applied to all selected features." ), QMessageBox::Ok | QMessageBox::Cancel );
783 if ( res != QMessageBox::Ok )
794 const auto constMultiEditFeatureIds = mMultiEditFeatureIds;
797 QgsAttributeMap::const_iterator aIt = newAttributeValues.constBegin();
798 for ( ; aIt != newAttributeValues.constEnd(); ++aIt )
804 clearMultiEditMessages();
809 mMultiEditMessageBarItem =
new QgsMessageBarItem( tr(
"Attribute changes for multiple features applied." ), Qgis::MessageLevel::Success, -1 );
814 mMultiEditMessageBarItem =
new QgsMessageBarItem( tr(
"Changes could not be applied." ), Qgis::MessageLevel::Warning, 0 );
817 if ( !mButtonBox->isVisible() )
818 mMessageBar->
pushItem( mMultiEditMessageBarItem );
844 wrapper->notifyAboutToSave();
884 success = saveEdits( error );
888 success = saveMultiEdits();
893 mUnsavedMultiEditChanges =
false;
902 mValuesInitialized =
false;
903 const auto constMWidgets = mWidgets;
906 ww->setFeature( mFeature );
908 mValuesInitialized =
true;
914 const auto widgets { findChildren< QgsAttributeFormEditorWidget * >() };
921 void QgsAttributeForm::clearMultiEditMessages()
923 if ( mMultiEditUnsavedMessageBarItem )
925 if ( !mButtonBox->isVisible() )
926 mMessageBar->
popWidget( mMultiEditUnsavedMessageBarItem );
927 mMultiEditUnsavedMessageBarItem =
nullptr;
929 if ( mMultiEditMessageBarItem )
931 if ( !mButtonBox->isVisible() )
932 mMessageBar->
popWidget( mMultiEditMessageBarItem );
933 mMultiEditMessageBarItem =
nullptr;
937 QString QgsAttributeForm::createFilterExpression()
const
943 if ( !filter.isEmpty() )
947 if ( filters.isEmpty() )
950 QString filter = filters.join( QLatin1String(
") AND (" ) ).prepend(
'(' ).append(
')' );
959 if ( mExtraContextScope )
966 void QgsAttributeForm::onAttributeChanged(
const QVariant &value,
const QVariantList &additionalFieldValues )
971 bool signalEmitted =
false;
973 if ( mValuesInitialized )
992 for (
int i = 0; i < additionalFields.count(); i++ )
994 const QString fieldName = additionalFields.at( i );
995 const QVariant value = additionalFieldValues.at( i );
999 signalEmitted =
true;
1001 if ( mValuesInitialized )
1002 updateJoinedFields( *eww );
1008 if ( !mIsSettingMultiEditFeatures )
1010 mUnsavedMultiEditChanges =
true;
1012 QLabel *msgLabel =
new QLabel( tr(
"Unsaved multiedit changes: <a href=\"#apply\">apply changes</a> or <a href=\"#reset\">reset changes</a>." ), mMessageBar );
1013 msgLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
1014 msgLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
1015 connect( msgLabel, &QLabel::linkActivated,
this, &QgsAttributeForm::multiEditMessageClicked );
1016 clearMultiEditMessages();
1018 mMultiEditUnsavedMessageBarItem =
new QgsMessageBarItem( msgLabel, Qgis::MessageLevel::Warning );
1019 if ( !mButtonBox->isVisible() )
1020 mMessageBar->
pushItem( mMultiEditUnsavedMessageBarItem );
1032 updateConstraints( eww );
1035 mAlreadyUpdatedFields.append( eww->
fieldIdx() );
1036 updateValuesDependencies( eww->
fieldIdx() );
1037 mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
1042 if ( !signalEmitted )
1051 void QgsAttributeForm::updateAllConstraints()
1053 const auto constMWidgets = mWidgets;
1058 updateConstraints( eww );
1066 if ( currentFormValuesFeature( ft ) )
1078 updateConstraint( ft, eww );
1081 const QList<QgsEditorWidgetWrapper *> deps = constraintDependencies( eww );
1084 updateConstraint( ft, depsEww );
1092 const QVector<ContainerInformation *> infos = mContainerInformationDependency.value( eww->
field().
name() );
1093 for ( ContainerInformation *info : infos )
1095 info->apply( &context );
1100 void QgsAttributeForm::updateContainersVisibility()
1104 const QVector<ContainerInformation *> infos = mContainerVisibilityInformation;
1106 for ( ContainerInformation *info : infos )
1108 info->apply( &context );
1112 updateAllConstraints();
1118 if ( mContext.
attributeFormMode() != QgsAttributeEditorContext::Mode::MultiEditMode )
1130 if ( mJoinedFeatures.contains( info ) )
1148 void QgsAttributeForm::updateLabels()
1150 if ( ! mLabelDataDefinedProperties.isEmpty() )
1153 if ( currentFormValuesFeature( currentFeature ) )
1157 for (
auto it = mLabelDataDefinedProperties.constBegin() ; it != mLabelDataDefinedProperties.constEnd(); ++it )
1159 QLabel *label { it.key() };
1161 const QString value { it->valueAsString( context, QString(), &ok ) };
1162 if ( ok && ! value.isEmpty() )
1164 label->setText( value );
1171 bool QgsAttributeForm::currentFormValuesFeature(
QgsFeature &feature )
1184 if ( dst.count() > eww->
fieldIdx() )
1186 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
1187 QVariantList srcVars = QVariantList() << eww->
value();
1188 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
1192 for (
const QString &fieldName : additionalFields )
1195 fieldIndexes << idx;
1196 dstVars << dst.at( idx );
1200 Q_ASSERT( dstVars.count() == srcVars.count() );
1202 for (
int i = 0; i < dstVars.count(); i++ )
1206 if ( ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) || dstVars[i].isNull() != srcVars[i].isNull() ) && srcVars[i].isValid() )
1208 dst[fieldIndexes[i]] = srcVars[i];
1225 void QgsAttributeForm::registerContainerInformation( QgsAttributeForm::ContainerInformation *info )
1227 mContainerVisibilityInformation.append( info );
1229 const QSet<QString> referencedColumns = info->expression.referencedColumns();
1231 for (
const QString &col : referencedColumns )
1233 mContainerInformationDependency[ col ].append( info );
1237 bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions )
const
1261 bool QgsAttributeForm::currentFormValidHardConstraints( QStringList &invalidFields, QStringList &descriptions )
const
1282 void QgsAttributeForm::onAttributeAdded(
int idx )
1284 mPreventFeatureRefresh =
false;
1288 attrs.insert( idx, QVariant(
layer()->fields().at( idx ).type() ) );
1296 void QgsAttributeForm::onAttributeDeleted(
int idx )
1298 mPreventFeatureRefresh =
false;
1302 attrs.remove( idx );
1310 void QgsAttributeForm::onRelatedFeaturesChanged()
1312 updateRelatedLayerFields();
1315 void QgsAttributeForm::onUpdatedFields()
1317 mPreventFeatureRefresh =
false;
1334 attrs[i] = QVariant(
layer()->fields().at( i ).type() );
1344 void QgsAttributeForm::onConstraintStatusChanged(
const QString &constraint,
1352 if ( formEditorWidget )
1358 QList<QgsEditorWidgetWrapper *> wDeps;
1370 if ( name != ewwName )
1377 for (
const QString &colName : referencedColumns )
1379 if ( name == colName )
1381 wDeps.append( eww );
1394 return setupRelationWidgetWrapper( QString(), rel, context );
1407 void QgsAttributeForm::preventFeatureRefresh()
1409 mPreventFeatureRefresh =
true;
1440 return mNeedsGeometry;
1443 void QgsAttributeForm::synchronizeState()
1445 bool isEditable = ( mFeature.
isValid()
1462 bool enabled = isEditable && fieldIsEditable( eww->
fieldIdx() );
1463 ww->setEnabled( enabled );
1469 ww->setEnabled( isEditable );
1477 QStringList invalidFields, descriptions;
1478 mValidConstraints = currentFormValidHardConstraints( invalidFields, descriptions );
1482 if ( !mValidConstraints && !mConstraintsFailMessageBarItem )
1484 mConstraintsFailMessageBarItem =
new QgsMessageBarItem( tr(
"Changes to this form will not be saved. %n field(s) don't meet their constraints.",
"invalid fields", invalidFields.size() ), Qgis::MessageLevel::Warning, -1 );
1485 mMessageBar->
pushItem( mConstraintsFailMessageBarItem );
1487 else if ( mValidConstraints && mConstraintsFailMessageBarItem )
1489 mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
1490 mConstraintsFailMessageBarItem =
nullptr;
1493 else if ( mConstraintsFailMessageBarItem )
1495 mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
1496 mConstraintsFailMessageBarItem =
nullptr;
1499 isEditable = isEditable & mValidConstraints;
1503 QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
1505 okButton->setEnabled( isEditable );
1508 void QgsAttributeForm::init()
1510 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1513 QWidget *formWidget =
nullptr;
1514 mNeedsGeometry =
false;
1516 bool buttonBoxVisible =
true;
1520 buttonBoxVisible = mButtonBox->isVisible();
1522 mButtonBox =
nullptr;
1525 if ( mSearchButtonBox )
1527 delete mSearchButtonBox;
1528 mSearchButtonBox =
nullptr;
1531 qDeleteAll( mWidgets );
1534 while ( QWidget *w = this->findChild<QWidget *>() )
1540 QVBoxLayout *vl =
new QVBoxLayout();
1541 vl->setContentsMargins( 0, 0, 0, 0 );
1543 mMessageBar->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
1544 vl->addWidget( mMessageBar );
1549 QGridLayout *layout =
new QGridLayout();
1550 QWidget *container =
new QWidget();
1551 container->setLayout( layout );
1552 vl->addWidget( container );
1554 mFormEditorWidgets.clear();
1555 mFormWidgets.clear();
1558 setContentsMargins( 0, 0, 0, 0 );
1567 if ( file && file->open( QFile::ReadOnly ) )
1571 QFileInfo fi( file->fileName() );
1572 loader.setWorkingDirectory( fi.dir() );
1573 formWidget = loader.load( file,
this );
1576 formWidget->setWindowFlags( Qt::Widget );
1577 layout->addWidget( formWidget );
1580 mButtonBox = findChild<QDialogButtonBox *>();
1583 formWidget->installEventFilter(
this );
1595 int columnCount = 1;
1596 bool hasRootFields =
false;
1597 bool addSpacer =
true;
1606 if ( !containerDef )
1611 tabWidget =
nullptr;
1612 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
1613 layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
1616 registerContainerInformation(
new ContainerInformation( widgetInfo.widget, containerDef->
visibilityExpression().
data() ) );
1625 layout->addWidget( tabWidget, row, column, 1, 2 );
1629 QWidget *tabPage =
new QWidget( tabWidget );
1631 tabWidget->addTab( tabPage, widgDef->name() );
1635 registerContainerInformation(
new ContainerInformation( tabWidget, tabPage, containerDef->
visibilityExpression().
data() ) );
1637 QGridLayout *tabPageLayout =
new QGridLayout();
1638 tabPage->setLayout( tabPageLayout );
1640 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, tabPage, mLayer, mContext );
1641 tabPageLayout->addWidget( widgetInfo.widget );
1646 hasRootFields =
true;
1647 tabWidget =
nullptr;
1648 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
1651 if ( widgetInfo.showLabel )
1652 collapsibleGroupBox->setTitle( widgetInfo.labelText );
1654 QVBoxLayout *collapsibleGroupBoxLayout =
new QVBoxLayout();
1655 collapsibleGroupBoxLayout->addWidget( widgetInfo.widget );
1656 collapsibleGroupBox->setLayout( collapsibleGroupBoxLayout );
1658 QVBoxLayout *
c =
new QVBoxLayout();
1659 c->addWidget( collapsibleGroupBox );
1660 layout->addLayout(
c, row, column, 1, 2 );
1668 hasRootFields =
true;
1669 tabWidget =
nullptr;
1670 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
1671 QLabel *label =
new QLabel( widgetInfo.labelText );
1672 label->setToolTip( widgetInfo.toolTip );
1673 if ( columnCount > 1 && !widgetInfo.labelOnTop )
1675 label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
1678 label->setBuddy( widgetInfo.widget );
1681 if ( widgetInfo.widget
1682 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Fixed
1683 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Maximum
1684 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Preferred )
1687 if ( !widgetInfo.showLabel )
1689 QVBoxLayout *
c =
new QVBoxLayout();
1690 label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1691 c->addWidget( widgetInfo.widget );
1692 layout->addLayout(
c, row, column, 1, 2 );
1695 else if ( widgetInfo.labelOnTop )
1697 QVBoxLayout *
c =
new QVBoxLayout();
1698 label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1699 c->addWidget( label );
1700 c->addWidget( widgetInfo.widget );
1701 layout->addLayout(
c, row, column, 1, 2 );
1706 layout->addWidget( label, row, column++ );
1707 layout->addWidget( widgetInfo.widget, row, column++ );
1711 if ( widgDef->type() == QgsAttributeEditorElement::AttributeEditorType::AeTypeField )
1714 const int fieldIdx = fieldElement->
idx();
1715 if ( fieldIdx >= 0 && fieldIdx < mLayer->fields().count() )
1717 const QString fieldName { mLayer->
fields().
at( fieldIdx ).
name() };
1721 if ( property.isActive() && !
property.expressionString().isEmpty() )
1723 mLabelDataDefinedProperties[ label ] = property;
1730 if ( column >= columnCount * 2 )
1737 if ( hasRootFields && addSpacer )
1739 QSpacerItem *spacerItem =
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
1740 layout->addItem( spacerItem, row, 0 );
1741 layout->setRowStretch( row, 1 );
1744 formWidget = container;
1753 formWidget =
new QWidget(
this );
1754 QGridLayout *gridLayout =
new QGridLayout( formWidget );
1755 formWidget->setLayout( gridLayout );
1761 scrollArea->setWidget( formWidget );
1762 scrollArea->setWidgetResizable(
true );
1763 scrollArea->setFrameShape( QFrame::NoFrame );
1764 scrollArea->setFrameShadow( QFrame::Plain );
1765 scrollArea->setFocusProxy(
this );
1766 layout->addWidget( scrollArea );
1770 layout->addWidget( formWidget );
1785 QString labelText = fieldName;
1786 labelText.replace(
'&', QLatin1String(
"&&" ) );
1790 if ( widgetSetup.
type() == QLatin1String(
"Hidden" ) )
1796 QLabel *label =
new QLabel( labelText );
1798 QSvgWidget *i =
new QSvgWidget();
1799 i->setFixedSize( 18, 18 );
1804 if ( property.isActive() && ! property.expressionString().isEmpty() )
1806 mLabelDataDefinedProperties[ label ] = property;
1812 QWidget *w =
nullptr;
1817 mFormEditorWidgets.insert( idx, formWidget );
1818 mFormWidgets.append( formWidget );
1821 label->setBuddy( eww->
widget() );
1825 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() ) ) );
1834 addWidgetWrapper( eww );
1835 mIconMap[eww->
widget()] = i;
1840 gridLayout->addWidget( label, row++, 0, 1, 2 );
1841 gridLayout->addWidget( w, row++, 0, 1, 2 );
1842 gridLayout->addWidget( i, row++, 0, 1, 2 );
1846 gridLayout->addWidget( label, row, 0 );
1847 gridLayout->addWidget( w, row, 1 );
1848 gridLayout->addWidget( i, row++, 2 );
1862 QVBoxLayout *collapsibleGroupBoxLayout =
new QVBoxLayout();
1863 collapsibleGroupBoxLayout->addWidget( formWidget );
1864 collapsibleGroupBox->setLayout( collapsibleGroupBoxLayout );
1866 gridLayout->addWidget( collapsibleGroupBox, row++, 0, 1, 2 );
1868 mWidgets.append( rww );
1869 mFormWidgets.append( formWidget );
1874 QSpacerItem *spacerItem =
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
1875 gridLayout->addItem( spacerItem, row, 0 );
1876 gridLayout->setRowStretch( row, 1 );
1881 updateFieldDependencies();
1885 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1886 mButtonBox->setObjectName( QStringLiteral(
"buttonBox" ) );
1887 layout->addWidget( mButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
1889 mButtonBox->setVisible( buttonBoxVisible );
1891 if ( !mSearchButtonBox )
1893 mSearchButtonBox =
new QWidget();
1894 QHBoxLayout *boxLayout =
new QHBoxLayout();
1895 boxLayout->setContentsMargins( 0, 0, 0, 0 );
1896 mSearchButtonBox->setLayout( boxLayout );
1897 mSearchButtonBox->setObjectName( QStringLiteral(
"searchButtonBox" ) );
1899 QPushButton *clearButton =
new QPushButton( tr(
"&Reset Form" ), mSearchButtonBox );
1901 boxLayout->addWidget( clearButton );
1902 boxLayout->addStretch( 1 );
1904 QPushButton *flashButton =
new QPushButton();
1905 flashButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1906 flashButton->setText( tr(
"&Flash Features" ) );
1907 connect( flashButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchFlash );
1908 boxLayout->addWidget( flashButton );
1910 QPushButton *zoomButton =
new QPushButton();
1911 zoomButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1912 zoomButton->setText( tr(
"&Zoom to Features" ) );
1913 connect( zoomButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchZoomTo );
1914 boxLayout->addWidget( zoomButton );
1916 QToolButton *selectButton =
new QToolButton();
1917 selectButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1918 selectButton->setText( tr(
"&Select Features" ) );
1920 selectButton->setPopupMode( QToolButton::MenuButtonPopup );
1921 selectButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
1922 connect( selectButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchSetSelection );
1923 QMenu *selectMenu =
new QMenu( selectButton );
1924 QAction *selectAction =
new QAction( tr(
"Select Features" ), selectMenu );
1926 connect( selectAction, &QAction::triggered,
this, &QgsAttributeForm::searchSetSelection );
1927 selectMenu->addAction( selectAction );
1928 QAction *addSelectAction =
new QAction( tr(
"Add to Current Selection" ), selectMenu );
1930 connect( addSelectAction, &QAction::triggered,
this, &QgsAttributeForm::searchAddToSelection );
1931 selectMenu->addAction( addSelectAction );
1932 QAction *deselectAction =
new QAction( tr(
"Remove from Current Selection" ), selectMenu );
1934 connect( deselectAction, &QAction::triggered,
this, &QgsAttributeForm::searchRemoveFromSelection );
1935 selectMenu->addAction( deselectAction );
1936 QAction *filterSelectAction =
new QAction( tr(
"Filter Current Selection" ), selectMenu );
1938 connect( filterSelectAction, &QAction::triggered,
this, &QgsAttributeForm::searchIntersectSelection );
1939 selectMenu->addAction( filterSelectAction );
1940 selectButton->setMenu( selectMenu );
1941 boxLayout->addWidget( selectButton );
1945 QToolButton *filterButton =
new QToolButton();
1946 filterButton->setText( tr(
"Filter Features" ) );
1947 filterButton->setPopupMode( QToolButton::MenuButtonPopup );
1948 filterButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1949 connect( filterButton, &QToolButton::clicked,
this, &QgsAttributeForm::filterTriggered );
1950 QMenu *filterMenu =
new QMenu( filterButton );
1951 QAction *filterAndAction =
new QAction( tr(
"Filter Within (\"AND\")" ), filterMenu );
1952 connect( filterAndAction, &QAction::triggered,
this, &QgsAttributeForm::filterAndTriggered );
1953 filterMenu->addAction( filterAndAction );
1954 QAction *filterOrAction =
new QAction( tr(
"Extend Filter (\"OR\")" ), filterMenu );
1955 connect( filterOrAction, &QAction::triggered,
this, &QgsAttributeForm::filterOrTriggered );
1956 filterMenu->addAction( filterOrAction );
1957 filterButton->setMenu( filterMenu );
1958 boxLayout->addWidget( filterButton );
1962 QPushButton *closeButton =
new QPushButton( tr(
"Close" ), mSearchButtonBox );
1964 closeButton->setShortcut( Qt::Key_Escape );
1965 boxLayout->addWidget( closeButton );
1968 layout->addWidget( mSearchButtonBox );
1986 const auto constMInterfaces = mInterfaces;
1997 QApplication::restoreOverrideCursor();
2000 void QgsAttributeForm::cleanPython()
2002 if ( !mPyFormVarName.isNull() )
2004 QString expr = QStringLiteral(
"if '%1' in locals(): del %1\n" ).arg( mPyFormVarName );
2009 void QgsAttributeForm::initPython()
2026 if ( !initFilePath.isEmpty() )
2030 if ( inputFile && inputFile->open( QFile::ReadOnly ) )
2033 QTextStream inf( inputFile );
2034 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2035 inf.setCodec(
"UTF-8" );
2037 initCode = inf.readAll();
2042 QgsLogger::warning( QStringLiteral(
"The external python file path %1 could not be opened!" ).arg( initFilePath ) );
2053 if ( initCode.isEmpty() )
2055 QgsLogger::warning( QStringLiteral(
"The python code provided in the dialog is empty!" ) );
2066 if ( !initCode.isEmpty() )
2072 tr(
"Python macro could not be run due to missing permissions." ),
2073 Qgis::MessageLevel::Warning );
2080 if (
QgsPythonRunner::eval( QStringLiteral(
"len(inspect.getfullargspec(%1)[0])" ).arg( initFunction ), numArgs ) )
2082 static int sFormId = 0;
2083 mPyFormVarName = QStringLiteral(
"_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
2085 QString form = QStringLiteral(
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
2086 .arg( mPyFormVarName )
2087 .arg( ( quint64 )
this );
2091 QgsDebugMsg( QStringLiteral(
"running featureForm init: %1" ).arg( mPyFormVarName ) );
2094 if ( numArgs == QLatin1String(
"3" ) )
2102 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 ) );
2105 QString expr = QString(
"%1(%2)" )
2106 .arg( mLayer->editFormInit() )
2107 .arg( mPyFormVarName );
2108 QgsAttributeFormInterface *iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface *>( expr,
"QgsAttributeFormInterface" );
2118 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 ) );
2126 WidgetInfo newWidgetInfo;
2128 switch ( widgetDef->
type() )
2140 mWidgets.append( actionWrapper );
2141 newWidgetInfo.widget = actionWrapper->
widget();
2142 newWidgetInfo.showLabel =
false;
2155 if ( fldIdx < fields.
count() && fldIdx >= 0 )
2161 mFormEditorWidgets.insert( fldIdx, formWidget );
2162 mFormWidgets.append( formWidget );
2166 newWidgetInfo.widget = formWidget;
2167 addWidgetWrapper( eww );
2169 newWidgetInfo.widget->setObjectName( fields.
at( fldIdx ).
name() );
2170 newWidgetInfo.hint = fields.
at( fldIdx ).
comment();
2175 newWidgetInfo.labelText.replace(
'&', QLatin1String(
"&&" ) );
2176 newWidgetInfo.toolTip = QStringLiteral(
"<b>%1</b><p>%2</p>" ).arg( mLayer->
attributeDisplayName( fldIdx ), newWidgetInfo.hint );
2177 newWidgetInfo.showLabel = widgetDef->
showLabel();
2198 mWidgets.append( rww );
2199 mFormWidgets.append( formWidget );
2201 newWidgetInfo.widget = formWidget;
2202 newWidgetInfo.showLabel = relDef->
showLabel();
2203 newWidgetInfo.labelText = relDef->
label();
2204 if ( newWidgetInfo.labelText.isEmpty() )
2206 newWidgetInfo.labelOnTop =
true;
2218 if ( columnCount <= 0 )
2222 QWidget *myContainer =
nullptr;
2225 QGroupBox *groupBox =
new QGroupBox( parent );
2226 widgetName = QStringLiteral(
"QGroupBox" );
2228 groupBox->setTitle( container->
name() );
2229 myContainer = groupBox;
2230 newWidgetInfo.widget = myContainer;
2234 myContainer =
new QWidget();
2238 scrollArea->setWidget( myContainer );
2239 scrollArea->setWidgetResizable(
true );
2240 scrollArea->setFrameShape( QFrame::NoFrame );
2241 widgetName = QStringLiteral(
"QScrollArea QWidget" );
2243 newWidgetInfo.widget = scrollArea;
2248 QString style {QStringLiteral(
"background-color: %1;" ).arg( container->
backgroundColor().name() )};
2249 newWidgetInfo.widget->setStyleSheet( style );
2252 QGridLayout *gbLayout =
new QGridLayout();
2253 myContainer->setLayout( gbLayout );
2258 const QList<QgsAttributeEditorElement *> children = container->
children();
2262 WidgetInfo widgetInfo = createWidgetFromDef( childDef, myContainer, vl, context );
2269 registerContainerInformation(
new ContainerInformation( widgetInfo.widget, containerDef->
visibilityExpression().
data() ) );
2273 if ( widgetInfo.labelText.isNull() || ! widgetInfo.showLabel )
2275 gbLayout->addWidget( widgetInfo.widget, row, column, 1, 2 );
2280 QLabel *mypLabel =
new QLabel( widgetInfo.labelText );
2287 const int fldIdx = fieldDef->
idx();
2288 if ( fldIdx < fields.
count() && fldIdx >= 0 )
2290 const QString fieldName { fields.
at( fldIdx ).
name() };
2294 if ( property.isActive() && !
property.expressionString().isEmpty() )
2296 mLabelDataDefinedProperties[ mypLabel ] = property;
2302 mypLabel->setToolTip( widgetInfo.toolTip );
2303 if ( columnCount > 1 && !widgetInfo.labelOnTop )
2305 mypLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
2308 mypLabel->setBuddy( widgetInfo.widget );
2310 if ( widgetInfo.labelOnTop )
2312 QVBoxLayout *
c =
new QVBoxLayout();
2313 mypLabel->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
2314 c->layout()->addWidget( mypLabel );
2315 c->layout()->addWidget( widgetInfo.widget );
2316 gbLayout->addLayout(
c, row, column, 1, 2 );
2321 gbLayout->addWidget( mypLabel, row, column++ );
2322 gbLayout->addWidget( widgetInfo.widget, row, column++ );
2326 if ( column >= columnCount * 2 )
2332 QWidget *spacer =
new QWidget();
2333 spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
2334 gbLayout->addWidget( spacer, ++row, 0 );
2335 gbLayout->setRowStretch( row, 1 );
2337 newWidgetInfo.labelText = QString();
2338 newWidgetInfo.labelOnTop =
true;
2339 newWidgetInfo.showLabel = widgetDef->
showLabel();
2352 mWidgets.append( qmlWrapper );
2354 newWidgetInfo.widget = qmlWrapper->
widget();
2355 newWidgetInfo.labelText = elementDef->
name();
2356 newWidgetInfo.labelOnTop =
true;
2357 newWidgetInfo.showLabel = widgetDef->
showLabel();
2369 mWidgets.append( htmlWrapper );
2371 newWidgetInfo.widget = htmlWrapper->
widget();
2372 newWidgetInfo.labelText = elementDef->
name();
2373 newWidgetInfo.labelOnTop =
true;
2374 newWidgetInfo.showLabel = widgetDef->
showLabel();
2380 QgsDebugMsg( QStringLiteral(
"Unknown attribute editor widget type encountered..." ) );
2384 return newWidgetInfo;
2405 mWidgets.append( eww );
2408 void QgsAttributeForm::createWrappers()
2410 QList<QWidget *> myWidgets = findChildren<QWidget *>();
2411 const QList<QgsField> fields = mLayer->
fields().
toList();
2413 const auto constMyWidgets = myWidgets;
2414 for ( QWidget *myWidget : constMyWidgets )
2417 QVariant vRel = myWidget->property(
"qgisRelation" );
2418 if ( vRel.isValid() )
2428 mWidgets.append( rww );
2433 const auto constFields = fields;
2436 if (
field.
name() == myWidget->objectName() )
2441 addWidgetWrapper( eww );
2448 void QgsAttributeForm::afterWidgetInit()
2450 bool isFirstEww =
true;
2452 const auto constMWidgets = mWidgets;
2461 setFocusProxy( eww->
widget() );
2471 if ( relationWidgetWrapper )
2484 if ( e->type() == QEvent::KeyPress )
2486 QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( e );
2487 if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
2499 QSet< int > &mixedValueFields,
2500 QHash< int, QVariant > &fieldSharedValues )
const
2502 mixedValueFields.clear();
2503 fieldSharedValues.clear();
2509 for (
int i = 0; i < mLayer->
fields().count(); ++i )
2511 if ( mixedValueFields.contains( i ) )
2516 fieldSharedValues[i] = f.
attribute( i );
2520 if ( fieldSharedValues.value( i ) != f.
attribute( i ) )
2522 fieldSharedValues.remove( i );
2523 mixedValueFields.insert( i );
2529 if ( mixedValueFields.count() == mLayer->
fields().
count() )
2538 void QgsAttributeForm::layerSelectionChanged()
2551 resetMultiEdit(
true );
2558 mIsSettingMultiEditFeatures =
true;
2559 mMultiEditFeatureIds = fids;
2561 if ( fids.isEmpty() )
2564 QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
2565 for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
2567 wIt.value()->initialize( QVariant() );
2569 mIsSettingMultiEditFeatures =
false;
2576 QSet< int > mixedValueFields;
2577 QHash< int, QVariant > fieldSharedValues;
2578 scanForEqualAttributes( fit, mixedValueFields, fieldSharedValues );
2585 const auto constMixedValueFields = mixedValueFields;
2586 for (
int fieldIndex : std::as_const( mixedValueFields ) )
2590 const QStringList additionalFields = w->editorWidget()->additionalFields();
2591 QVariantList additionalFieldValues;
2592 for (
const QString &additionalField : additionalFields )
2593 additionalFieldValues << firstFeature.
attribute( additionalField );
2594 w->initialize( firstFeature.
attribute( fieldIndex ),
true, additionalFieldValues );
2597 QHash< int, QVariant >::const_iterator sharedValueIt = fieldSharedValues.constBegin();
2598 for ( ; sharedValueIt != fieldSharedValues.constEnd(); ++sharedValueIt )
2603 const QStringList additionalFields = w->editorWidget()->additionalFields();
2604 for (
const QString &additionalField : additionalFields )
2607 if ( constMixedValueFields.contains( index ) )
2614 QVariantList additionalFieldValues;
2617 for (
const QString &additionalField : additionalFields )
2618 additionalFieldValues << firstFeature.
attribute( additionalField );
2619 w->initialize( firstFeature.
attribute( sharedValueIt.key() ),
true, additionalFieldValues );
2623 for (
const QString &additionalField : additionalFields )
2626 Q_ASSERT( fieldSharedValues.contains( index ) );
2627 additionalFieldValues << fieldSharedValues.value( index );
2629 w->initialize( sharedValueIt.value(),
false, additionalFieldValues );
2633 mIsSettingMultiEditFeatures =
false;
2638 if ( mOwnsMessageBar )
2640 mOwnsMessageBar =
false;
2641 mMessageBar = messageBar;
2651 QStringList filters;
2654 QString filter = widget->currentFilterExpression();
2655 if ( !filter.isNull() )
2656 filters <<
'(' + filter +
')';
2659 return filters.join( QLatin1String(
" AND " ) );
2664 mExtraContextScope.reset( extraScope );
2669 bool newVisibility = expression.evaluate( expressionContext ).toBool();
2671 if ( newVisibility != isVisible )
2679 widget->setVisible( newVisibility );
2682 isVisible = newVisibility;
2695 if ( infos.count() == 0 || !currentFormValuesFeature( formFeature ) )
2698 const QString hint = tr(
"No feature joined" );
2699 const auto constInfos = infos;
2702 if ( !info->isDynamicFormEnabled() )
2707 mJoinedFeatures[info] = joinFeature;
2709 if ( info->hasSubset() )
2713 const auto constSubsetNames = subsetNames;
2714 for (
const QString &
field : constSubsetNames )
2716 QString prefixedName = info->prefixedFieldName(
field );
2718 QString hintText = hint;
2734 QString prefixedName = info->prefixedFieldName(
field );
2736 QString hintText = hint;
2750 bool QgsAttributeForm::fieldIsEditable(
int fieldIndex )
const
2755 void QgsAttributeForm::updateFieldDependencies()
2757 mDefaultValueDependencies.clear();
2758 mVirtualFieldsDependencies.clear();
2759 mRelatedLayerFieldsDependencies.clear();
2768 updateFieldDependenciesDefaultValue( eww );
2769 updateFieldDependenciesVirtualFields( eww );
2770 updateRelatedLayerFieldsDependencies( eww );
2777 const QSet<QString> referencedColumns = exp.referencedColumns();
2778 for (
const QString &referencedColumn : referencedColumns )
2784 for (
const int id : allAttributeIds )
2786 mDefaultValueDependencies.insertMulti(
id, eww );
2791 mDefaultValueDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
2799 if ( expressionField.isEmpty() )
2803 const QSet<QString> referencedColumns = exp.referencedColumns();
2804 for (
const QString &referencedColumn : referencedColumns )
2809 for (
const int id : allAttributeIds )
2811 mVirtualFieldsDependencies.insertMulti(
id, eww );
2816 mVirtualFieldsDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
2826 if ( expressionField.contains( QStringLiteral(
"relation_aggregate" ) )
2827 || expressionField.contains( QStringLiteral(
"get_features" ) ) )
2828 mRelatedLayerFieldsDependencies.insert( eww );
2832 mRelatedLayerFieldsDependencies.clear();
2837 if ( ! editorWidgetWrapper )
2840 updateRelatedLayerFieldsDependencies( editorWidgetWrapper );
2851 mIconMap[eww->
widget()]->hide();
2865 const QString file = QStringLiteral(
"/mIconJoinNotEditable.svg" );
2866 const QString tooltip = tr(
"Join settings do not allow editing" );
2867 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2871 const QString file = QStringLiteral(
"mIconJoinHasNotUpsertOnEdit.svg" );
2872 const QString tooltip = tr(
"Join settings do not allow upsert on edit" );
2873 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2877 const QString file = QStringLiteral(
"/mIconJoinedLayerNotEditable.svg" );
2878 const QString tooltip = tr(
"Joined layer is not toggled editable" );
2879 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
2885 void QgsAttributeForm::reloadIcon(
const QString &file,
const QString &tooltip, QSvgWidget *sw )
2888 sw->setToolTip( tooltip );
SelectBehavior
Specifies how a selection should be applied.
@ SetSelection
Set selection, removing any existing selection.
@ AddToSelection
Add selection to current selection.
@ IntersectSelection
Modify current selection to include only select features which match.
@ RemoveFromSelection
Remove from current selection.
static 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 QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
This element will load a layer action onto the form.
const QgsAction & action(const QgsVectorLayer *layer) const
Returns the (possibly lazy loaded) action for the given layer.
This is a container for attribute editors, used to group them visually in the attribute form if it is...
QgsOptionalExpression visibilityExpression() const
The visibility expression is used in the attribute form to show or hide this container based on an ex...
virtual bool isGroupBox() const
Returns if this container is going to be rendered as a group box.
QColor backgroundColor() const
backgroundColor
int columnCount() const
Gets the number of columns in this group.
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
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.
This is an abstract base class for any elements of a drag and drop form.
AttributeEditorType type() const
The type of this element.
bool showLabel() const
Controls if this element should be labeled with a title (field, relation or groupname).
QString name() const
Returns the name of this element.
@ AeTypeHtmlElement
A HTML element.
@ AeTypeQmlElement
A QML element.
@ AeTypeContainer
A container.
@ AeTypeRelation
A relation.
@ AeTypeAction
A layer action element (since QGIS 3.22)
This element will load a field's widget onto the form.
int idx() const
Returns the index of the field.
An attribute editor widget that will represent arbitrary HTML code.
QString htmlCode() const
The Html code that will be represented within this widget.
An attribute editor widget that will represent arbitrary QML code.
QString qmlCode() const
The QML code that will be represented within this widget.
This element will load a relation editor onto the form.
const QgsRelation & relation() const
Gets the id of the relation which shall be embedded.
QVariantMap relationEditorConfiguration() const
Returns the relation editor widget configuration.
QVariant nmRelationId() const
Determines the relation id of the second relation involved in an N:M relation.
bool forceSuppressFormPopup() const
Determines the force suppress form popup status.
QString relationWidgetTypeId() const
Returns the current relation widget type id.
QString label() const
Determines the label of this element.
A groupbox that collapses/expands when toggled and can save its collapsed and checked states.
Q_GADGET QString expression
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
void setValid(bool validity)
Sets the validity of the feature.
bool isValid() const
Returns the validity of this feature.
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
ConstraintOrigin
Origin of constraints.
@ ConstraintOriginNotSet
Constraint is not set.
@ ConstraintOriginLayer
Constraint was set by layer.
QString constraintExpression() const
Returns the constraint expression for the field, if set.
static QString fieldToolTipExtended(const QgsField &field, const QgsVectorLayer *layer)
Returns a HTML formatted tooltip string for a field, containing details like the field name,...
Encapsulate a field in an attribute table or data source.
QString displayName() const
Returns the name to use when displaying this field.
QgsDefaultValue defaultValueDefinition
QgsFieldConstraints constraints
Container of fields for a vector layer.
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
int count() const
Returns number of items.
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
bool exists(int i) const
Returns if a field index is valid.
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
static bool pythonMacroAllowed(void(*lambda)()=nullptr, QgsMessageBar *messageBar=nullptr)
Returns true if python macros are currently allowed to be run If the global option is to ask user,...
static void warning(const QString &msg)
Goes to qWarning.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
void editingStarted()
Emitted when editing on this layer has started.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
Represents an item shown within a QgsMessageBar widget.
A bar for displaying non-blocking messages to the user.
bool popWidget(QgsMessageBarItem *item)
Remove the specified item from the bar, and display the next most recent one in the stack.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
void pushItem(QgsMessageBarItem *item)
Display a message item on the bar, after hiding the currently visible one and putting it in a stack.
QFile * localFile(const QString &filePathOrUrl)
Returns a QFile from a local file or to a temporary file previously fetched by the registry.
bool enabled() const
Check if this optional is enabled.
T data() const
Access the payload data.
QgsRelationManager * relationManager
static QgsProject * instance()
Returns the QgsProject singleton instance.
bool hasProperty(int key) const override
Returns true if the collection contains a property with the specified key.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
A store for object properties.
static bool run(const QString &command, const QString &messageOnError=QString())
Execute a Python statement.
static bool eval(const QString &command, QString &result)
Eval a Python statement.
This class manages a set of relations between layers.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
bool isInvalidJSON()
Returns whether the text edit widget contains Invalid JSON.
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.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QString expressionField(int index) const
Returns the expression used for a given expression field.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
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.
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.
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.
Q_INVOKABLE void selectByExpression(const QString &expression, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects matching features using an expression.
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)