57 #include <QTextStream>
60 #include <QFormLayout>
61 #include <QGridLayout>
64 #include <QPushButton>
66 #include <QMessageBox>
67 #include <QToolButton>
71 int QgsAttributeForm::sFormCounter = 0;
76 , mOwnsMessageBar( true )
78 , mFormNr( sFormCounter++ )
80 , mPreventFeatureRefresh( false )
81 , mIsSettingMultiEditFeatures( false )
82 , mUnsavedMultiEditChanges( false )
83 , mEditCommandMessage( tr(
"Attributes changed" ) )
96 updateContainersVisibility();
104 qDeleteAll( mInterfaces );
131 mInterfaces.append( iface );
147 if ( mUnsavedMultiEditChanges )
150 int res = QMessageBox::question(
this, tr(
"Multiedit Attributes" ),
151 tr(
"Apply changes to edited features?" ), QMessageBox::Yes | QMessageBox::No );
152 if ( res == QMessageBox::Yes )
157 clearMultiEditMessages();
159 mUnsavedMultiEditChanges =
false;
211 w->setContext( newContext );
217 w->setVisible( relationWidgetsVisible );
224 mSearchButtonBox->setVisible(
false );
229 mSearchButtonBox->setVisible(
false );
234 mSearchButtonBox->setVisible(
false );
238 resetMultiEdit(
false );
240 mSearchButtonBox->setVisible(
false );
244 mSearchButtonBox->setVisible(
true );
250 mSearchButtonBox->setVisible(
false );
258 mSearchButtonBox->setVisible(
false );
267 const auto constMWidgets = mWidgets;
282 QVariant mainValue = eww->
value();
284 additionalFieldValues[index] = value;
285 eww->
setValues( mainValue, additionalFieldValues );
294 mIsSettingFeature =
true;
311 mIsSettingFeature =
false;
312 const auto constMInterfaces = mInterfaces;
315 iface->featureChanged();
331 mIsSettingFeature =
false;
334 bool QgsAttributeForm::saveEdits( QString *error )
337 bool changedLayer =
false;
342 bool doUpdate =
false;
362 *error = tr(
"JSON value for %1 is invalid and has not been saved" ).arg( eww->
field().
name() );
365 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
366 QVariantList srcVars = QVariantList() << eww->
value();
367 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
371 for (
const QString &fieldName : additionalFields )
375 dstVars << dst.at( idx );
379 Q_ASSERT( dstVars.count() == srcVars.count() );
381 for (
int i = 0; i < dstVars.count(); i++ )
384 if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() )
386 dst[fieldIndexes[i]] = srcVars[i];
396 const auto constMInterfaces = mInterfaces;
399 if ( !iface->acceptChanges( updatedFeature ) )
409 mFeature = updatedFeature;
415 bool res = mLayer->
addFeature( updatedFeature );
434 for (
int i = 0; i < dst.count(); ++i )
437 || !dst.at( i ).isValid()
438 || !fieldIsEditable( i ) )
444 QgsDebugMsgLevel( QStringLiteral(
"dst:'%1' (type:%2, isNull:%3, isValid:%4)" )
445 .arg( dst.at( i ).toString(), dst.at( i ).typeName() ).arg( dst.at( i ).isNull() ).arg( dst.at( i ).isValid() ), 2 );
446 QgsDebugMsgLevel( QStringLiteral(
"src:'%1' (type:%2, isNull:%3, isValid:%4)" )
447 .arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( src.at( i ).isNull() ).arg( src.at( i ).isValid() ), 2 );
449 newValues[i] = dst.at( i );
450 oldValues[i] = src.at( i );
457 if ( success && n > 0 )
484 QgsFeature QgsAttributeForm::getUpdatedFeature()
const
496 QVariantList dstVars = QVariantList() << featureAttributes.at( eww->
fieldIdx() );
497 QVariantList srcVars = QVariantList() << eww->
value();
498 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
502 for (
const QString &fieldName : additionalFields )
506 dstVars << featureAttributes.at( idx );
510 Q_ASSERT( dstVars.count() == srcVars.count() );
512 for (
int i = 0; i < dstVars.count(); i++ )
514 if ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() )
515 featureAttributes[fieldIndexes[i]] = srcVars[i];
520 return updatedFeature;
523 void QgsAttributeForm::updateValuesDependencies(
const int originIdx )
525 updateFieldDependencies();
527 updateValuesDependenciesDefaultValues( originIdx );
528 updateValuesDependenciesVirtualFields( originIdx );
531 void QgsAttributeForm::updateValuesDependenciesDefaultValues(
const int originIdx )
533 if ( !mDefaultValueDependencies.contains( originIdx ) )
541 QgsFeature updatedFeature = getUpdatedFeature();
544 QList<QgsWidgetWrapper *> relevantWidgets = mDefaultValueDependencies.values( originIdx );
557 if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
568 void QgsAttributeForm::updateValuesDependenciesVirtualFields(
const int originIdx )
570 if ( !mVirtualFieldsDependencies.contains( originIdx ) )
577 QgsFeature updatedFeature = getUpdatedFeature();
580 const QList<QgsWidgetWrapper *> relevantWidgets = mVirtualFieldsDependencies.values( originIdx );
588 if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
594 const QVariant value = exp.evaluate( &context );
600 void QgsAttributeForm::updateRelatedLayerFields()
603 updateRelatedLayerFieldsDependencies();
605 if ( mRelatedLayerFieldsDependencies.isEmpty() )
612 QgsFeature updatedFeature = getUpdatedFeature();
615 const QSet<QgsEditorWidgetWrapper *> relevantWidgets = mRelatedLayerFieldsDependencies;
619 if ( mAlreadyUpdatedFields.contains( eww->
fieldIdx() ) )
625 QVariant value = exp.evaluate( &context );
630 void QgsAttributeForm::resetMultiEdit(
bool promptToSave )
635 mUnsavedMultiEditChanges =
false;
639 void QgsAttributeForm::multiEditMessageClicked(
const QString &link )
641 clearMultiEditMessages();
642 resetMultiEdit( link == QLatin1String(
"#apply" ) );
645 void QgsAttributeForm::filterTriggered()
647 QString filter = createFilterExpression();
653 void QgsAttributeForm::searchZoomTo()
655 QString filter = createFilterExpression();
656 if ( filter.isEmpty() )
662 void QgsAttributeForm::searchFlash()
664 QString filter = createFilterExpression();
665 if ( filter.isEmpty() )
671 void QgsAttributeForm::filterAndTriggered()
673 QString filter = createFilterExpression();
674 if ( filter.isEmpty() )
682 void QgsAttributeForm::filterOrTriggered()
684 QString filter = createFilterExpression();
685 if ( filter.isEmpty() )
693 void QgsAttributeForm::pushSelectedFeaturesMessage()
699 tr(
"%n matching feature(s) selected",
"matching features", count ),
700 Qgis::MessageLevel::Info );
705 tr(
"No matching features found" ),
706 Qgis::MessageLevel::Info );
714 Qgis::MessageLevel::Warning );
719 QString filter = createFilterExpression();
720 if ( filter.isEmpty() )
724 pushSelectedFeaturesMessage();
729 void QgsAttributeForm::searchSetSelection()
734 void QgsAttributeForm::searchAddToSelection()
739 void QgsAttributeForm::searchRemoveFromSelection()
744 void QgsAttributeForm::searchIntersectSelection()
749 bool QgsAttributeForm::saveMultiEdits()
753 QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
754 for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
761 || !fieldIsEditable( wIt.key() ) )
769 newAttributeValues.insert( wIt.key(), w->
currentValue() );
772 if ( newAttributeValues.isEmpty() )
780 int res = QMessageBox::information(
this, tr(
"Multiedit Attributes" ),
781 tr(
"Edits will be applied to all selected features." ), QMessageBox::Ok | QMessageBox::Cancel );
782 if ( res != QMessageBox::Ok )
793 const auto constMultiEditFeatureIds = mMultiEditFeatureIds;
796 QgsAttributeMap::const_iterator aIt = newAttributeValues.constBegin();
797 for ( ; aIt != newAttributeValues.constEnd(); ++aIt )
803 clearMultiEditMessages();
808 mMultiEditMessageBarItem =
new QgsMessageBarItem( tr(
"Attribute changes for multiple features applied." ), Qgis::MessageLevel::Success, -1 );
813 mMultiEditMessageBarItem =
new QgsMessageBarItem( tr(
"Changes could not be applied." ), Qgis::MessageLevel::Warning, 0 );
816 if ( !mButtonBox->isVisible() )
817 mMessageBar->
pushItem( mMultiEditMessageBarItem );
843 wrapper->notifyAboutToSave();
883 success = saveEdits( error );
887 success = saveMultiEdits();
892 mUnsavedMultiEditChanges =
false;
901 mValuesInitialized =
false;
902 const auto constMWidgets = mWidgets;
905 ww->setFeature( mFeature );
907 mValuesInitialized =
true;
913 const auto widgets { findChildren< QgsAttributeFormEditorWidget * >() };
920 void QgsAttributeForm::clearMultiEditMessages()
922 if ( mMultiEditUnsavedMessageBarItem )
924 if ( !mButtonBox->isVisible() )
925 mMessageBar->
popWidget( mMultiEditUnsavedMessageBarItem );
926 mMultiEditUnsavedMessageBarItem =
nullptr;
928 if ( mMultiEditMessageBarItem )
930 if ( !mButtonBox->isVisible() )
931 mMessageBar->
popWidget( mMultiEditMessageBarItem );
932 mMultiEditMessageBarItem =
nullptr;
936 QString QgsAttributeForm::createFilterExpression()
const
942 if ( !filter.isEmpty() )
946 if ( filters.isEmpty() )
949 QString filter = filters.join( QLatin1String(
") AND (" ) ).prepend(
'(' ).append(
')' );
958 if ( mExtraContextScope )
965 void QgsAttributeForm::onAttributeChanged(
const QVariant &value,
const QVariantList &additionalFieldValues )
970 bool signalEmitted =
false;
972 if ( mValuesInitialized )
991 for (
int i = 0; i < additionalFields.count(); i++ )
993 const QString fieldName = additionalFields.at( i );
994 const QVariant value = additionalFieldValues.at( i );
998 signalEmitted =
true;
1000 if ( mValuesInitialized )
1001 updateJoinedFields( *eww );
1007 if ( !mIsSettingMultiEditFeatures )
1009 mUnsavedMultiEditChanges =
true;
1011 QLabel *msgLabel =
new QLabel( tr(
"Unsaved multiedit changes: <a href=\"#apply\">apply changes</a> or <a href=\"#reset\">reset changes</a>." ), mMessageBar );
1012 msgLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
1013 msgLabel->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
1014 connect( msgLabel, &QLabel::linkActivated,
this, &QgsAttributeForm::multiEditMessageClicked );
1015 clearMultiEditMessages();
1017 mMultiEditUnsavedMessageBarItem =
new QgsMessageBarItem( msgLabel, Qgis::MessageLevel::Warning );
1018 if ( !mButtonBox->isVisible() )
1019 mMessageBar->
pushItem( mMultiEditUnsavedMessageBarItem );
1022 signalEmitted =
true;
1032 updateConstraints( eww );
1035 if ( mValuesInitialized )
1038 mAlreadyUpdatedFields.append( eww->
fieldIdx() );
1039 updateValuesDependencies( eww->
fieldIdx() );
1040 mAlreadyUpdatedFields.removeAll( eww->
fieldIdx() );
1046 if ( !signalEmitted )
1051 bool attributeHasChanged = !mIsSettingFeature;
1053 attributeHasChanged &= !mIsSettingMultiEditFeatures;
1059 void QgsAttributeForm::updateAllConstraints()
1061 const auto constMWidgets = mWidgets;
1066 updateConstraints( eww );
1074 if ( currentFormValuesFeature( ft ) )
1086 updateConstraint( ft, eww );
1089 const QList<QgsEditorWidgetWrapper *> deps = constraintDependencies( eww );
1092 updateConstraint( ft, depsEww );
1100 const QVector<ContainerInformation *> infos = mContainerInformationDependency.value( eww->
field().
name() );
1101 for ( ContainerInformation *info : infos )
1103 info->apply( &context );
1108 void QgsAttributeForm::updateContainersVisibility()
1112 const QVector<ContainerInformation *> infos = mContainerVisibilityCollapsedInformation;
1114 for ( ContainerInformation *info : infos )
1116 info->apply( &context );
1120 updateAllConstraints();
1126 if ( mContext.
attributeFormMode() != QgsAttributeEditorContext::Mode::MultiEditMode )
1138 if ( mJoinedFeatures.contains( info ) )
1156 void QgsAttributeForm::updateLabels()
1158 if ( ! mLabelDataDefinedProperties.isEmpty() )
1161 if ( currentFormValuesFeature( currentFeature ) )
1165 for (
auto it = mLabelDataDefinedProperties.constBegin() ; it != mLabelDataDefinedProperties.constEnd(); ++it )
1167 QLabel *label { it.key() };
1169 const QString value { it->valueAsString( context, QString(), &ok ) };
1170 if ( ok && ! value.isEmpty() )
1172 label->setText( value );
1179 bool QgsAttributeForm::currentFormValuesFeature(
QgsFeature &feature )
1192 if ( dst.count() > eww->
fieldIdx() )
1194 QVariantList dstVars = QVariantList() << dst.at( eww->
fieldIdx() );
1195 QVariantList srcVars = QVariantList() << eww->
value();
1196 QList<int> fieldIndexes = QList<int>() << eww->
fieldIdx();
1200 for (
const QString &fieldName : additionalFields )
1203 fieldIndexes << idx;
1204 dstVars << dst.at( idx );
1208 Q_ASSERT( dstVars.count() == srcVars.count() );
1210 for (
int i = 0; i < dstVars.count(); i++ )
1214 if ( ( !
qgsVariantEqual( dstVars[i], srcVars[i] ) || dstVars[i].isNull() != srcVars[i].isNull() ) && srcVars[i].isValid() )
1216 dst[fieldIndexes[i]] = srcVars[i];
1233 void QgsAttributeForm::registerContainerInformation( QgsAttributeForm::ContainerInformation *info )
1235 mContainerVisibilityCollapsedInformation.append( info );
1237 const QSet<QString> referencedColumns = info->expression.referencedColumns().unite( info->collapsedExpression.referencedColumns() );
1239 for (
const QString &col : referencedColumns )
1241 mContainerInformationDependency[ col ].append( info );
1245 bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions )
const
1269 bool QgsAttributeForm::currentFormValidHardConstraints( QStringList &invalidFields, QStringList &descriptions )
const
1290 void QgsAttributeForm::onAttributeAdded(
int idx )
1292 mPreventFeatureRefresh =
false;
1296 attrs.insert( idx, QVariant(
layer()->fields().at( idx ).type() ) );
1304 void QgsAttributeForm::onAttributeDeleted(
int idx )
1306 mPreventFeatureRefresh =
false;
1310 attrs.remove( idx );
1318 void QgsAttributeForm::onRelatedFeaturesChanged()
1320 updateRelatedLayerFields();
1323 void QgsAttributeForm::onUpdatedFields()
1325 mPreventFeatureRefresh =
false;
1342 attrs[i] = QVariant(
layer()->fields().at( i ).type() );
1352 void QgsAttributeForm::onConstraintStatusChanged(
const QString &constraint,
1360 if ( formEditorWidget )
1366 QList<QgsEditorWidgetWrapper *> wDeps;
1378 if ( name != ewwName )
1385 for (
const QString &colName : referencedColumns )
1387 if ( name == colName )
1389 wDeps.append( eww );
1402 return setupRelationWidgetWrapper( QString(), rel, context );
1415 void QgsAttributeForm::preventFeatureRefresh()
1417 mPreventFeatureRefresh =
true;
1448 return mNeedsGeometry;
1451 void QgsAttributeForm::synchronizeState()
1453 bool isEditable = ( mFeature.
isValid()
1470 bool enabled = isEditable && fieldIsEditable( eww->
fieldIdx() );
1471 ww->setEnabled( enabled );
1477 ww->setEnabled( isEditable );
1485 QStringList invalidFields, descriptions;
1486 mValidConstraints = currentFormValidHardConstraints( invalidFields, descriptions );
1490 if ( !mValidConstraints && !mConstraintsFailMessageBarItem )
1492 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 );
1493 mMessageBar->
pushItem( mConstraintsFailMessageBarItem );
1495 else if ( mValidConstraints && mConstraintsFailMessageBarItem )
1497 mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
1498 mConstraintsFailMessageBarItem =
nullptr;
1501 else if ( mConstraintsFailMessageBarItem )
1503 mMessageBar->
popWidget( mConstraintsFailMessageBarItem );
1504 mConstraintsFailMessageBarItem =
nullptr;
1507 isEditable = isEditable & mValidConstraints;
1511 QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
1513 okButton->setEnabled( isEditable );
1516 void QgsAttributeForm::init()
1518 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1521 QWidget *formWidget =
nullptr;
1522 mNeedsGeometry =
false;
1524 bool buttonBoxVisible =
true;
1528 buttonBoxVisible = mButtonBox->isVisible();
1530 mButtonBox =
nullptr;
1533 if ( mSearchButtonBox )
1535 delete mSearchButtonBox;
1536 mSearchButtonBox =
nullptr;
1539 qDeleteAll( mWidgets );
1542 while ( QWidget *w = this->findChild<QWidget *>() )
1548 QVBoxLayout *vl =
new QVBoxLayout();
1549 vl->setContentsMargins( 0, 0, 0, 0 );
1551 mMessageBar->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
1552 vl->addWidget( mMessageBar );
1557 QGridLayout *layout =
new QGridLayout();
1558 QWidget *container =
new QWidget();
1559 container->setLayout( layout );
1560 vl->addWidget( container );
1562 mFormEditorWidgets.clear();
1563 mFormWidgets.clear();
1566 setContentsMargins( 0, 0, 0, 0 );
1575 if ( file && file->open( QFile::ReadOnly ) )
1579 QFileInfo fi( file->fileName() );
1580 loader.setWorkingDirectory( fi.dir() );
1581 formWidget = loader.load( file,
this );
1584 formWidget->setWindowFlags( Qt::Widget );
1585 layout->addWidget( formWidget );
1588 mButtonBox = findChild<QDialogButtonBox *>();
1591 formWidget->installEventFilter(
this );
1603 int columnCount = 1;
1604 bool hasRootFields =
false;
1605 bool addSpacer =
true;
1614 if ( !containerDef )
1619 tabWidget =
nullptr;
1620 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
1621 if ( widgetInfo.labelStyle.overrideColor )
1623 if ( widgetInfo.labelStyle.color.isValid() )
1625 widgetInfo.widget->setStyleSheet( QStringLiteral(
"QGroupBox::title { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
1628 if ( widgetInfo.labelStyle.overrideFont )
1630 widgetInfo.widget->setFont( widgetInfo.labelStyle.font );
1632 layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
1644 layout->addWidget( tabWidget, row, column, 1, 2 );
1648 QWidget *tabPage =
new QWidget( tabWidget );
1650 tabWidget->addTab( tabPage, widgDef->name() );
1651 tabWidget->
setTabStyle( tabWidget->tabBar()->count() - 1, widgDef->labelStyle() );
1655 registerContainerInformation(
new ContainerInformation( tabWidget, tabPage, containerDef->
visibilityExpression().
data() ) );
1657 QGridLayout *tabPageLayout =
new QGridLayout();
1658 tabPage->setLayout( tabPageLayout );
1660 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, tabPage, mLayer, mContext );
1661 tabPageLayout->addWidget( widgetInfo.widget );
1666 hasRootFields =
true;
1667 tabWidget =
nullptr;
1668 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
1671 if ( widgetInfo.showLabel )
1673 if ( widgetInfo.labelStyle.overrideColor && widgetInfo.labelStyle.color.isValid() )
1675 collapsibleGroupBox->
setStyleSheet( QStringLiteral(
"QGroupBox::title { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
1678 if ( widgetInfo.labelStyle.overrideFont )
1680 collapsibleGroupBox->setFont( widgetInfo.labelStyle.font );
1683 collapsibleGroupBox->setTitle( widgetInfo.labelText );
1686 QVBoxLayout *collapsibleGroupBoxLayout =
new QVBoxLayout();
1687 collapsibleGroupBoxLayout->addWidget( widgetInfo.widget );
1688 collapsibleGroupBox->setLayout( collapsibleGroupBoxLayout );
1690 QVBoxLayout *
c =
new QVBoxLayout();
1691 c->addWidget( collapsibleGroupBox );
1692 layout->addLayout(
c, row, column, 1, 2 );
1700 hasRootFields =
true;
1701 tabWidget =
nullptr;
1702 WidgetInfo widgetInfo = createWidgetFromDef( widgDef, container, mLayer, mContext );
1703 QLabel *label =
new QLabel( widgetInfo.labelText );
1705 if ( widgetInfo.labelStyle.overrideColor )
1707 if ( widgetInfo.labelStyle.color.isValid() )
1709 label->setStyleSheet( QStringLiteral(
"QLabel { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
1713 if ( widgetInfo.labelStyle.overrideFont )
1715 label->setFont( widgetInfo.labelStyle.font );
1718 label->setToolTip( widgetInfo.toolTip );
1719 if ( columnCount > 1 && !widgetInfo.labelOnTop )
1721 label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
1724 label->setBuddy( widgetInfo.widget );
1727 if ( widgetInfo.widget
1728 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Fixed
1729 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Maximum
1730 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Preferred )
1733 if ( !widgetInfo.showLabel )
1735 QVBoxLayout *
c =
new QVBoxLayout();
1736 label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1737 c->addWidget( widgetInfo.widget );
1738 layout->addLayout(
c, row, column, 1, 2 );
1741 else if ( widgetInfo.labelOnTop )
1743 QVBoxLayout *
c =
new QVBoxLayout();
1744 label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
1745 c->addWidget( label );
1746 c->addWidget( widgetInfo.widget );
1747 layout->addLayout(
c, row, column, 1, 2 );
1752 layout->addWidget( label, row, column++ );
1753 layout->addWidget( widgetInfo.widget, row, column++ );
1757 if ( widgDef->type() == QgsAttributeEditorElement::AttributeEditorType::AeTypeField )
1760 const int fieldIdx = fieldElement->
idx();
1761 if ( fieldIdx >= 0 && fieldIdx < mLayer->fields().count() )
1763 const QString fieldName { mLayer->
fields().
at( fieldIdx ).
name() };
1767 if ( property.isActive() && !
property.expressionString().isEmpty() )
1769 mLabelDataDefinedProperties[ label ] = property;
1776 if ( column >= columnCount * 2 )
1783 if ( hasRootFields && addSpacer )
1785 QSpacerItem *spacerItem =
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
1786 layout->addItem( spacerItem, row, 0 );
1787 layout->setRowStretch( row, 1 );
1790 formWidget = container;
1799 formWidget =
new QWidget(
this );
1800 QGridLayout *gridLayout =
new QGridLayout( formWidget );
1801 formWidget->setLayout( gridLayout );
1807 scrollArea->setWidget( formWidget );
1808 scrollArea->setWidgetResizable(
true );
1809 scrollArea->setFrameShape( QFrame::NoFrame );
1810 scrollArea->setFrameShadow( QFrame::Plain );
1811 scrollArea->setFocusProxy(
this );
1812 layout->addWidget( scrollArea );
1816 layout->addWidget( formWidget );
1831 QString labelText = fieldName;
1832 labelText.replace(
'&', QLatin1String(
"&&" ) );
1836 if ( widgetSetup.
type() == QLatin1String(
"Hidden" ) )
1842 QLabel *label =
new QLabel( labelText );
1844 QSvgWidget *i =
new QSvgWidget();
1845 i->setFixedSize( 18, 18 );
1850 if ( property.isActive() && ! property.expressionString().isEmpty() )
1852 mLabelDataDefinedProperties[ label ] = property;
1858 QWidget *w =
nullptr;
1863 mFormEditorWidgets.insert( idx, formWidget );
1864 mFormWidgets.append( formWidget );
1867 label->setBuddy( eww->
widget() );
1871 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() ) ) );
1880 addWidgetWrapper( eww );
1881 mIconMap[eww->
widget()] = i;
1886 gridLayout->addWidget( label, row++, 0, 1, 2 );
1887 gridLayout->addWidget( w, row++, 0, 1, 2 );
1888 gridLayout->addWidget( i, row++, 0, 1, 2 );
1892 gridLayout->addWidget( label, row, 0 );
1893 gridLayout->addWidget( w, row, 1 );
1894 gridLayout->addWidget( i, row++, 2 );
1908 QVBoxLayout *collapsibleGroupBoxLayout =
new QVBoxLayout();
1909 collapsibleGroupBoxLayout->addWidget( formWidget );
1910 collapsibleGroupBox->setLayout( collapsibleGroupBoxLayout );
1912 gridLayout->addWidget( collapsibleGroupBox, row++, 0, 1, 2 );
1914 mWidgets.append( rww );
1915 mFormWidgets.append( formWidget );
1920 QSpacerItem *spacerItem =
new QSpacerItem( 20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding );
1921 gridLayout->addItem( spacerItem, row, 0 );
1922 gridLayout->setRowStretch( row, 1 );
1927 updateFieldDependencies();
1931 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1932 mButtonBox->setObjectName( QStringLiteral(
"buttonBox" ) );
1933 layout->addWidget( mButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
1935 mButtonBox->setVisible( buttonBoxVisible );
1937 if ( !mSearchButtonBox )
1939 mSearchButtonBox =
new QWidget();
1940 QHBoxLayout *boxLayout =
new QHBoxLayout();
1941 boxLayout->setContentsMargins( 0, 0, 0, 0 );
1942 mSearchButtonBox->setLayout( boxLayout );
1943 mSearchButtonBox->setObjectName( QStringLiteral(
"searchButtonBox" ) );
1945 QPushButton *clearButton =
new QPushButton( tr(
"&Reset Form" ), mSearchButtonBox );
1947 boxLayout->addWidget( clearButton );
1948 boxLayout->addStretch( 1 );
1950 QPushButton *flashButton =
new QPushButton();
1951 flashButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1952 flashButton->setText( tr(
"&Flash Features" ) );
1953 connect( flashButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchFlash );
1954 boxLayout->addWidget( flashButton );
1956 QPushButton *openAttributeTableButton =
new QPushButton();
1957 openAttributeTableButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1958 openAttributeTableButton->setText( tr(
"Show in &Table" ) );
1959 openAttributeTableButton->setToolTip( tr(
"Open the attribute table editor with the filtered features" ) );
1960 connect( openAttributeTableButton, &QToolButton::clicked,
this, [ = ]
1964 boxLayout->addWidget( openAttributeTableButton );
1966 QPushButton *zoomButton =
new QPushButton();
1967 zoomButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1968 zoomButton->setText( tr(
"&Zoom to Features" ) );
1969 connect( zoomButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchZoomTo );
1970 boxLayout->addWidget( zoomButton );
1972 QToolButton *selectButton =
new QToolButton();
1973 selectButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
1974 selectButton->setText( tr(
"&Select Features" ) );
1976 selectButton->setPopupMode( QToolButton::MenuButtonPopup );
1977 selectButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
1978 connect( selectButton, &QToolButton::clicked,
this, &QgsAttributeForm::searchSetSelection );
1979 QMenu *selectMenu =
new QMenu( selectButton );
1980 QAction *selectAction =
new QAction( tr(
"Select Features" ), selectMenu );
1982 connect( selectAction, &QAction::triggered,
this, &QgsAttributeForm::searchSetSelection );
1983 selectMenu->addAction( selectAction );
1984 QAction *addSelectAction =
new QAction( tr(
"Add to Current Selection" ), selectMenu );
1986 connect( addSelectAction, &QAction::triggered,
this, &QgsAttributeForm::searchAddToSelection );
1987 selectMenu->addAction( addSelectAction );
1988 QAction *deselectAction =
new QAction( tr(
"Remove from Current Selection" ), selectMenu );
1990 connect( deselectAction, &QAction::triggered,
this, &QgsAttributeForm::searchRemoveFromSelection );
1991 selectMenu->addAction( deselectAction );
1992 QAction *filterSelectAction =
new QAction( tr(
"Filter Current Selection" ), selectMenu );
1994 connect( filterSelectAction, &QAction::triggered,
this, &QgsAttributeForm::searchIntersectSelection );
1995 selectMenu->addAction( filterSelectAction );
1996 selectButton->setMenu( selectMenu );
1997 boxLayout->addWidget( selectButton );
2001 QToolButton *filterButton =
new QToolButton();
2002 filterButton->setText( tr(
"Filter Features" ) );
2003 filterButton->setPopupMode( QToolButton::MenuButtonPopup );
2004 filterButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
2005 connect( filterButton, &QToolButton::clicked,
this, &QgsAttributeForm::filterTriggered );
2006 QMenu *filterMenu =
new QMenu( filterButton );
2007 QAction *filterAndAction =
new QAction( tr(
"Filter Within (\"AND\")" ), filterMenu );
2008 connect( filterAndAction, &QAction::triggered,
this, &QgsAttributeForm::filterAndTriggered );
2009 filterMenu->addAction( filterAndAction );
2010 QAction *filterOrAction =
new QAction( tr(
"Extend Filter (\"OR\")" ), filterMenu );
2011 connect( filterOrAction, &QAction::triggered,
this, &QgsAttributeForm::filterOrTriggered );
2012 filterMenu->addAction( filterOrAction );
2013 filterButton->setMenu( filterMenu );
2014 boxLayout->addWidget( filterButton );
2018 QPushButton *closeButton =
new QPushButton( tr(
"Close" ), mSearchButtonBox );
2020 closeButton->setShortcut( Qt::Key_Escape );
2021 boxLayout->addWidget( closeButton );
2024 layout->addWidget( mSearchButtonBox, layout->rowCount(), 0, 1, layout->columnCount() );
2042 const auto constMInterfaces = mInterfaces;
2053 QApplication::restoreOverrideCursor();
2056 void QgsAttributeForm::cleanPython()
2058 if ( !mPyFormVarName.isNull() )
2060 QString expr = QStringLiteral(
"if '%1' in locals(): del %1\n" ).arg( mPyFormVarName );
2065 void QgsAttributeForm::initPython()
2082 if ( !initFilePath.isEmpty() )
2086 if ( inputFile && inputFile->open( QFile::ReadOnly ) )
2089 QTextStream inf( inputFile );
2090 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2091 inf.setCodec(
"UTF-8" );
2093 initCode = inf.readAll();
2098 QgsLogger::warning( QStringLiteral(
"The external python file path %1 could not be opened!" ).arg( initFilePath ) );
2109 if ( initCode.isEmpty() )
2111 QgsLogger::warning( QStringLiteral(
"The python code provided in the dialog is empty!" ) );
2122 if ( !initCode.isEmpty() )
2128 tr(
"Python macro could not be run due to missing permissions." ),
2129 Qgis::MessageLevel::Warning );
2136 if (
QgsPythonRunner::eval( QStringLiteral(
"len(inspect.getfullargspec(%1)[0])" ).arg( initFunction ), numArgs ) )
2138 static int sFormId = 0;
2139 mPyFormVarName = QStringLiteral(
"_qgis_featureform_%1_%2" ).arg( mFormNr ).arg( sFormId++ );
2141 QString form = QStringLiteral(
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
2142 .arg( mPyFormVarName )
2143 .arg( ( quint64 )
this );
2147 QgsDebugMsg( QStringLiteral(
"running featureForm init: %1" ).arg( mPyFormVarName ) );
2150 if ( numArgs == QLatin1String(
"3" ) )
2158 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 ) );
2161 QString expr = QString(
"%1(%2)" )
2162 .arg( mLayer->editFormInit() )
2163 .arg( mPyFormVarName );
2164 QgsAttributeFormInterface *iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface *>( expr,
"QgsAttributeFormInterface" );
2174 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 ) );
2182 WidgetInfo newWidgetInfo;
2184 newWidgetInfo.labelStyle = widgetDef->
labelStyle();
2186 switch ( widgetDef->
type() )
2198 mWidgets.append( actionWrapper );
2199 newWidgetInfo.widget = actionWrapper->
widget();
2200 newWidgetInfo.showLabel =
false;
2213 if ( fldIdx < fields.
count() && fldIdx >= 0 )
2219 mFormEditorWidgets.insert( fldIdx, formWidget );
2220 mFormWidgets.append( formWidget );
2224 newWidgetInfo.widget = formWidget;
2225 addWidgetWrapper( eww );
2227 newWidgetInfo.widget->setObjectName( fields.
at( fldIdx ).
name() );
2228 newWidgetInfo.hint = fields.
at( fldIdx ).
comment();
2233 newWidgetInfo.labelText.replace(
'&', QLatin1String(
"&&" ) );
2234 newWidgetInfo.toolTip = QStringLiteral(
"<b>%1</b><p>%2</p>" ).arg( mLayer->
attributeDisplayName( fldIdx ), newWidgetInfo.hint );
2235 newWidgetInfo.showLabel = widgetDef->
showLabel();
2256 mWidgets.append( rww );
2257 mFormWidgets.append( formWidget );
2259 newWidgetInfo.widget = formWidget;
2260 newWidgetInfo.showLabel = relDef->
showLabel();
2261 newWidgetInfo.labelText = relDef->
label();
2262 if ( newWidgetInfo.labelText.isEmpty() )
2264 newWidgetInfo.labelOnTop =
true;
2276 if ( columnCount <= 0 )
2280 QWidget *myContainer =
nullptr;
2284 widgetName = QStringLiteral(
"QGroupBox" );
2287 groupBox->setTitle( container->
name() );
2288 if ( newWidgetInfo.labelStyle.overrideColor )
2290 if ( newWidgetInfo.labelStyle.color.isValid() )
2292 groupBox->
setStyleSheet( QStringLiteral(
"QGroupBox::title { color: %1; }" ).arg( newWidgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
2295 if ( newWidgetInfo.labelStyle.overrideFont )
2297 groupBox->setFont( newWidgetInfo.labelStyle.font );
2300 myContainer = groupBox;
2301 newWidgetInfo.widget = myContainer;
2306 myContainer =
new QWidget();
2310 scrollArea->setWidget( myContainer );
2311 scrollArea->setWidgetResizable(
true );
2312 scrollArea->setFrameShape( QFrame::NoFrame );
2313 widgetName = QStringLiteral(
"QScrollArea QWidget" );
2315 newWidgetInfo.widget = scrollArea;
2320 QString style {QStringLiteral(
"background-color: %1;" ).arg( container->
backgroundColor().name() )};
2321 newWidgetInfo.widget->setStyleSheet( style );
2324 QGridLayout *gbLayout =
new QGridLayout();
2325 myContainer->setLayout( gbLayout );
2329 bool addSpacer =
true;
2331 const QList<QgsAttributeEditorElement *> children = container->
children();
2335 WidgetInfo widgetInfo = createWidgetFromDef( childDef, myContainer, vl, context );
2346 if ( widgetInfo.labelText.isNull() || ! widgetInfo.showLabel )
2348 gbLayout->addWidget( widgetInfo.widget, row, column, 1, 2 );
2353 QLabel *mypLabel =
new QLabel( widgetInfo.labelText );
2355 if ( widgetInfo.labelStyle.overrideColor )
2357 if ( widgetInfo.labelStyle.color.isValid() )
2359 mypLabel->setStyleSheet( QStringLiteral(
"QLabel { color: %1; }" ).arg( widgetInfo.labelStyle.color.name( QColor::HexArgb ) ) );
2363 if ( widgetInfo.labelStyle.overrideFont )
2365 mypLabel->setFont( widgetInfo.labelStyle.font );
2373 const int fldIdx = fieldDef->
idx();
2374 if ( fldIdx < fields.
count() && fldIdx >= 0 )
2376 const QString fieldName { fields.
at( fldIdx ).
name() };
2380 if ( property.isActive() && !
property.expressionString().isEmpty() )
2382 mLabelDataDefinedProperties[ mypLabel ] = property;
2388 mypLabel->setToolTip( widgetInfo.toolTip );
2389 if ( columnCount > 1 && !widgetInfo.labelOnTop )
2391 mypLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
2394 mypLabel->setBuddy( widgetInfo.widget );
2396 if ( widgetInfo.labelOnTop )
2398 QVBoxLayout *
c =
new QVBoxLayout();
2399 mypLabel->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
2400 c->layout()->addWidget( mypLabel );
2401 c->layout()->addWidget( widgetInfo.widget );
2402 gbLayout->addLayout(
c, row, column, 1, 2 );
2407 gbLayout->addWidget( mypLabel, row, column++ );
2408 gbLayout->addWidget( widgetInfo.widget, row, column++ );
2412 if ( column >= columnCount * 2 )
2418 if ( widgetInfo.widget
2419 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Fixed
2420 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Maximum
2421 && widgetInfo.widget->sizePolicy().verticalPolicy() != QSizePolicy::Preferred )
2425 if ( qobject_cast<QgsAttributeFormRelationEditorWidget *>( widgetInfo.widget ) )
2431 QWidget *spacer =
new QWidget();
2432 spacer->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
2433 gbLayout->addWidget( spacer, ++row, 0 );
2434 gbLayout->setRowStretch( row, 1 );
2437 newWidgetInfo.labelText = QString();
2438 newWidgetInfo.labelOnTop =
true;
2439 newWidgetInfo.showLabel = widgetDef->
showLabel();
2452 mWidgets.append( qmlWrapper );
2454 newWidgetInfo.widget = qmlWrapper->
widget();
2455 newWidgetInfo.labelText = elementDef->
name();
2456 newWidgetInfo.labelOnTop =
true;
2457 newWidgetInfo.showLabel = widgetDef->
showLabel();
2469 mWidgets.append( htmlWrapper );
2471 newWidgetInfo.widget = htmlWrapper->
widget();
2472 newWidgetInfo.labelText = elementDef->
name();
2473 newWidgetInfo.labelOnTop =
true;
2474 newWidgetInfo.showLabel = widgetDef->
showLabel();
2480 QgsDebugMsg( QStringLiteral(
"Unknown attribute editor widget type encountered..." ) );
2484 return newWidgetInfo;
2505 mWidgets.append( eww );
2508 void QgsAttributeForm::createWrappers()
2510 QList<QWidget *> myWidgets = findChildren<QWidget *>();
2511 const QList<QgsField> fields = mLayer->
fields().
toList();
2513 const auto constMyWidgets = myWidgets;
2514 for ( QWidget *myWidget : constMyWidgets )
2517 QVariant vRel = myWidget->property(
"qgisRelation" );
2518 if ( vRel.isValid() )
2528 mWidgets.append( rww );
2533 const auto constFields = fields;
2536 if (
field.
name() == myWidget->objectName() )
2541 addWidgetWrapper( eww );
2548 void QgsAttributeForm::afterWidgetInit()
2550 bool isFirstEww =
true;
2552 const auto constMWidgets = mWidgets;
2561 setFocusProxy( eww->
widget() );
2571 if ( relationWidgetWrapper )
2584 if ( e->type() == QEvent::KeyPress )
2586 QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( e );
2587 if ( keyEvent && keyEvent->key() == Qt::Key_Escape )
2599 QSet< int > &mixedValueFields,
2600 QHash< int, QVariant > &fieldSharedValues )
const
2602 mixedValueFields.clear();
2603 fieldSharedValues.clear();
2609 for (
int i = 0; i < mLayer->
fields().count(); ++i )
2611 if ( mixedValueFields.contains( i ) )
2616 fieldSharedValues[i] = f.
attribute( i );
2620 if ( fieldSharedValues.value( i ) != f.
attribute( i ) )
2622 fieldSharedValues.remove( i );
2623 mixedValueFields.insert( i );
2629 if ( mixedValueFields.count() == mLayer->
fields().
count() )
2638 void QgsAttributeForm::layerSelectionChanged()
2651 resetMultiEdit(
true );
2658 mIsSettingMultiEditFeatures =
true;
2659 mMultiEditFeatureIds = fids;
2661 if ( fids.isEmpty() )
2664 QMap< int, QgsAttributeFormEditorWidget * >::const_iterator wIt = mFormEditorWidgets.constBegin();
2665 for ( ; wIt != mFormEditorWidgets.constEnd(); ++ wIt )
2667 wIt.value()->initialize( QVariant() );
2669 mIsSettingMultiEditFeatures =
false;
2676 QSet< int > mixedValueFields;
2677 QHash< int, QVariant > fieldSharedValues;
2678 scanForEqualAttributes( fit, mixedValueFields, fieldSharedValues );
2685 const auto constMixedValueFields = mixedValueFields;
2686 for (
int fieldIndex : std::as_const( mixedValueFields ) )
2690 const QStringList additionalFields = w->editorWidget()->additionalFields();
2691 QVariantList additionalFieldValues;
2692 for (
const QString &additionalField : additionalFields )
2693 additionalFieldValues << firstFeature.
attribute( additionalField );
2694 w->initialize( firstFeature.
attribute( fieldIndex ),
true, additionalFieldValues );
2697 QHash< int, QVariant >::const_iterator sharedValueIt = fieldSharedValues.constBegin();
2698 for ( ; sharedValueIt != fieldSharedValues.constEnd(); ++sharedValueIt )
2703 const QStringList additionalFields = w->editorWidget()->additionalFields();
2704 for (
const QString &additionalField : additionalFields )
2707 if ( constMixedValueFields.contains( index ) )
2714 QVariantList additionalFieldValues;
2717 for (
const QString &additionalField : additionalFields )
2718 additionalFieldValues << firstFeature.
attribute( additionalField );
2719 w->initialize( firstFeature.
attribute( sharedValueIt.key() ),
true, additionalFieldValues );
2723 for (
const QString &additionalField : additionalFields )
2726 Q_ASSERT( fieldSharedValues.contains( index ) );
2727 additionalFieldValues << fieldSharedValues.value( index );
2729 w->initialize( sharedValueIt.value(),
false, additionalFieldValues );
2734 setMultiEditFeatureIdsRelations( fids );
2736 mIsSettingMultiEditFeatures =
false;
2741 if ( mOwnsMessageBar )
2743 mOwnsMessageBar =
false;
2744 mMessageBar = messageBar;
2754 QStringList filters;
2757 QString filter = widget->currentFilterExpression();
2758 if ( !filter.isNull() )
2759 filters <<
'(' + filter +
')';
2762 return filters.join( QLatin1String(
" AND " ) );
2767 mExtraContextScope.reset( extraScope );
2773 const bool newVisibility = expression.evaluate( expressionContext ).toBool();
2775 if ( expression.isValid() && ! expression.hasEvalError() && newVisibility != isVisible )
2783 widget->setVisible( newVisibility );
2786 isVisible = newVisibility;
2789 const bool newCollapsedState = collapsedExpression.evaluate( expressionContext ).toBool();
2791 if ( collapsedExpression.isValid() && ! collapsedExpression.hasEvalError() && newCollapsedState != isCollapsed )
2796 collapsibleGroupBox->
setCollapsed( newCollapsedState );
2797 isCollapsed = newCollapsedState;
2811 if ( infos.count() == 0 || !currentFormValuesFeature( formFeature ) )
2814 const QString hint = tr(
"No feature joined" );
2815 const auto constInfos = infos;
2818 if ( !info->isDynamicFormEnabled() )
2823 mJoinedFeatures[info] = joinFeature;
2825 if ( info->hasSubset() )
2829 const auto constSubsetNames = subsetNames;
2830 for (
const QString &
field : constSubsetNames )
2832 QString prefixedName = info->prefixedFieldName(
field );
2834 QString hintText = hint;
2850 QString prefixedName = info->prefixedFieldName(
field );
2852 QString hintText = hint;
2866 bool QgsAttributeForm::fieldIsEditable(
int fieldIndex )
const
2871 void QgsAttributeForm::updateFieldDependencies()
2873 mDefaultValueDependencies.clear();
2874 mVirtualFieldsDependencies.clear();
2875 mRelatedLayerFieldsDependencies.clear();
2884 updateFieldDependenciesDefaultValue( eww );
2885 updateFieldDependenciesVirtualFields( eww );
2886 updateRelatedLayerFieldsDependencies( eww );
2894 if ( exp.needsGeometry() )
2895 mNeedsGeometry =
true;
2897 const QSet<QString> referencedColumns = exp.referencedColumns();
2898 for (
const QString &referencedColumn : referencedColumns )
2904 for (
const int id : allAttributeIds )
2906 mDefaultValueDependencies.insertMulti(
id, eww );
2911 mDefaultValueDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
2919 if ( expressionField.isEmpty() )
2924 if ( exp.needsGeometry() )
2925 mNeedsGeometry =
true;
2927 const QSet<QString> referencedColumns = exp.referencedColumns();
2928 for (
const QString &referencedColumn : referencedColumns )
2933 for (
const int id : allAttributeIds )
2935 mVirtualFieldsDependencies.insertMulti(
id, eww );
2940 mVirtualFieldsDependencies.insertMulti( mLayer->
fields().
lookupField( referencedColumn ), eww );
2950 if ( expressionField.contains( QStringLiteral(
"relation_aggregate" ) )
2951 || expressionField.contains( QStringLiteral(
"get_features" ) ) )
2952 mRelatedLayerFieldsDependencies.insert( eww );
2956 mRelatedLayerFieldsDependencies.clear();
2961 if ( ! editorWidgetWrapper )
2964 updateRelatedLayerFieldsDependencies( editorWidgetWrapper );
2969 void QgsAttributeForm::setMultiEditFeatureIdsRelations(
const QgsFeatureIds &fids )
2974 if ( !relationEditorWidget )
2987 mIconMap[eww->
widget()]->hide();
3001 const QString file = QStringLiteral(
"/mIconJoinNotEditable.svg" );
3002 const QString tooltip = tr(
"Join settings do not allow editing" );
3003 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
3007 const QString file = QStringLiteral(
"mIconJoinHasNotUpsertOnEdit.svg" );
3008 const QString tooltip = tr(
"Join settings do not allow upsert on edit" );
3009 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
3013 const QString file = QStringLiteral(
"/mIconJoinedLayerNotEditable.svg" );
3014 const QString tooltip = tr(
"Joined layer is not toggled editable" );
3015 reloadIcon( file, tooltip, mIconMap[eww->
widget()] );
3021 void QgsAttributeForm::reloadIcon(
const QString &file,
const QString &tooltip, QSvgWidget *sw )
3024 sw->setToolTip( tooltip );