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