33 : d( new QgsEditFormConfigPrivate() )
40 d->mDataDefinedFieldProperties[ fieldName ] = properties;
45 return d->mDataDefinedFieldProperties.value( fieldName );
50 return QgsEditFormConfigPrivate::propertyDefinitions();
55 const int fieldIndex = d->mFields.indexOf( widgetName );
56 if ( fieldIndex != -1 )
57 return d->mFields.at( fieldIndex ).editorWidgetSetup().config();
59 return d->mWidgetConfigs.value( widgetName );
62void QgsEditFormConfig::setFields(
const QgsFields &fields )
67 if ( !d->mConfiguredRootContainer )
69 d->mInvisibleRootContainer->clear();
70 for (
int i = 0; i < d->mFields.size(); ++i )
73 d->mInvisibleRootContainer->addChildElement(
field );
78void QgsEditFormConfig::onRelationsLoaded()
80 const QList<QgsAttributeEditorElement *> relations = d->mInvisibleRootContainer->findElements( Qgis::AttributeEditorType::Relation );
92bool QgsEditFormConfig::legacyUpdateRelationWidgetInTabs(
QgsAttributeEditorContainer *container,
const QString &widgetName,
const QVariantMap &config )
94 const QList<QgsAttributeEditorElement *> children = container->
children();
97 if ( child->type() == Qgis::AttributeEditorType::Container )
100 if ( legacyUpdateRelationWidgetInTabs( container, widgetName, config ) )
106 else if ( child->type() == Qgis::AttributeEditorType::Relation )
111 if ( relation->
relation().
id() == widgetName )
113 if ( config.contains( QStringLiteral(
"nm-rel" ) ) )
117 if ( config.contains( QStringLiteral(
"force-suppress-popup" ) ) )
131 if ( d->mFields.indexOf( widgetName ) != -1 )
133 QgsDebugError( QStringLiteral(
"Trying to set a widget config for a field on QgsEditFormConfig. Use layer->setEditorWidgetSetup() instead." ) );
138 if ( config.contains( QStringLiteral(
"force-suppress-popup" ) ) || config.contains( QStringLiteral(
"nm-rel" ) ) )
140 QgsMessageLog::logMessage( QStringLiteral(
"Deprecation Warning: Trying to set a relation config directly on the relation %1. Relation settings should be done for the specific widget instance instead. Use attributeEditorRelation->setNmRelationId() or attributeEditorRelation->setForceSuppressFormPopup() instead." ).arg( widgetName ) );
141 legacyUpdateRelationWidgetInTabs( d->mInvisibleRootContainer, widgetName, config );
145 d->mWidgetConfigs[widgetName] = config;
152 return d->mWidgetConfigs.remove( widgetName ) != 0;
177 d->mInvisibleRootContainer->addChildElement( data );
182 return d->mInvisibleRootContainer->children();
188 d->mInvisibleRootContainer->clear();
193 return d->mInvisibleRootContainer;
198 return d->mEditorLayout;
204 d->mEditorLayout = editorLayout;
206 if ( editorLayout == Qgis::AttributeFormLayout::DragAndDrop )
207 d->mConfiguredRootContainer =
true;
212 return d->mUiFormPath;
217 if ( !ui.isEmpty() && !QUrl::fromUserInput( ui ).isLocalFile() )
225 setLayout( Qgis::AttributeFormLayout::AutoGenerated );
229 setLayout( Qgis::AttributeFormLayout::UiFile );
236 if ( idx >= 0 && idx < d->mFields.count() )
241 return !d->mFieldEditables.value( d->mFields.at( idx ).name(),
true );
249 if ( idx >= 0 && idx < d->mFields.count() )
250 return d->mLabelOnTop.value( d->mFields.at( idx ).name(),
false );
257 if ( idx >= 0 && idx < d->mFields.count() )
260 d->mFieldEditables[ d->mFields.at( idx ).name()] = !
readOnly;
266 if ( idx >= 0 && idx < d->mFields.count() )
269 d->mLabelOnTop[ d->mFields.at( idx ).name()] = onTop;
275 if ( index >= 0 && index < d->mFields.count() )
276 return d->mReuseLastValue.value( d->mFields.at( index ).name(),
false );
283 if ( index >= 0 && index < d->mFields.count() )
286 d->mReuseLastValue[ d->mFields.at( index ).name()] = reuse;
292 return d->mInitFunction;
298 d->mInitFunction = function;
314 return d->mInitFilePath;
320 d->mInitFilePath = filePath;
323 if ( !filePath.isEmpty() && !QUrl::fromUserInput( filePath ).isLocalFile() )
332 return d->mInitCodeSource;
343 return d->mSuppressForm;
349 d->mSuppressForm = s;
358 const QDomNode editFormNode = node.namedItem( QStringLiteral(
"editform" ) );
359 if ( !editFormNode.isNull() )
361 const QDomElement e = editFormNode.toElement();
362 const bool tolerantRemoteUrls = e.hasAttribute( QStringLiteral(
"tolerant" ) );
363 if ( !e.text().isEmpty() )
369 const bool localFile = QFileInfo::exists( uiFormPath );
370 if ( localFile || tolerantRemoteUrls || uiFormPath.startsWith( QLatin1String(
"http" ) ) )
375 const QDomNode editFormInitNode = node.namedItem( QStringLiteral(
"editforminit" ) );
376 if ( !editFormInitNode.isNull() )
378 d->mInitFunction = editFormInitNode.toElement().text();
381 const QDomNode editFormInitCodeSourceNode = node.namedItem( QStringLiteral(
"editforminitcodesource" ) );
382 if ( !editFormInitCodeSourceNode.isNull() && !editFormInitCodeSourceNode.toElement().text().isEmpty() )
387 const QDomNode editFormInitCodeNode = node.namedItem( QStringLiteral(
"editforminitcode" ) );
388 if ( !editFormInitCodeNode.isNull() )
390 setInitCode( editFormInitCodeNode.toElement().text() );
398 const int dotPos = d->mInitFunction.lastIndexOf(
'.' );
402 setInitCode( QStringLiteral(
"from %1 import %2\n" ).arg( d->mInitFunction.left( dotPos ), d->mInitFunction.mid( dotPos + 1 ) ) );
406 const QDomNode editFormInitFilePathNode = node.namedItem( QStringLiteral(
"editforminitfilepath" ) );
407 if ( !editFormInitFilePathNode.isNull() && !editFormInitFilePathNode.toElement().text().isEmpty() )
412 const QDomNode fFSuppNode = node.namedItem( QStringLiteral(
"featformsuppress" ) );
413 if ( fFSuppNode.isNull() )
415 d->mSuppressForm = Qgis::AttributeFormSuppression::Default;
419 const QDomElement e = fFSuppNode.toElement();
424 const QDomNode editorLayoutNode = node.namedItem( QStringLiteral(
"editorlayout" ) );
425 if ( editorLayoutNode.isNull() )
427 d->mEditorLayout = Qgis::AttributeFormLayout::AutoGenerated;
431 if ( editorLayoutNode.toElement().text() == QLatin1String(
"uifilelayout" ) )
433 d->mEditorLayout = Qgis::AttributeFormLayout::UiFile;
435 else if ( editorLayoutNode.toElement().text() == QLatin1String(
"tablayout" ) )
437 d->mEditorLayout = Qgis::AttributeFormLayout::DragAndDrop;
441 d->mEditorLayout = Qgis::AttributeFormLayout::AutoGenerated;
445 d->mFieldEditables.clear();
446 const QDomNodeList editableNodeList = node.namedItem( QStringLiteral(
"editable" ) ).toElement().childNodes();
447 for (
int i = 0; i < editableNodeList.size(); ++i )
449 const QDomElement editableElement = editableNodeList.at( i ).toElement();
450 d->mFieldEditables.insert( editableElement.attribute( QStringLiteral(
"name" ) ),
static_cast< bool >( editableElement.attribute( QStringLiteral(
"editable" ) ).toInt() ) );
453 d->mLabelOnTop.clear();
454 const QDomNodeList labelOnTopNodeList = node.namedItem( QStringLiteral(
"labelOnTop" ) ).toElement().childNodes();
455 for (
int i = 0; i < labelOnTopNodeList.size(); ++i )
457 const QDomElement labelOnTopElement = labelOnTopNodeList.at( i ).toElement();
458 d->mLabelOnTop.insert( labelOnTopElement.attribute( QStringLiteral(
"name" ) ),
static_cast< bool >( labelOnTopElement.attribute( QStringLiteral(
"labelOnTop" ) ).toInt() ) );
461 d->mReuseLastValue.clear();
462 const QDomNodeList reuseLastValueNodeList = node.namedItem( QStringLiteral(
"reuseLastValue" ) ).toElement().childNodes();
463 for (
int i = 0; i < reuseLastValueNodeList.size(); ++i )
465 const QDomElement reuseLastValueElement = reuseLastValueNodeList.at( i ).toElement();
466 d->mReuseLastValue.insert( reuseLastValueElement.attribute( QStringLiteral(
"name" ) ),
static_cast< bool >( reuseLastValueElement.attribute( QStringLiteral(
"reuseLastValue" ) ).toInt() ) );
470 const QDomNodeList fieldDDPropertiesNodeList = node.namedItem( QStringLiteral(
"dataDefinedFieldProperties" ) ).toElement().childNodes();
471 for (
int i = 0; i < fieldDDPropertiesNodeList.size(); ++i )
473 const QDomElement DDElement = fieldDDPropertiesNodeList.at( i ).toElement();
476 d->mDataDefinedFieldProperties.insert( DDElement.attribute( QStringLiteral(
"name" ) ), collection );
479 const QDomNodeList widgetsNodeList = node.namedItem( QStringLiteral(
"widgets" ) ).toElement().childNodes();
481 for (
int i = 0; i < widgetsNodeList.size(); ++i )
483 const QDomElement widgetElement = widgetsNodeList.at( i ).toElement();
486 d->mWidgetConfigs[widgetElement.attribute( QStringLiteral(
"name" ) )] = config.toMap();
490 const QDomNode attributeEditorFormNode = node.namedItem( QStringLiteral(
"attributeEditorForm" ) );
491 if ( !attributeEditorFormNode.isNull() )
493 const QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
495 if ( attributeEditorFormNodeList.size() )
497 d->mConfiguredRootContainer =
true;
500 for (
int i = 0; i < attributeEditorFormNodeList.size(); i++ )
502 QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
504 fixLegacyConfig( elem );
506 const QString layerId = node.namedItem( QStringLiteral(
"id" ) ).toElement().text();
508 if ( attributeEditorWidget )
509 addTab( attributeEditorWidget );
517void QgsEditFormConfig::fixLegacyConfig( QDomElement &el )
521 if ( el.tagName() == QLatin1String(
"attributeEditorRelation" ) )
523 if ( !el.hasAttribute( QStringLiteral(
"forceSuppressFormPopup" ) ) )
526 const bool forceSuppress =
widgetConfig( el.attribute( QStringLiteral(
"relation" ) ) ).value( QStringLiteral(
"force-suppress-popup" ),
false ).toBool();
527 el.setAttribute( QStringLiteral(
"forceSuppressFormPopup" ), forceSuppress ? 1 : 0 );
529 if ( !el.hasAttribute( QStringLiteral(
"nmRelationId" ) ) )
532 el.setAttribute( QStringLiteral(
"nmRelationId" ),
widgetConfig( el.attribute( QStringLiteral(
"relation" ) ) ).value( QStringLiteral(
"nm-rel" ) ).toString() );
536 const QDomNodeList children = el.childNodes();
537 for (
int i = 0; i < children.size(); i++ )
539 QDomElement child = children.at( i ).toElement();
540 fixLegacyConfig( child );
541 el.replaceChild( child, children.at( i ) );
547 QDomDocument doc( node.ownerDocument() );
549 QDomElement efField = doc.createElement( QStringLiteral(
"editform" ) );
550 efField.setAttribute( QStringLiteral(
"tolerant" ), QStringLiteral(
"1" ) );
552 efField.appendChild( efText );
553 node.appendChild( efField );
555 QDomElement efiField = doc.createElement( QStringLiteral(
"editforminit" ) );
557 efiField.appendChild( doc.createTextNode(
initFunction() ) );
558 node.appendChild( efiField );
560 QDomElement eficsField = doc.createElement( QStringLiteral(
"editforminitcodesource" ) );
561 eficsField.appendChild( doc.createTextNode( QString::number(
static_cast< int >(
initCodeSource() ) ) ) );
562 node.appendChild( eficsField );
564 QDomElement efifpField = doc.createElement( QStringLiteral(
"editforminitfilepath" ) );
566 node.appendChild( efifpField );
568 QDomElement eficField = doc.createElement( QStringLiteral(
"editforminitcode" ) );
569 eficField.appendChild( doc.createCDATASection(
initCode() ) );
570 node.appendChild( eficField );
572 QDomElement fFSuppElem = doc.createElement( QStringLiteral(
"featformsuppress" ) );
573 const QDomText fFSuppText = doc.createTextNode( QString::number(
static_cast< int >(
suppress() ) ) );
574 fFSuppElem.appendChild( fFSuppText );
575 node.appendChild( fFSuppElem );
578 QDomElement editorLayoutElem = doc.createElement( QStringLiteral(
"editorlayout" ) );
581 case Qgis::AttributeFormLayout::UiFile:
582 editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral(
"uifilelayout" ) ) );
585 case Qgis::AttributeFormLayout::DragAndDrop:
586 editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral(
"tablayout" ) ) );
589 case Qgis::AttributeFormLayout::AutoGenerated:
591 editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral(
"generatedlayout" ) ) );
595 node.appendChild( editorLayoutElem );
598 if ( !
tabs().empty() && d->mConfiguredRootContainer )
600 QDomElement tabsElem = doc.createElement( QStringLiteral(
"attributeEditorForm" ) );
601 const QDomElement rootElem = d->mInvisibleRootContainer->toDomElement( doc );
602 const QDomNodeList elemList = rootElem.childNodes();
603 while ( !elemList.isEmpty() )
605 tabsElem.appendChild( elemList.at( 0 ) );
607 node.appendChild( tabsElem );
610 QDomElement editableElem = doc.createElement( QStringLiteral(
"editable" ) );
611 for (
auto editIt = d->mFieldEditables.constBegin(); editIt != d->mFieldEditables.constEnd(); ++editIt )
613 QDomElement fieldElem = doc.createElement( QStringLiteral(
"field" ) );
614 fieldElem.setAttribute( QStringLiteral(
"name" ), editIt.key() );
615 fieldElem.setAttribute( QStringLiteral(
"editable" ), editIt.value() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
616 editableElem.appendChild( fieldElem );
618 node.appendChild( editableElem );
620 QDomElement labelOnTopElem = doc.createElement( QStringLiteral(
"labelOnTop" ) );
621 for (
auto labelOnTopIt = d->mLabelOnTop.constBegin(); labelOnTopIt != d->mLabelOnTop.constEnd(); ++labelOnTopIt )
623 QDomElement fieldElem = doc.createElement( QStringLiteral(
"field" ) );
624 fieldElem.setAttribute( QStringLiteral(
"name" ), labelOnTopIt.key() );
625 fieldElem.setAttribute( QStringLiteral(
"labelOnTop" ), labelOnTopIt.value() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
626 labelOnTopElem.appendChild( fieldElem );
628 node.appendChild( labelOnTopElem );
630 QDomElement reuseLastValueElem = doc.createElement( QStringLiteral(
"reuseLastValue" ) );
631 for (
auto reuseLastValueIt = d->mReuseLastValue.constBegin(); reuseLastValueIt != d->mReuseLastValue.constEnd(); ++reuseLastValueIt )
633 QDomElement fieldElem = doc.createElement( QStringLiteral(
"field" ) );
634 fieldElem.setAttribute( QStringLiteral(
"name" ), reuseLastValueIt.key() );
635 fieldElem.setAttribute( QStringLiteral(
"reuseLastValue" ), reuseLastValueIt.value() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
636 reuseLastValueElem.appendChild( fieldElem );
638 node.appendChild( reuseLastValueElem );
641 QDomElement ddFieldPropsElement = doc.createElement( QStringLiteral(
"dataDefinedFieldProperties" ) );
642 for (
auto it = d->mDataDefinedFieldProperties.constBegin(); it != d->mDataDefinedFieldProperties.constEnd(); ++it )
644 QDomElement ddPropsElement = doc.createElement( QStringLiteral(
"field" ) );
645 ddPropsElement.setAttribute( QStringLiteral(
"name" ), it.key() );
647 ddFieldPropsElement.appendChild( ddPropsElement );
649 node.appendChild( ddFieldPropsElement );
651 QDomElement widgetsElem = doc.createElement( QStringLiteral(
"widgets" ) );
653 QMap<QString, QVariantMap >::ConstIterator configIt( d->mWidgetConfigs.constBegin() );
655 while ( configIt != d->mWidgetConfigs.constEnd() )
657 QDomElement widgetElem = doc.createElement( QStringLiteral(
"widget" ) );
658 widgetElem.setAttribute( QStringLiteral(
"name" ), configIt.key() );
662 configElem.setTagName( QStringLiteral(
"config" ) );
663 widgetElem.appendChild( configElem );
664 widgetsElem.appendChild( widgetElem );
668 node.appendChild( widgetsElem );
AttributeFormSuppression
Available form types for layout of the attribute form editor.
AttributeFormPythonInitCodeSource
The Python init code source for attribute forms.
AttributeFormLayout
Available form types for layout of the attribute form editor.
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
This is a container for attribute editors, used to group them visually in the attribute form if it is...
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
This is an abstract base class for any elements of a drag and drop form.
static QgsAttributeEditorElement * create(const QDomElement &element, const QString &layerId, const QgsFields &fields, const QgsReadWriteContext &context, QgsAttributeEditorElement *parent=nullptr)
Constructs the editor element from the given element.
This element will load a field's widget onto the form.
This element will load a relation editor onto the form.
void setNmRelationId(const QVariant &nmRelationId=QVariant())
Sets nmRelationId for the relation id of the second relation involved in an N:M relation.
bool init(QgsRelationManager *relManager)
Initializes the relation from the id.
const QgsRelation & relation() const
Gets the id of the relation which shall be embedded.
void setForceSuppressFormPopup(bool forceSuppressFormPopup)
Sets force suppress form popup status to forceSuppressFormPopup.
Container of fields for a vector layer.
@ OriginExpression
Field is calculated from an expression.
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QgsFetchedContent * fetch(const QString &url, Qgis::ActionStart fetchingMode=Qgis::ActionStart::Deferred, const QString &authConfig=QString())
Initialize a download for the given URL.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
QgsRelationManager * relationManager
static QgsProject * instance()
Returns the QgsProject singleton instance.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Allows entering a context category and takes care of leaving this category on deletion of the class.
The class is used as a container of context for various read/write operations on other objects.
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
#define QgsDebugError(str)
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.